diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 0acc4f3..9c86c9e 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,15 @@ + + + + + + + + + diff --git a/lib/main.dart b/lib/main.dart index dc7b434..eaf04e4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,8 +10,15 @@ import 'package:openlib/ui/search_page.dart'; import 'package:openlib/ui/mylibrary_page.dart'; import 'package:openlib/ui/settings_page.dart'; import 'package:openlib/services/database.dart' show Sqlite, MyLibraryDb; +import 'package:openlib/services/files.dart' + show moveFilesToAndroidInternalStorage; import 'package:openlib/state/state.dart' - show selectedIndexProvider, themeModeProvider, dbProvider; + show + selectedIndexProvider, + themeModeProvider, + openPdfWithExternalAppProvider, + openEpubWithExternalAppProvider, + dbProvider; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -24,12 +31,25 @@ void main() async { Database initDb = await Sqlite.initDb(); MyLibraryDb dataBase = MyLibraryDb(dbInstance: initDb); bool isDarkMode = await dataBase.getPreference('darkMode'); + bool openPdfwithExternalapp = + await dataBase.getPreference('openPdfwithExternalApp'); + bool openEpubwithExternalapp = + await dataBase.getPreference('openEpubwithExternalApp'); + + if (Platform.isAndroid) { + await moveFilesToAndroidInternalStorage(); + } + runApp( ProviderScope( overrides: [ dbProvider.overrideWithValue(dataBase), themeModeProvider.overrideWith( - (ref) => isDarkMode ? ThemeMode.dark : ThemeMode.light) + (ref) => isDarkMode ? ThemeMode.dark : ThemeMode.light), + openPdfWithExternalAppProvider + .overrideWith((ref) => openPdfwithExternalapp), + openEpubWithExternalAppProvider + .overrideWith((ref) => openEpubwithExternalapp) ], child: const MyApp(), ), diff --git a/lib/services/download_file.dart b/lib/services/download_file.dart index 7600666..9ffcdb6 100644 --- a/lib/services/download_file.dart +++ b/lib/services/download_file.dart @@ -1,9 +1,9 @@ -import 'package:path_provider/path_provider.dart'; import 'package:dio/dio.dart'; +import 'files.dart'; Future _getFilePath(String fileName) async { - final path = await getApplicationDocumentsDirectory(); - return '${path.path}/$fileName'; + final path = await getAppDirectoryPath; + return '$path/$fileName'; } List _reorderMirrors(List mirrors) { diff --git a/lib/services/files.dart b/lib/services/files.dart index d37da1e..ede10a6 100644 --- a/lib/services/files.dart +++ b/lib/services/files.dart @@ -1,13 +1,58 @@ import 'dart:io'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:path_provider/path_provider.dart'; +// import 'package:permission_handler/permission_handler.dart'; import 'package:openlib/state/state.dart' show dbProvider, myLibraryProvider; Future get getAppDirectoryPath async { - final directory = await getApplicationDocumentsDirectory(); - return directory.path; + if (Platform.isAndroid) { + final directory = await getExternalStorageDirectory(); + return directory!.path; + // // final path = '/storage/emulated/0/Openlib'; + // print(directory.path); + // // File(directory.path).copySync(newPath); + // return '/storage/emulated/0/Openlib'; + } else { + final directory = await getApplicationDocumentsDirectory(); + return directory.path; + } } +Future moveFilesToAndroidInternalStorage() async { + try { + final directory = await getApplicationDocumentsDirectory(); + final directoryExternal = await getExternalStorageDirectory(); + List files = Directory(directory.path).listSync(); + for (var element in files) { + if ((element.path.contains('pdf')) || element.path.contains('epub')) { + String fileName = element.path.split('/').last; + File file = File(element.path); + file.copySync('${directoryExternal!.path}/$fileName'); + file.deleteSync(); + } + } + } catch (e) { + print(e); + } +} + +// Future getStoragePermissionAndroid() async { +// if (Platform.isAndroid) { +// print("hi"); +// if (await Permission.storage.status.isGranted || +// await Permission.manageExternalStorage.status.isGranted) { +// final storagePermission = await Permission.storage.request().isGranted; +// final manageStoragePermission = +// await Permission.manageExternalStorage.request().isGranted; +// print(storagePermission || manageStoragePermission); +// if (storagePermission || manageStoragePermission) { +// await openAppSettings(); +// print(storagePermission || manageStoragePermission); +// } +// } +// } +// } + Future isFileExists(String filePath) async { return await File(filePath).exists(); } diff --git a/lib/state/state.dart b/lib/state/state.dart index f31ac87..30b36dc 100644 --- a/lib/state/state.dart +++ b/lib/state/state.dart @@ -144,6 +144,9 @@ final getBookPosition = return await ref.read(dbProvider).getBookState(fileName); }); +final openPdfWithExternalAppProvider = StateProvider((ref) => false); +final openEpubWithExternalAppProvider = StateProvider((ref) => false); + final filePathProvider = FutureProvider.family((ref, fileName) async { String path = await getFilePath(fileName); diff --git a/lib/ui/components/file_buttons_widget.dart b/lib/ui/components/file_buttons_widget.dart index a47038d..adb252e 100644 --- a/lib/ui/components/file_buttons_widget.dart +++ b/lib/ui/components/file_buttons_widget.dart @@ -3,7 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:openlib/ui/components/delete_dialog_widget.dart'; import 'package:openlib/ui/epub_viewer.dart' show launchEpubViewer; -import 'package:openlib/ui/pdf_viewer.dart'; +import 'package:openlib/ui/pdf_viewer.dart' show launchPdfViewer; class FileOpenAndDeleteButtons extends ConsumerWidget { final String id; @@ -35,12 +35,8 @@ class FileOpenAndDeleteButtons extends ConsumerWidget { )), onPressed: () async { if (format == 'pdf') { - Navigator.push(context, - MaterialPageRoute(builder: (BuildContext context) { - return PdfView( - fileName: '$id.$format', - ); - })); + await launchPdfViewer( + fileName: '$id.$format', context: context, ref: ref); } else { await launchEpubViewer( fileName: '$id.$format', context: context, ref: ref); diff --git a/lib/ui/epub_viewer.dart b/lib/ui/epub_viewer.dart index 4bef49b..7b52e16 100644 --- a/lib/ui/epub_viewer.dart +++ b/lib/ui/epub_viewer.dart @@ -4,11 +4,17 @@ import 'package:flutter/material.dart'; import 'package:epub_view/epub_view.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:vocsy_epub_viewer/epub_viewer.dart'; +import 'package:open_file/open_file.dart'; -import 'package:openlib/services/files.dart'; +import 'package:openlib/services/files.dart' show getFilePath; import 'package:openlib/ui/components/snack_bar_widget.dart'; import 'package:openlib/state/state.dart' - show filePathProvider, saveEpubState, dbProvider, getBookPosition; + show + filePathProvider, + saveEpubState, + dbProvider, + getBookPosition, + openEpubWithExternalAppProvider; Future launchEpubViewer( {required String fileName, @@ -17,31 +23,36 @@ Future launchEpubViewer( if (Platform.isAndroid || Platform.isIOS) { String path = await getFilePath(fileName); String? epubConfig = await ref.read(dbProvider).getBookState(fileName); + bool openWithExternalApp = ref.watch(openEpubWithExternalAppProvider); - try { - VocsyEpub.setConfig( + if (openWithExternalApp) { + await OpenFile.open(path); + } else { + try { + VocsyEpub.setConfig( + // ignore: use_build_context_synchronously + themeColor: const Color.fromARGB(255, 210, 15, 1), + identifier: "iosBook", + scrollDirection: EpubScrollDirection.HORIZONTAL, + ); + + if ((epubConfig?.isNotEmpty ?? true) && + (epubConfig != null) && + (!(epubConfig.startsWith('epubcfi')))) { + VocsyEpub.open(path, + lastLocation: EpubLocator.fromJson(json.decode(epubConfig))); + } else { + VocsyEpub.open(path); + } + + VocsyEpub.locatorStream.listen((locator) async { + await saveEpubState(fileName, locator, ref); + // convert locator from string to json and save to your database to be retrieved later + }); + } catch (e) { // ignore: use_build_context_synchronously - themeColor: const Color.fromARGB(255, 210, 15, 1), - identifier: "iosBook", - scrollDirection: EpubScrollDirection.HORIZONTAL, - ); - - if ((epubConfig?.isNotEmpty ?? true) && - (epubConfig != null) && - (!(epubConfig.startsWith('epubcfi')))) { - VocsyEpub.open(path, - lastLocation: EpubLocator.fromJson(json.decode(epubConfig))); - } else { - VocsyEpub.open(path); + showSnackBar(context: context, message: 'Unable to open pdf!'); } - - VocsyEpub.locatorStream.listen((locator) async { - await saveEpubState(fileName, locator, ref); - // convert locator from string to json and save to your database to be retrieved later - }); - } catch (e) { - // ignore: use_build_context_synchronously - showSnackBar(context: context, message: 'Unable to open pdf!'); } } else { Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) { diff --git a/lib/ui/pdf_viewer.dart b/lib/ui/pdf_viewer.dart index c2228ba..15317cd 100644 --- a/lib/ui/pdf_viewer.dart +++ b/lib/ui/pdf_viewer.dart @@ -7,10 +7,31 @@ import 'package:openlib/state/state.dart' pdfCurrentPage, totalPdfPage, savePdfState, + openPdfWithExternalAppProvider, getBookPosition; import 'package:url_launcher/url_launcher.dart'; +import 'package:open_file/open_file.dart'; import 'dart:io' show Platform; +import 'package:openlib/services/files.dart' show getFilePath; + +Future launchPdfViewer( + {required String fileName, + required BuildContext context, + required WidgetRef ref}) async { + bool openWithExternalApp = ref.watch(openPdfWithExternalAppProvider); + if (openWithExternalApp) { + String path = await getFilePath(fileName); + await OpenFile.open(path); + } else { + Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) { + return PdfView( + fileName: fileName, + ); + })); + } +} + class PdfView extends ConsumerStatefulWidget { const PdfView({super.key, required this.fileName}); diff --git a/lib/ui/settings_page.dart b/lib/ui/settings_page.dart index 85ea320..67f2fec 100644 --- a/lib/ui/settings_page.dart +++ b/lib/ui/settings_page.dart @@ -3,7 +3,12 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:openlib/ui/components/page_title_widget.dart'; import 'package:openlib/ui/about_page.dart'; -import 'package:openlib/state/state.dart' show themeModeProvider, dbProvider; +import 'package:openlib/state/state.dart' + show + themeModeProvider, + openPdfWithExternalAppProvider, + openEpubWithExternalAppProvider, + dbProvider; class SettingsPage extends ConsumerWidget { const SettingsPage({Key? key}) : super(key: key); @@ -41,6 +46,56 @@ class SettingsPage extends ConsumerWidget { ) ], ), + _PaddedContainer( + children: [ + Text( + "Open PDF with External Reader", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.tertiary, + ), + ), + Switch( + // This bool value toggles the switch. + value: ref.watch(openPdfWithExternalAppProvider), + activeColor: Colors.red, + onChanged: (bool value) { + ref.read(openPdfWithExternalAppProvider.notifier).state = + value; + ref + .read(dbProvider) + .savePreference('openPdfwithExternalApp', value); + }, + ) + ], + ), + _PaddedContainer( + children: [ + Text( + "Open Epub with External Reader", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.tertiary, + ), + ), + Switch( + // This bool value toggles the switch. + value: ref.watch( + openEpubWithExternalAppProvider, + ), + activeColor: Colors.red, + onChanged: (bool value) { + ref.read(openEpubWithExternalAppProvider.notifier).state = + value; + ref + .read(dbProvider) + .savePreference('openEpubwithExternalApp', value); + }, + ) + ], + ), _PaddedContainer( onClick: () { Navigator.push(context, diff --git a/pubspec.lock b/pubspec.lock index 4aca087..af6a313 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -392,6 +392,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + open_file: + dependency: "direct main" + description: + name: open_file + sha256: a5a32d44acb7c899987d0999e1e3cbb0a0f1adebbf41ac813ec6d2d8faa0af20 + url: "https://pub.dev" + source: hosted + version: "3.3.2" path: dependency: transitive description: @@ -456,6 +464,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "63e5216aae014a72fe9579ccd027323395ce7a98271d9defa9d57320d001af81" + url: "https://pub.dev" + source: hosted + version: "10.4.3" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: d74e77a5ecd38649905db0a7d05ef16bed42ff263b9efb73ed794317c5764ec3 + url: "https://pub.dev" + source: hosted + version: "10.3.4" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5" + url: "https://pub.dev" + source: hosted + version: "9.1.4" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: "7c6b1500385dd1d2ca61bb89e2488ca178e274a69144d26bbd65e33eae7c02a9" + url: "https://pub.dev" + source: hosted + version: "3.11.3" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098 + url: "https://pub.dev" + source: hosted + version: "0.1.3" petitparser: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 0811500..d338d87 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -45,6 +45,8 @@ dependencies: sqflite: ^2.3.0 path_provider: ^2.0.15 + permission_handler: ^10.4.3 + open_file: ^3.3.2 flutter_svg: ^2.0.7 google_fonts: ^5.1.0 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 )