custom directory
This commit is contained in:
parent
185a1c62e9
commit
7e82ddcbb7
12 changed files with 396 additions and 56 deletions
|
|
@ -9,6 +9,7 @@ android {
|
||||||
namespace = "com.example.muzzlevelocity"
|
namespace = "com.example.muzzlevelocity"
|
||||||
compileSdk = flutter.compileSdkVersion
|
compileSdk = flutter.compileSdkVersion
|
||||||
ndkVersion = flutter.ndkVersion
|
ndkVersion = flutter.ndkVersion
|
||||||
|
compileSdkVersion 34
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
|
@ -28,6 +29,7 @@ android {
|
||||||
targetSdk = flutter.targetSdkVersion
|
targetSdk = flutter.targetSdkVersion
|
||||||
versionCode = flutter.versionCode
|
versionCode = flutter.versionCode
|
||||||
versionName = flutter.versionName
|
versionName = flutter.versionName
|
||||||
|
targetSdkVersion 34
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,14 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:label="muzzlevelocity"
|
android:label="muzzlevelocity"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:requestLegacyExternalStorage="true">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
|
@ -42,5 +48,14 @@
|
||||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||||
<data android:mimeType="text/plain"/>
|
<data android:mimeType="text/plain"/>
|
||||||
</intent>
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.OPEN_DOCUMENT_TREE" />
|
||||||
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION"/>
|
||||||
|
</intent>
|
||||||
</queries>
|
</queries>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
package com.example.muzzlevelocity
|
package com.example.muzzlevelocity
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||||
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
|
import io.flutter.plugins.GeneratedPluginRegistrant
|
||||||
|
|
||||||
class MainActivity: FlutterActivity()
|
class MainActivity: FlutterFragmentActivity() {
|
||||||
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||||
|
GeneratedPluginRegistrant.registerWith(flutterEngine)
|
||||||
|
}
|
||||||
|
}
|
||||||
154
lib/main.dart
154
lib/main.dart
|
|
@ -1,11 +1,19 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:muzzlevelocity/themes/day.dart';
|
||||||
|
import 'package:muzzlevelocity/themes/night.dart';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'note_editor.dart';
|
import 'note_editor.dart';
|
||||||
import 'search_service.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
void main() {
|
|
||||||
|
void main() async {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
await Permission.storage.request();
|
||||||
runApp(MuzzleVelocityApp());
|
runApp(MuzzleVelocityApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,8 +52,9 @@ class _MuzzleVelocityAppState extends State<MuzzleVelocityApp> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _emptyTrash() async {
|
Future<void> _emptyTrash() async {
|
||||||
final dir = await getApplicationDocumentsDirectory();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
final trashDir = Directory('${dir.path}/notes/trash');
|
final notesPath = prefs.getString('notes_directory') ?? (await getApplicationDocumentsDirectory()).path;
|
||||||
|
final trashDir = Directory('$notesPath/trash');
|
||||||
if (trashDir.existsSync()) {
|
if (trashDir.existsSync()) {
|
||||||
trashDir.deleteSync(recursive: true);
|
trashDir.deleteSync(recursive: true);
|
||||||
trashDir.createSync();
|
trashDir.createSync();
|
||||||
|
|
@ -60,13 +69,13 @@ class _MuzzleVelocityAppState extends State<MuzzleVelocityApp> {
|
||||||
brightness: Brightness.light,
|
brightness: Brightness.light,
|
||||||
scaffoldBackgroundColor: Color(0xffF6F4F1),
|
scaffoldBackgroundColor: Color(0xffF6F4F1),
|
||||||
appBarTheme: AppBarTheme(backgroundColor: Color(0xffF6F4F1)),
|
appBarTheme: AppBarTheme(backgroundColor: Color(0xffF6F4F1)),
|
||||||
textTheme: GoogleFonts.ibmPlexMonoTextTheme(),
|
textTheme: GoogleFonts.ibmPlexMonoTextTheme(dayText),
|
||||||
),
|
),
|
||||||
darkTheme: ThemeData(
|
darkTheme: ThemeData(
|
||||||
brightness: Brightness.dark,
|
brightness: Brightness.dark,
|
||||||
scaffoldBackgroundColor: Color(0xFF121212),
|
scaffoldBackgroundColor: Color(0xFF121212),
|
||||||
appBarTheme: AppBarTheme(backgroundColor: Color(0xFF121212)),
|
appBarTheme: AppBarTheme(backgroundColor: Color(0xFF121212)),
|
||||||
textTheme: GoogleFonts.ibmPlexMonoTextTheme(),
|
textTheme: GoogleFonts.ibmPlexMonoTextTheme(nightText),
|
||||||
),
|
),
|
||||||
themeMode: _themeMode,
|
themeMode: _themeMode,
|
||||||
home: NoteListScreen(
|
home: NoteListScreen(
|
||||||
|
|
@ -103,55 +112,65 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
||||||
TextEditingController searchController = TextEditingController();
|
TextEditingController searchController = TextEditingController();
|
||||||
List<File> notes = [];
|
List<File> notes = [];
|
||||||
List<File> filteredNotes = [];
|
List<File> filteredNotes = [];
|
||||||
|
String? notesDirectoryPath;
|
||||||
|
String? defaultDir;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_loadNotes();
|
_initializeApp(); // Call an async method to handle initialization
|
||||||
searchController.addListener(() {
|
searchController.addListener(() {
|
||||||
final text = searchController.text.trim();
|
final text = searchController.text.trim();
|
||||||
|
|
||||||
if (text.startsWith(':')) {
|
if (text.startsWith(':')) {
|
||||||
_handleCommand(text);
|
_handleCommand(text);
|
||||||
} else {
|
} else {
|
||||||
_filterNotes(); // Only filter, do NOT create a note here!
|
_filterNotes();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _initializeApp() async {
|
||||||
|
final dir = await getApplicationDocumentsDirectory();
|
||||||
|
setState(() {
|
||||||
|
defaultDir = dir.path; // Update state with defaultDir
|
||||||
|
});
|
||||||
|
await _loadNotes(); // Load notes after setting defaultDir
|
||||||
|
}
|
||||||
|
|
||||||
bool _isNewNote(String title) {
|
bool _isNewNote(String title) {
|
||||||
final safeTitle = _sanitizeFilename(title);
|
final safeTitle = _sanitizeFilename(title);
|
||||||
return !notes.any((note) => note.uri.pathSegments.last == '$safeTitle.md');
|
return !notes.any((note) => note.uri.pathSegments.last == '$safeTitle.md');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _createNewNote(String title) async {
|
void _createNewNote(String title) async {
|
||||||
final dir = await getApplicationDocumentsDirectory();
|
try {
|
||||||
final notesDir = Directory('${dir.path}/notes');
|
|
||||||
|
|
||||||
if (!notesDir.existsSync()) {
|
|
||||||
notesDir.createSync(recursive: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
final safeTitle = _sanitizeFilename(title);
|
final safeTitle = _sanitizeFilename(title);
|
||||||
final newNote = File('${notesDir.path}/$safeTitle.md');
|
final newNote = File(path.join(notesDirectoryPath!, '$safeTitle.md'));
|
||||||
|
|
||||||
if (!newNote.existsSync()) {
|
if (!newNote.existsSync()) {
|
||||||
newNote.writeAsStringSync('# $title\n\n'); // Pre-fill with title
|
newNote.writeAsStringSync('# $title\n\n');
|
||||||
setState(() {
|
setState(() {
|
||||||
notes.add(newNote);
|
notes.add(newNote);
|
||||||
filteredNotes.add(newNote);
|
filteredNotes.add(newNote);
|
||||||
});
|
});
|
||||||
|
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => NoteEditorScreen(
|
builder: (context) => NoteEditorScreen(
|
||||||
note: newNote,
|
note: newNote,
|
||||||
isDarkMode: widget.isDarkMode,
|
isDarkMode: widget.isDarkMode,
|
||||||
|
notesDirectoryPath: notesDirectoryPath,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text('Failed to create note: $e'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _sanitizeFilename(String title) {
|
String _sanitizeFilename(String title) {
|
||||||
|
|
@ -210,20 +229,57 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
||||||
|
|
||||||
|
|
||||||
Future<void> _loadNotes() async {
|
Future<void> _loadNotes() async {
|
||||||
final dir = await getApplicationDocumentsDirectory();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
final notesDir = Directory('${dir.path}/notes');
|
notesDirectoryPath = prefs.getString('notes_directory') ?? defaultDir; // Use custom or default directory
|
||||||
|
|
||||||
|
final notesDir = Directory(notesDirectoryPath!);
|
||||||
if (!notesDir.existsSync()) {
|
if (!notesDir.existsSync()) {
|
||||||
notesDir.createSync(recursive: true);
|
notesDir.createSync(recursive: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
final files = notesDir.listSync().whereType<File>().where((file) => file.path.endsWith('.md')).toList();
|
final files = notesDir.listSync().whereType<File>().where((file) => file.path.endsWith('.md')).toList();
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
setState(() {
|
||||||
notes = files;
|
notes = files;
|
||||||
filteredNotes = files;
|
filteredNotes = files;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _showDirectoryChoiceDialog(String defaultPath) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false, // Force user to make a choice
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text("Choose Notes Directory"),
|
||||||
|
content: Text("Your notes will be saved in:\n\n📂 $defaultPath\n\nWould you like to use a different folder?"),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
// Reset to default directory
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
await prefs.remove('notes_directory'); // Remove custom directory from preferences
|
||||||
|
setState(() {
|
||||||
|
notesDirectoryPath = defaultDir; // Reset to default directory
|
||||||
|
});
|
||||||
|
Navigator.pop(context); // Close dialog
|
||||||
|
_loadNotes(); // Reload notes from the default directory
|
||||||
|
},
|
||||||
|
child: Text("Use Default"),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
Navigator.pop(context); // Close the current dialog
|
||||||
|
await _selectNotesDirectory(); // Allow user to pick a folder
|
||||||
|
},
|
||||||
|
child: Text("Choose Folder"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _filterNotes() {
|
void _filterNotes() {
|
||||||
final query = searchController.text.toLowerCase();
|
final query = searchController.text.toLowerCase();
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
@ -279,6 +335,38 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
||||||
return spans;
|
return spans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _selectNotesDirectory() async {
|
||||||
|
String? selectedDirectory = await FilePicker.platform.getDirectoryPath();
|
||||||
|
if (selectedDirectory != null) {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
await prefs.setString('notes_directory', selectedDirectory); // Save custom directory
|
||||||
|
setState(() {
|
||||||
|
notesDirectoryPath = selectedDirectory; // Update state
|
||||||
|
});
|
||||||
|
_loadNotes(); // Reload notes from the new directory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _requestStoragePermission() async {
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
if (await Permission.storage.request().isGranted) {
|
||||||
|
print("✅ Basic storage permission granted.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For Android 11+ (Scoped Storage)
|
||||||
|
if (await Permission.manageExternalStorage.request().isGranted) {
|
||||||
|
print("✅ Full file access granted.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
print("❌ Storage permission denied. Opening settings...");
|
||||||
|
await openAppSettings(); // Open settings if denied
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true; // No permissions needed for other platforms
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
|
@ -322,6 +410,9 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
||||||
widget.toggleTheme(!widget.isDarkMode);
|
widget.toggleTheme(!widget.isDarkMode);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case 'Select Folder':
|
||||||
|
_showDirectoryChoiceDialog(notesDirectoryPath ?? ''); // Re-trigger popup
|
||||||
|
break;
|
||||||
case 'Empty Trash':
|
case 'Empty Trash':
|
||||||
_confirmEmptyTrash();
|
_confirmEmptyTrash();
|
||||||
break;
|
break;
|
||||||
|
|
@ -346,6 +437,13 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
PopupMenuItem<String>(
|
||||||
|
value: 'Select Folder',
|
||||||
|
child: ListTile(
|
||||||
|
leading: Icon(Icons.folder),
|
||||||
|
title: Text('Set Notes Directory'),
|
||||||
|
),
|
||||||
|
),
|
||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
value: 'Empty Trash',
|
value: 'Empty Trash',
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
|
|
@ -386,14 +484,16 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
||||||
await Navigator.push(
|
await Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => NoteEditorScreen(
|
builder: (context) =>
|
||||||
note: noteFile,
|
NoteEditorScreen(
|
||||||
|
note: File(path.join(notesDirectoryPath!, noteFile.uri.pathSegments.last)),
|
||||||
isDarkMode: widget.isDarkMode,
|
isDarkMode: widget.isDarkMode,
|
||||||
|
notesDirectoryPath: notesDirectoryPath,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
_loadNotes(); // 🔄 Reload notes after returning
|
_loadNotes(); // Reload notes after returning
|
||||||
setState(() {}); // 🔄 Force UI refresh
|
setState(() {}); // Force UI refresh
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,21 @@ import 'themes/day.dart';
|
||||||
import 'themes/night.dart';
|
import 'themes/night.dart';
|
||||||
import 'themes/markdown.dart';
|
import 'themes/markdown.dart';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
class NoteEditorScreen extends StatefulWidget {
|
class NoteEditorScreen extends StatefulWidget {
|
||||||
final File note;
|
final File note;
|
||||||
|
final String? notesDirectoryPath; // ✅ Add this
|
||||||
bool isDarkMode;
|
bool isDarkMode;
|
||||||
|
|
||||||
NoteEditorScreen({required this.note, required this.isDarkMode});
|
NoteEditorScreen({required this.note, required this.isDarkMode, required this.notesDirectoryPath});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_NoteEditorScreenState createState() => _NoteEditorScreenState();
|
_NoteEditorScreenState createState() => _NoteEditorScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _NoteEditorScreenState extends State<NoteEditorScreen> {
|
class _NoteEditorScreenState extends State<NoteEditorScreen> {
|
||||||
|
bool isLoading = true;
|
||||||
bool _isPreviewMode = false; // Default: Editing mode
|
bool _isPreviewMode = false; // Default: Editing mode
|
||||||
late CodeController _controller;
|
late CodeController _controller;
|
||||||
double _fontSize = 16.0; // Default font size
|
double _fontSize = 16.0; // Default font size
|
||||||
|
|
@ -37,7 +40,13 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _loadNoteContent() async {
|
Future<void> _loadNoteContent() async {
|
||||||
final content = await widget.note.readAsString();
|
String content = "";
|
||||||
|
try {
|
||||||
|
content = await widget.note.readAsString();
|
||||||
|
} catch (e) {
|
||||||
|
print("❌ Failed to read file: ${widget.note.path}");
|
||||||
|
}
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_controller = CodeController(
|
_controller = CodeController(
|
||||||
text: content,
|
text: content,
|
||||||
|
|
@ -45,11 +54,26 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
|
||||||
);
|
);
|
||||||
_controller.addListener(_saveNote);
|
_controller.addListener(_saveNote);
|
||||||
_controller.popupController.enabled = false;
|
_controller.popupController.enabled = false;
|
||||||
|
isLoading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<void> _saveNote() async {
|
Future<void> _saveNote() async {
|
||||||
await widget.note.writeAsString(_controller.text);
|
try {
|
||||||
|
final notesDirectory = widget.notesDirectoryPath ?? widget.note.parent.path; // ✅ Use correct directory
|
||||||
|
final newFilePath = path.join(notesDirectory, widget.note.uri.pathSegments.last);
|
||||||
|
|
||||||
|
print("📝 Attempting to save note at: $newFilePath");
|
||||||
|
final newFile = File(newFilePath);
|
||||||
|
await newFile.writeAsString(_controller.text);
|
||||||
|
|
||||||
|
print("✅ Successfully saved note at: $newFilePath");
|
||||||
|
} catch (e, stackTrace) {
|
||||||
|
print("❌ Error saving note: ${widget.note.path}");
|
||||||
|
print("⚠️ Exception: $e");
|
||||||
|
print("🛠 Stack trace: $stackTrace");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -118,7 +142,9 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: _controller == null
|
body: isLoading
|
||||||
|
? Center(child: CircularProgressIndicator()) // Show loader while initializing
|
||||||
|
: _controller == null
|
||||||
? Center(child: CircularProgressIndicator())
|
? Center(child: CircularProgressIndicator())
|
||||||
: _isPreviewMode
|
: _isPreviewMode
|
||||||
? Padding(
|
? Padding(
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,24 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/painting.dart';
|
import 'package:flutter/painting.dart';
|
||||||
|
|
||||||
|
const TextTheme dayText = TextTheme(
|
||||||
|
titleLarge: TextStyle(color: Color(0xff333333)),
|
||||||
|
bodyLarge: TextStyle(color: Color(0xff333333)),
|
||||||
|
bodyMedium: TextStyle(color: Color(0xff333333)),
|
||||||
|
bodySmall: TextStyle(color: Color(0xff333333)),
|
||||||
|
displayLarge: TextStyle(color: Color(0xff333333)),
|
||||||
|
displayMedium: TextStyle(color: Color(0xff333333)),
|
||||||
|
displaySmall: TextStyle(color: Color(0xff333333)),
|
||||||
|
headlineLarge: TextStyle(color: Color(0xff333333)),
|
||||||
|
headlineMedium: TextStyle(color: Color(0xff333333)),
|
||||||
|
headlineSmall: TextStyle(color: Color(0xff333333)),
|
||||||
|
labelLarge: TextStyle(color: Color(0xff333333)),
|
||||||
|
labelMedium: TextStyle(color: Color(0xff333333)),
|
||||||
|
labelSmall: TextStyle(color: Color(0xff333333)),
|
||||||
|
titleMedium: TextStyle(color: Color(0xff333333)),
|
||||||
|
titleSmall: TextStyle(color: Color(0xff333333)),
|
||||||
|
);
|
||||||
|
|
||||||
const dayTheme = {
|
const dayTheme = {
|
||||||
'root':
|
'root':
|
||||||
TextStyle(backgroundColor: Color(0xffF6F4F1), color: Color(0xff333333)),
|
TextStyle(backgroundColor: Color(0xffF6F4F1), color: Color(0xff333333)),
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,24 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/painting.dart';
|
import 'package:flutter/painting.dart';
|
||||||
|
|
||||||
|
const TextTheme nightText = TextTheme(
|
||||||
|
titleLarge: TextStyle(color: Color(0xffc5c8c6)),
|
||||||
|
bodyLarge: TextStyle(color: Color(0xffc5c8c6)),
|
||||||
|
bodyMedium: TextStyle(color: Color(0xffc5c8c6)),
|
||||||
|
bodySmall: TextStyle(color: Color(0xffc5c8c6)),
|
||||||
|
displayLarge: TextStyle(color: Color(0xffc5c8c6)),
|
||||||
|
displayMedium: TextStyle(color: Color(0xffc5c8c6)),
|
||||||
|
displaySmall: TextStyle(color: Color(0xffc5c8c6)),
|
||||||
|
headlineLarge: TextStyle(color: Color(0xffc5c8c6)),
|
||||||
|
headlineMedium: TextStyle(color: Color(0xffc5c8c6)),
|
||||||
|
headlineSmall: TextStyle(color: Color(0xffc5c8c6)),
|
||||||
|
labelLarge: TextStyle(color: Color(0xffc5c8c6)),
|
||||||
|
labelMedium: TextStyle(color: Color(0xffc5c8c6)),
|
||||||
|
labelSmall: TextStyle(color: Color(0xffc5c8c6)),
|
||||||
|
titleMedium: TextStyle(color: Color(0xffc5c8c6)),
|
||||||
|
titleSmall: TextStyle(color: Color(0xffc5c8c6)),
|
||||||
|
);
|
||||||
|
|
||||||
const nightTheme = {
|
const nightTheme = {
|
||||||
'comment': TextStyle(color: Color(0xff969896)),
|
'comment': TextStyle(color: Color(0xff969896)),
|
||||||
'quote': TextStyle(color: Color(0xff969896)),
|
'quote': TextStyle(color: Color(0xff969896)),
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,14 @@
|
||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
import file_picker
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
|
import shared_preferences_foundation
|
||||||
import url_launcher_macos
|
import url_launcher_macos
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
|
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
144
pubspec.lock
144
pubspec.lock
|
|
@ -65,6 +65,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.19.0"
|
version: "1.19.0"
|
||||||
|
cross_file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cross_file
|
||||||
|
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.4+2"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -105,6 +113,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.3"
|
version: "2.1.3"
|
||||||
|
file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file
|
||||||
|
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.1"
|
||||||
|
file_picker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: file_picker
|
||||||
|
sha256: "6f6bfa8797f296965bdc3e1f702574ab49a540c19b9237b401e7c2b25dfe594c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.0.0"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
@ -158,6 +182,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.3"
|
version: "0.7.3"
|
||||||
|
flutter_plugin_android_lifecycle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_plugin_android_lifecycle
|
||||||
|
sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.24"
|
||||||
flutter_svg:
|
flutter_svg:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -368,6 +400,54 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.3.0"
|
||||||
|
permission_handler:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: permission_handler
|
||||||
|
sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "11.4.0"
|
||||||
|
permission_handler_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_android
|
||||||
|
sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "12.1.0"
|
||||||
|
permission_handler_apple:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_apple
|
||||||
|
sha256: f84a188e79a35c687c132a0a0556c254747a08561e99ab933f12f6ca71ef3c98
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.4.6"
|
||||||
|
permission_handler_html:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_html
|
||||||
|
sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.3+5"
|
||||||
|
permission_handler_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_platform_interface
|
||||||
|
sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.3.0"
|
||||||
|
permission_handler_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_windows
|
||||||
|
sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1"
|
||||||
petitparser:
|
petitparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -408,6 +488,62 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.8"
|
version: "0.3.8"
|
||||||
|
shared_preferences:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: shared_preferences
|
||||||
|
sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.2"
|
||||||
|
shared_preferences_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_android
|
||||||
|
sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.6"
|
||||||
|
shared_preferences_foundation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_foundation
|
||||||
|
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.4"
|
||||||
|
shared_preferences_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_linux
|
||||||
|
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
|
shared_preferences_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_platform_interface
|
||||||
|
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
|
shared_preferences_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_web
|
||||||
|
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.3"
|
||||||
|
shared_preferences_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_windows
|
||||||
|
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
@ -589,6 +725,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
|
win32:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: win32
|
||||||
|
sha256: daf97c9d80197ed7b619040e86c8ab9a9dad285e7671ee7390f9180cc828a51e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.10.1"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,9 @@ dependencies:
|
||||||
flutter_code_editor: ^0.3.2
|
flutter_code_editor: ^0.3.2
|
||||||
flutter_markdown: ^0.7.6+2
|
flutter_markdown: ^0.7.6+2
|
||||||
flutter_markdown_latex: ^0.3.4
|
flutter_markdown_latex: ^0.3.4
|
||||||
|
permission_handler: ^11.4.0
|
||||||
|
shared_preferences: ^2.5.2
|
||||||
|
file_picker: ^9.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,12 @@
|
||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||||
UrlLauncherWindowsRegisterWithRegistrar(
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
permission_handler_windows
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue