diff --git a/android/app/build.gradle b/android/app/build.gradle
index 42606da..8e29607 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -9,6 +9,7 @@ android {
namespace = "com.example.muzzlevelocity"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
+ compileSdkVersion 34
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
@@ -28,6 +29,7 @@ android {
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
+ targetSdkVersion 34
}
buildTypes {
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 2c16406..ba0b42b 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,8 +1,14 @@
+
+
+
+
+
+ android:icon="@mipmap/ic_launcher"
+ android:requestLegacyExternalStorage="true">
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/kotlin/com/example/muzzlevelocity/MainActivity.kt b/android/app/src/main/kotlin/com/example/muzzlevelocity/MainActivity.kt
index 46cc26b..ce0d7fc 100644
--- a/android/app/src/main/kotlin/com/example/muzzlevelocity/MainActivity.kt
+++ b/android/app/src/main/kotlin/com/example/muzzlevelocity/MainActivity.kt
@@ -1,5 +1,11 @@
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)
+ }
+}
\ No newline at end of file
diff --git a/lib/main.dart b/lib/main.dart
index 324f718..e168e24 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,11 +1,19 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
+import 'package:muzzlevelocity/themes/day.dart';
+import 'package:muzzlevelocity/themes/night.dart';
import 'dart:io';
import 'package:path_provider/path_provider.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());
}
@@ -44,8 +52,9 @@ class _MuzzleVelocityAppState extends State {
}
Future _emptyTrash() async {
- final dir = await getApplicationDocumentsDirectory();
- final trashDir = Directory('${dir.path}/notes/trash');
+ final prefs = await SharedPreferences.getInstance();
+ final notesPath = prefs.getString('notes_directory') ?? (await getApplicationDocumentsDirectory()).path;
+ final trashDir = Directory('$notesPath/trash');
if (trashDir.existsSync()) {
trashDir.deleteSync(recursive: true);
trashDir.createSync();
@@ -60,13 +69,13 @@ class _MuzzleVelocityAppState extends State {
brightness: Brightness.light,
scaffoldBackgroundColor: Color(0xffF6F4F1),
appBarTheme: AppBarTheme(backgroundColor: Color(0xffF6F4F1)),
- textTheme: GoogleFonts.ibmPlexMonoTextTheme(),
+ textTheme: GoogleFonts.ibmPlexMonoTextTheme(dayText),
),
darkTheme: ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: Color(0xFF121212),
appBarTheme: AppBarTheme(backgroundColor: Color(0xFF121212)),
- textTheme: GoogleFonts.ibmPlexMonoTextTheme(),
+ textTheme: GoogleFonts.ibmPlexMonoTextTheme(nightText),
),
themeMode: _themeMode,
home: NoteListScreen(
@@ -103,52 +112,62 @@ class _NoteListScreenState extends State {
TextEditingController searchController = TextEditingController();
List notes = [];
List filteredNotes = [];
+ String? notesDirectoryPath;
+ String? defaultDir;
@override
void initState() {
super.initState();
- _loadNotes();
+ _initializeApp(); // Call an async method to handle initialization
searchController.addListener(() {
final text = searchController.text.trim();
-
if (text.startsWith(':')) {
_handleCommand(text);
} else {
- _filterNotes(); // Only filter, do NOT create a note here!
+ _filterNotes();
}
});
}
+ Future _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) {
final safeTitle = _sanitizeFilename(title);
return !notes.any((note) => note.uri.pathSegments.last == '$safeTitle.md');
}
- Future _createNewNote(String title) async {
- final dir = await getApplicationDocumentsDirectory();
- final notesDir = Directory('${dir.path}/notes');
+ void _createNewNote(String title) async {
+ try {
+ final safeTitle = _sanitizeFilename(title);
+ final newNote = File(path.join(notesDirectoryPath!, '$safeTitle.md'));
- if (!notesDir.existsSync()) {
- notesDir.createSync(recursive: true);
- }
-
- final safeTitle = _sanitizeFilename(title);
- final newNote = File('${notesDir.path}/$safeTitle.md');
-
- if (!newNote.existsSync()) {
- newNote.writeAsStringSync('# $title\n\n'); // Pre-fill with title
- setState(() {
- notes.add(newNote);
- filteredNotes.add(newNote);
- });
-
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => NoteEditorScreen(
- note: newNote,
- isDarkMode: widget.isDarkMode,
+ if (!newNote.existsSync()) {
+ newNote.writeAsStringSync('# $title\n\n');
+ setState(() {
+ notes.add(newNote);
+ filteredNotes.add(newNote);
+ });
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => NoteEditorScreen(
+ note: newNote,
+ isDarkMode: widget.isDarkMode,
+ notesDirectoryPath: notesDirectoryPath,
+ ),
),
+ );
+ }
+ } catch (e) {
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(
+ content: Text('Failed to create note: $e'),
),
);
}
@@ -210,20 +229,57 @@ class _NoteListScreenState extends State {
Future _loadNotes() async {
- final dir = await getApplicationDocumentsDirectory();
- final notesDir = Directory('${dir.path}/notes');
+ final prefs = await SharedPreferences.getInstance();
+ notesDirectoryPath = prefs.getString('notes_directory') ?? defaultDir; // Use custom or default directory
+
+ final notesDir = Directory(notesDirectoryPath!);
if (!notesDir.existsSync()) {
notesDir.createSync(recursive: true);
}
+
final files = notesDir.listSync().whereType().where((file) => file.path.endsWith('.md')).toList();
- if (mounted) {
- setState(() {
- notes = files;
- filteredNotes = files;
- });
- }
+ setState(() {
+ notes = 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() {
final query = searchController.text.toLowerCase();
setState(() {
@@ -279,6 +335,38 @@ class _NoteListScreenState extends State {
return spans;
}
+ Future _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 _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
Widget build(BuildContext context) {
return Scaffold(
@@ -322,6 +410,9 @@ class _NoteListScreenState extends State {
widget.toggleTheme(!widget.isDarkMode);
});
break;
+ case 'Select Folder':
+ _showDirectoryChoiceDialog(notesDirectoryPath ?? ''); // Re-trigger popup
+ break;
case 'Empty Trash':
_confirmEmptyTrash();
break;
@@ -346,6 +437,13 @@ class _NoteListScreenState extends State {
),
),
),
+ PopupMenuItem(
+ value: 'Select Folder',
+ child: ListTile(
+ leading: Icon(Icons.folder),
+ title: Text('Set Notes Directory'),
+ ),
+ ),
PopupMenuItem(
value: 'Empty Trash',
child: ListTile(
@@ -386,14 +484,16 @@ class _NoteListScreenState extends State {
await Navigator.push(
context,
MaterialPageRoute(
- builder: (context) => NoteEditorScreen(
- note: noteFile,
- isDarkMode: widget.isDarkMode,
- ),
+ builder: (context) =>
+ NoteEditorScreen(
+ note: File(path.join(notesDirectoryPath!, noteFile.uri.pathSegments.last)),
+ isDarkMode: widget.isDarkMode,
+ notesDirectoryPath: notesDirectoryPath,
+ ),
),
);
- _loadNotes(); // š Reload notes after returning
- setState(() {}); // š Force UI refresh
+ _loadNotes(); // Reload notes after returning
+ setState(() {}); // Force UI refresh
},
),
);
diff --git a/lib/note_editor.dart b/lib/note_editor.dart
index 03652ef..44dad8b 100644
--- a/lib/note_editor.dart
+++ b/lib/note_editor.dart
@@ -7,18 +7,21 @@ import 'themes/day.dart';
import 'themes/night.dart';
import 'themes/markdown.dart';
import 'dart:io';
+import 'package:path/path.dart' as path;
class NoteEditorScreen extends StatefulWidget {
final File note;
+ final String? notesDirectoryPath; // ā
Add this
bool isDarkMode;
- NoteEditorScreen({required this.note, required this.isDarkMode});
+ NoteEditorScreen({required this.note, required this.isDarkMode, required this.notesDirectoryPath});
@override
_NoteEditorScreenState createState() => _NoteEditorScreenState();
}
class _NoteEditorScreenState extends State {
+ bool isLoading = true;
bool _isPreviewMode = false; // Default: Editing mode
late CodeController _controller;
double _fontSize = 16.0; // Default font size
@@ -37,7 +40,13 @@ class _NoteEditorScreenState extends State {
}
Future _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(() {
_controller = CodeController(
text: content,
@@ -45,11 +54,26 @@ class _NoteEditorScreenState extends State {
);
_controller.addListener(_saveNote);
_controller.popupController.enabled = false;
+ isLoading = false;
});
}
+
Future _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
@@ -118,10 +142,12 @@ class _NoteEditorScreenState extends State {
),
],
),
- body: _controller == null
- ? Center(child: CircularProgressIndicator())
- : _isPreviewMode
- ? Padding(
+ body: isLoading
+ ? Center(child: CircularProgressIndicator()) // Show loader while initializing
+ : _controller == null
+ ? Center(child: CircularProgressIndicator())
+ : _isPreviewMode
+ ? Padding(
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: MarkdownBody(
diff --git a/lib/themes/day.dart b/lib/themes/day.dart
index b3398c0..7033e5f 100644
--- a/lib/themes/day.dart
+++ b/lib/themes/day.dart
@@ -3,6 +3,24 @@
import 'package:flutter/material.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 = {
'root':
TextStyle(backgroundColor: Color(0xffF6F4F1), color: Color(0xff333333)),
diff --git a/lib/themes/night.dart b/lib/themes/night.dart
index d1ac776..8f6bc79 100644
--- a/lib/themes/night.dart
+++ b/lib/themes/night.dart
@@ -3,6 +3,24 @@
import 'package:flutter/material.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 = {
'comment': TextStyle(color: Color(0xff969896)),
'quote': TextStyle(color: Color(0xff969896)),
diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift
index a1cdfd0..b832e00 100644
--- a/macos/Flutter/GeneratedPluginRegistrant.swift
+++ b/macos/Flutter/GeneratedPluginRegistrant.swift
@@ -5,10 +5,14 @@
import FlutterMacOS
import Foundation
+import file_picker
import path_provider_foundation
+import shared_preferences_foundation
import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
+ FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
+ SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
}
diff --git a/pubspec.lock b/pubspec.lock
index 263d3dc..af38ab8 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -65,6 +65,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
@@ -105,6 +113,22 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: "direct main"
description: flutter
@@ -158,6 +182,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
@@ -368,6 +400,54 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
@@ -408,6 +488,62 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description: flutter
@@ -589,6 +725,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.0"
+ win32:
+ dependency: transitive
+ description:
+ name: win32
+ sha256: daf97c9d80197ed7b619040e86c8ab9a9dad285e7671ee7390f9180cc828a51e
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.10.1"
xdg_directories:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index b1db1d0..3d2f2d7 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -40,6 +40,9 @@ dependencies:
flutter_code_editor: ^0.3.2
flutter_markdown: ^0.7.6+2
flutter_markdown_latex: ^0.3.4
+ permission_handler: ^11.4.0
+ shared_preferences: ^2.5.2
+ file_picker: ^9.0.0
dev_dependencies:
flutter_test:
diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc
index 4f78848..a0d0bbe 100644
--- a/windows/flutter/generated_plugin_registrant.cc
+++ b/windows/flutter/generated_plugin_registrant.cc
@@ -6,9 +6,12 @@
#include "generated_plugin_registrant.h"
+#include
#include
void RegisterPlugins(flutter::PluginRegistry* registry) {
+ PermissionHandlerWindowsPluginRegisterWithRegistrar(
+ registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
}
diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake
index 88b22e5..c20a586 100644
--- a/windows/flutter/generated_plugins.cmake
+++ b/windows/flutter/generated_plugins.cmake
@@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
+ permission_handler_windows
url_launcher_windows
)