use external editor, manage permissions
This commit is contained in:
parent
05026b3fe2
commit
34580109bb
4 changed files with 117 additions and 14 deletions
|
|
@ -3,6 +3,7 @@
|
|||
<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"/>
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
|
||||
|
||||
<application
|
||||
android:label="muzzlevelocity"
|
||||
|
|
@ -57,5 +58,8 @@
|
|||
<intent>
|
||||
<action android:name="android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION"/>
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
</intent>
|
||||
</queries>
|
||||
</manifest>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ import 'dart:io';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:open_filex/open_filex.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'note_editor.dart';
|
||||
|
|
@ -30,6 +32,7 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
|||
List<File> filteredNotes = [];
|
||||
String? notesDirectoryPath;
|
||||
String? defaultDir;
|
||||
bool _useExternalEditor = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
|
@ -45,12 +48,33 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
|||
});
|
||||
}
|
||||
|
||||
Future<void> _requestStoragePermission() async {
|
||||
if (Platform.isAndroid) {
|
||||
if (await Permission.storage.request().isGranted) {
|
||||
print("✅ Basic storage permission granted.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (await Permission.manageExternalStorage.request().isGranted) {
|
||||
print("✅ Full file access granted.");
|
||||
return;
|
||||
}
|
||||
|
||||
print("❌ Storage permission denied. Opening settings...");
|
||||
await openAppSettings(); // Open settings if denied
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _initializeApp() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final dir = await getApplicationDocumentsDirectory();
|
||||
|
||||
setState(() {
|
||||
defaultDir = dir.path; // Update state with defaultDir
|
||||
defaultDir = dir.path;
|
||||
_useExternalEditor = prefs.getBool('use_external_editor') ?? false;
|
||||
});
|
||||
await _loadNotes(); // Load notes after setting defaultDir
|
||||
|
||||
await _loadNotes();
|
||||
}
|
||||
|
||||
void _showDirectoryChoiceDialog(String defaultPath) {
|
||||
|
|
@ -79,6 +103,7 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
|||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await _requestStoragePermission();
|
||||
Navigator.pop(context); // Close the current dialog
|
||||
await _selectNotesDirectory(); // Allow user to pick a folder
|
||||
},
|
||||
|
|
@ -194,6 +219,25 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
|||
.trim();
|
||||
}
|
||||
|
||||
Future<void> _openExternalEditor(File noteFile) async {
|
||||
if (!noteFile.existsSync()) {
|
||||
print("❌ File does not exist: ${noteFile.path}");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (Platform.isAndroid) {
|
||||
await _requestStoragePermission();
|
||||
}
|
||||
|
||||
final result = await OpenFilex.open(noteFile.path);
|
||||
print("✅ OpenFilex result: ${result.type}, message: ${result.message}");
|
||||
} catch (e) {
|
||||
print("❌ Failed to open external editor: $e");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _deleteNote(File note) {
|
||||
final trashDir = Directory('${note.parent.path}/trash');
|
||||
if (!trashDir.existsSync()) {
|
||||
|
|
@ -326,6 +370,14 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
|||
widget.toggleTheme(!widget.isDarkMode);
|
||||
});
|
||||
break;
|
||||
case 'External Editor':
|
||||
setState(() {
|
||||
_useExternalEditor = !_useExternalEditor;
|
||||
});
|
||||
SharedPreferences.getInstance().then((prefs) {
|
||||
prefs.setBool('use_external_editor', _useExternalEditor);
|
||||
});
|
||||
break;
|
||||
case 'Select Folder':
|
||||
_showDirectoryChoiceDialog(
|
||||
notesDirectoryPath ?? ''); // Re-trigger popup
|
||||
|
|
@ -359,6 +411,21 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
|||
),
|
||||
),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'External Editor',
|
||||
child: ListTile(
|
||||
leading: Icon(
|
||||
_useExternalEditor
|
||||
? Icons.open_in_new_off
|
||||
: Icons.open_in_new,
|
||||
),
|
||||
title: Text(
|
||||
!_useExternalEditor
|
||||
? 'Use External Editor'
|
||||
: 'Use Internal Editor',
|
||||
),
|
||||
),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'Select Folder',
|
||||
child: ListTile(
|
||||
|
|
@ -410,19 +477,42 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
|||
children: tagSpans))
|
||||
: null,
|
||||
onTap: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => NoteEditorScreen(
|
||||
note: File(path.join(notesDirectoryPath!,
|
||||
noteFile.uri.pathSegments.last)),
|
||||
isDarkMode: widget.isDarkMode,
|
||||
notesDirectoryPath: notesDirectoryPath,
|
||||
if (_useExternalEditor) {
|
||||
// Open with system's default editor
|
||||
try {
|
||||
if (Platform.isLinux) {
|
||||
final result = await Process.run('which', ['xdg-open']);
|
||||
if (result.stdout.toString().trim().isNotEmpty) {
|
||||
await Process.run('xdg-open', [noteFile.path]);
|
||||
} else {
|
||||
print("❌ `xdg-open` is not available.");
|
||||
}
|
||||
} else if (Platform.isAndroid) {
|
||||
await _requestStoragePermission();
|
||||
final result = await OpenFilex.open(
|
||||
noteFile.path,
|
||||
type: "text/markdown",
|
||||
);
|
||||
print("✅ OpenFilex result: ${result.type}, message: ${result.message}");
|
||||
}
|
||||
} catch (e) {
|
||||
print("❌ Failed to open external editor: $e");
|
||||
}
|
||||
} else {
|
||||
// Open internally
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
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
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -336,6 +336,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
open_filex:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: open_filex
|
||||
sha256: dcb7bd3d32db8db5260253a62f1564c02c2c8df64bc0187cd213f65f827519bd
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.6.0"
|
||||
path:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ dependencies:
|
|||
permission_handler: ^11.4.0
|
||||
shared_preferences: ^2.5.2
|
||||
highlight: ^0.7.0
|
||||
open_filex: ^4.6.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue