diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index e2407688..4b574f77 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,9 +1,6 @@ - - - +=-;:~,._;/\\|()[]'{}')", "error_password_do_not_match": "Passwords do not match", - "error_access_external_storage_required": "Please grant access to external storage or save the file to the internal storage.", + "error_permission": "Failed to get permission to write the file.", + "error_read_file": "Failed to read the file.", "login_email": "Email", "login_password": "Password", "login_log_in": "Log in", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 80eb007a..187dd973 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -12,7 +12,8 @@ "error_required": "Requis", "error_password_requirements": "Requis:\n• 12 caractères\n• 1 minuscule\n• 1 majuscule\n• 1 nombre\n• 1 caractère spécial (!@#$&%*^\"''`<>+=-;:~,._;/\\|()[]'{}')", "error_password_do_not_match": "Les mots de passe ne correspondent pas", - "error_access_external_storage_required": "Veuillez autoriser l''accès au stockage externe où sauvegarder le fichier sur le stockage interne.", + "error_permission": "Échec lors de la demande de permission pour écrire le fichier.", + "error_read_file": "Échec lors de la lecture du fichier.", "login_email": "Email", "login_password": "Mot de passe", "login_log_in": "Se connecter", diff --git a/lib/l10n/app_localizations.g.dart b/lib/l10n/app_localizations.g.dart index b6acdf66..eef62901 100644 --- a/lib/l10n/app_localizations.g.dart +++ b/lib/l10n/app_localizations.g.dart @@ -168,11 +168,17 @@ abstract class AppLocalizations { /// **'Passwords do not match'** String get error_password_do_not_match; - /// No description provided for @error_access_external_storage_required. + /// No description provided for @error_permission. /// /// In en, this message translates to: - /// **'Please grant access to external storage or save the file to the internal storage.'** - String get error_access_external_storage_required; + /// **'Failed to get permission to write the file.'** + String get error_permission; + + /// No description provided for @error_read_file. + /// + /// In en, this message translates to: + /// **'Failed to read the file.'** + String get error_read_file; /// No description provided for @login_email. /// diff --git a/lib/l10n/app_localizations_en.g.dart b/lib/l10n/app_localizations_en.g.dart index 4012f8e5..17a3d115 100644 --- a/lib/l10n/app_localizations_en.g.dart +++ b/lib/l10n/app_localizations_en.g.dart @@ -49,8 +49,10 @@ class AppLocalizationsEn extends AppLocalizations { String get error_password_do_not_match => 'Passwords do not match'; @override - String get error_access_external_storage_required => - 'Please grant access to external storage or save the file to the internal storage.'; + String get error_permission => 'Failed to get permission to write the file.'; + + @override + String get error_read_file => 'Failed to read the file.'; @override String get login_email => 'Email'; diff --git a/lib/l10n/app_localizations_fr.g.dart b/lib/l10n/app_localizations_fr.g.dart index e21399c6..67deb759 100644 --- a/lib/l10n/app_localizations_fr.g.dart +++ b/lib/l10n/app_localizations_fr.g.dart @@ -49,8 +49,10 @@ class AppLocalizationsFr extends AppLocalizations { String get error_password_do_not_match => 'Les mots de passe ne correspondent pas'; @override - String get error_access_external_storage_required => - 'Veuillez autoriser l\'accès au stockage externe où sauvegarder le fichier sur le stockage interne.'; + String get error_permission => 'Échec lors de la demande de permission pour écrire le fichier.'; + + @override + String get error_read_file => 'Échec lors de la lecture du fichier.'; @override String get login_email => 'Email'; diff --git a/lib/utils/database_manager.dart b/lib/utils/database_manager.dart index 12108963..870c4396 100644 --- a/lib/utils/database_manager.dart +++ b/lib/utils/database_manager.dart @@ -1,18 +1,15 @@ import 'dart:convert'; -import 'dart:io'; import 'dart:ui'; -import 'package:file_picker/file_picker.dart'; import 'package:is_first_run/is_first_run.dart'; import 'package:isar/isar.dart'; import 'package:localmaterialnotes/models/note/note.dart'; import 'package:localmaterialnotes/utils/constants/constants.dart'; import 'package:localmaterialnotes/utils/extensions/date_time_extensions.dart'; -import 'package:localmaterialnotes/utils/info_manager.dart'; import 'package:localmaterialnotes/utils/locale_manager.dart'; import 'package:localmaterialnotes/utils/preferences/sort_method.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:permission_handler/permission_handler.dart'; +import 'package:shared_storage/shared_storage.dart' as saf; class DatabaseManager { static final DatabaseManager _singleton = DatabaseManager._internal(); @@ -89,56 +86,40 @@ class DatabaseManager { } Future export() async { - final exportDirectory = await FilePicker.platform.getDirectoryPath(); + final exportDirectory = await saf.openDocumentTree(); - if (exportDirectory == null) return; - - await _checkPermissions(exportDirectory); + if (exportDirectory == null) throw Exception(localizations.error_permission); final timestamp = DateTime.timestamp(); - final exportFile = File('$exportDirectory/materialnotes_export_${timestamp.filename}.json'); - final notes = await _database.notes.where().findAll(); final notesJson = jsonEncode(notes); - await exportFile.writeAsString(notesJson); + + await saf.createFileAsString( + exportDirectory, + mimeType: 'application/json', + displayName: 'materialnotes_export_${timestamp.filename}.json', + content: notesJson, + ); } Future import() async { - final filePickerResult = await FilePicker.platform.pickFiles( - type: FileType.custom, - allowedExtensions: ['json'], + final importFiles = await saf.openDocument( + grantWritePermission: false, + mimeType: 'application/json', ); - if (filePickerResult == null || filePickerResult.count == 0) return; + if (importFiles == null || importFiles.isEmpty) throw Exception(localizations.error_permission); - final importFilePath = filePickerResult.paths.first!; + final importData = await saf.getDocumentContentAsString(importFiles.first); - await _checkPermissions(importFilePath); + if (importData == null) throw Exception(localizations.error_read_file); - final importFile = File(importFilePath); - final notesJson = jsonDecode(await importFile.readAsString()) as List; + final notesJson = jsonDecode(importData) as List; final notes = notesJson.map((e) => Note.fromJson(e as Map)).toList(); await addAll(notes); } - Future _checkPermissions(String filepath) async { - // External storage requires permissions - if (!filepath.startsWith('/storage/emulated')) { - if (InfoManager().androidVersion > 33) { - // Android 13 or above - if (!(await Permission.manageExternalStorage.request()).isGranted) { - throw Exception(localizations.error_access_external_storage_required); - } - } else { - // Android 12 or below - if (!(await Permission.storage.request()).isGranted) { - throw Exception(localizations.error_access_external_storage_required); - } - } - } - } - Note get _welcomeNote { final locale = LocaleManager().locale; diff --git a/pubspec.lock b/pubspec.lock index 253005c2..ce2b18b9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -329,14 +329,6 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" - file_picker: - dependency: "direct main" - description: - name: file_picker - sha256: "4e42aacde3b993c5947467ab640882c56947d9d27342a5b6f2895b23956954a6" - url: "https://pub.dev" - source: hosted - version: "6.1.1" fixnum: dependency: transitive description: @@ -781,54 +773,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.1" - permission_handler: - dependency: "direct main" - description: - name: permission_handler - sha256: "74e962b7fad7ff75959161bb2c0ad8fe7f2568ee82621c9c2660b751146bfe44" - url: "https://pub.dev" - source: hosted - version: "11.3.0" - permission_handler_android: - dependency: transitive - description: - name: permission_handler_android - sha256: "758284a0976772f9c744d6384fc5dc4834aa61e3f7aa40492927f244767374eb" - url: "https://pub.dev" - source: hosted - version: "12.0.3" - permission_handler_apple: - dependency: transitive - description: - name: permission_handler_apple - sha256: bdafc6db74253abb63907f4e357302e6bb786ab41465e8635f362ee71fd8707b - url: "https://pub.dev" - source: hosted - version: "9.4.0" - permission_handler_html: - dependency: transitive - description: - name: permission_handler_html - sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d" - url: "https://pub.dev" - source: hosted - version: "0.1.1" - permission_handler_platform_interface: - dependency: transitive - description: - name: permission_handler_platform_interface - sha256: "23dfba8447c076ab5be3dee9ceb66aad345c4a648f0cac292c77b1eb0e800b78" - url: "https://pub.dev" - source: hosted - version: "4.2.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: @@ -1061,6 +1005,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + shared_storage: + dependency: "direct main" + description: + name: shared_storage + sha256: cf20428d06af065311b71e09cbfbbfe431e979a3bf9180001c1952129b7c708f + url: "https://pub.dev" + source: hosted + version: "0.8.1" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 92add686..2cb37dd2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,6 @@ dependencies: device_info_plus: ^9.1.2 dynamic_color: ^1.6.9 equatable: ^2.0.5 - file_picker: ^6.1.1 fleather: ^1.14.1 flutter: sdk: flutter @@ -37,13 +36,13 @@ dependencies: package_info_plus: ^5.0.1 path: ^1.8.3 path_provider: ^2.1.2 - permission_handler: ^11.3.0 quick_actions: ^1.0.7 receive_sharing_intent: ^1.6.7 restart_app: ^1.2.1 riverpod_annotation: ^2.3.4 share_plus: ^7.2.2 shared_preferences: ^2.2.2 + shared_storage: ^0.8.1 simple_icons: ^10.1.3 url_launcher: ^6.2.4 uuid: ^4.3.3