Compare commits
36 Commits
v1.0-beta.
...
v1.0.2-bet
Author | SHA1 | Date | |
---|---|---|---|
ccd260d451 | |||
546805be20 | |||
250f0f8b7b | |||
f0d0178a2d | |||
f4f86a1353 | |||
93013fe6bb | |||
1de126104d | |||
e4c8ddaa88 | |||
82798bb749 | |||
16fc051219 | |||
da399604bf | |||
1b87e89470 | |||
0db7794455 | |||
6b31a63e86 | |||
27061a1922 | |||
162ea41196 | |||
010dc1dfdb | |||
b2a1be7a7e | |||
1507656944 | |||
9cc3c3dde5 | |||
e7b6a9d40f | |||
60df4afac2 | |||
bcfb35ab14 | |||
4ac80f08d8 | |||
a9fde1c561 | |||
110d089b8d | |||
4445fc4d84 | |||
11d19b3001 | |||
052c5993b1 | |||
bc36a350ab | |||
9102b0be7b | |||
365d29c19e | |||
52c742e8d0 | |||
d2c992bf80 | |||
39a91b9992 | |||
19df3b4f7b |
11
README.md
@ -3,7 +3,13 @@
|
|||||||
|
|
||||||
#### An Open source app to download and read books from shadow library ([Anna’s Archive](https://annas-archive.org/)).
|
#### An Open source app to download and read books from shadow library ([Anna’s Archive](https://annas-archive.org/)).
|
||||||
|
|
||||||
[](https://flutter.dev/) [](https://opensource.org/licenses/)
|
[](https://flutter.dev/) [](https://opensource.org/licenses/) 
|
||||||
|
|
||||||
|
[<img src="github_releases.png"
|
||||||
|
alt="Download from GitHub"
|
||||||
|
height="80">](https://github.com/dstark5/Openlib/releases) [<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png"
|
||||||
|
alt="Get it on IzzyDroid"
|
||||||
|
height="80">](https://android.izzysoft.de/repo/apk/com.app.openlib)
|
||||||
|
|
||||||
|
|
||||||
## Note
|
## Note
|
||||||
@ -43,6 +49,7 @@
|
|||||||
- Adding Support For Multiple Downloads
|
- Adding Support For Multiple Downloads
|
||||||
|
|
||||||
## Installation and updates
|
## Installation and updates
|
||||||
|
- Download the APK from [ IzzyOnDroid ](https://android.izzysoft.de/repo/apk/com.app.openlib) and install it.
|
||||||
- Download the APK from [GitHub Releases](https://github.com/dstark5/Openlib/releases) and install it.
|
- Download the APK from [GitHub Releases](https://github.com/dstark5/Openlib/releases) and install it.
|
||||||
|
|
||||||
## Building from Source
|
## Building from Source
|
||||||
@ -69,7 +76,7 @@ flutter build
|
|||||||
- The Build Will Be In './build/app/outputs/flutter-apk/app-release.apk'
|
- The Build Will Be In './build/app/outputs/flutter-apk/app-release.apk'
|
||||||
|
|
||||||
## Contribution
|
## Contribution
|
||||||
Whether you have ideas, design changes or even major code changes, help is always welcome. The app gets better and better with each contribution, no matter how big or small! If you'd like to get involved just fork the app make a pull request.
|
Whether you have ideas, design changes or even major code changes, help is always welcome. The app gets better and better with each contribution, no matter how big or small! If you'd like to get involved ,Please read our [CONTRIBUTING.md](https://github.com/dstark5/Openlib/blob/main/CONTRIBUTING.md)
|
||||||
|
|
||||||
## Issues
|
## Issues
|
||||||
|
|
||||||
|
@ -79,6 +79,8 @@ android {
|
|||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||||
// replace with "debug" when running on debug version
|
// replace with "debug" when running on debug version
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
|
minifyEnabled false
|
||||||
|
shrinkResources false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,4 +91,4 @@ flutter {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
}
|
}
|
@ -1,6 +1,22 @@
|
|||||||
<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.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEOS" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29"/>
|
||||||
|
|
||||||
|
<queries>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
</intent>
|
||||||
|
</queries>
|
||||||
<application
|
<application
|
||||||
android:label="Openlib"
|
android:label="Openlib"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
|
15
fastlane/metadata/android/en-US/full_description.txt
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<p>
|
||||||
|
<i>Openlib</i> is an open source app to download and read books from shadow library (<a href='https://annas-archive.org/' target='_blank' rel='nofollow noopener'>Anna’s Archive</a>). The App Has Built In Reader to Read Books.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
As <i>Anna’s Archive</i> doesn't have an API, the app works by sending requests to <i>Anna’s Archive</i> and parses the response to objects. The app extracts the mirrors from the responses, downloads the book and stores it in the application's document directory.
|
||||||
|
</p>
|
||||||
|
<p>Main Features:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Trending Books</li>
|
||||||
|
<li>Download And Read Books With In-Built Viewer</li>
|
||||||
|
<li>Supports Epub And Pdf Formats</li>
|
||||||
|
<li>Open Books With Your Favourite Ebooks Reader</li>
|
||||||
|
<li>Filter Books</li>
|
||||||
|
<li>Sort Books</li>
|
||||||
|
</ul>
|
BIN
fastlane/metadata/android/en-US/images/icon.png
Normal file
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 17 KiB |
1
fastlane/metadata/android/en-US/short_description.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
download and read books from shadow library (Anna’s Archive)
|
BIN
github_releases.png
Normal file
After Width: | Height: | Size: 15 KiB |
112
lib/main.dart
@ -1,29 +1,65 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:io' show Platform;
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:google_nav_bar/google_nav_bar.dart';
|
import 'package:google_nav_bar/google_nav_bar.dart';
|
||||||
import 'package:sqflite/sqflite.dart';
|
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
|
||||||
|
|
||||||
import 'package:openlib/ui/extensions.dart';
|
import 'package:openlib/ui/themes.dart';
|
||||||
import 'package:openlib/ui/trending_page.dart';
|
import 'package:openlib/ui/trending_page.dart';
|
||||||
import 'package:openlib/ui/search_page.dart';
|
import 'package:openlib/ui/search_page.dart';
|
||||||
import 'package:openlib/ui/mylibrary_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/database.dart' show Sqlite, MyLibraryDb;
|
||||||
|
import 'package:openlib/services/files.dart'
|
||||||
|
show moveFilesToAndroidInternalStorage;
|
||||||
import 'package:openlib/state/state.dart'
|
import 'package:openlib/state/state.dart'
|
||||||
show selectedIndexProvider, dbProvider;
|
show
|
||||||
|
selectedIndexProvider,
|
||||||
|
themeModeProvider,
|
||||||
|
openPdfWithExternalAppProvider,
|
||||||
|
openEpubWithExternalAppProvider,
|
||||||
|
dbProvider;
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
Database db = await Sqlite.initDb();
|
|
||||||
runApp(ProviderScope(
|
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
|
||||||
overrides: [dbProvider.overrideWithValue(MyLibraryDb(dbInstance: db))],
|
sqfliteFfiInit();
|
||||||
child: const MyApp()));
|
databaseFactory = databaseFactoryFfi;
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
openPdfWithExternalAppProvider
|
||||||
|
.overrideWith((ref) => openPdfwithExternalapp),
|
||||||
|
openEpubWithExternalAppProvider
|
||||||
|
.overrideWith((ref) => openEpubwithExternalapp)
|
||||||
|
],
|
||||||
|
child: const MyApp(),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends ConsumerWidget {
|
||||||
const MyApp({super.key});
|
const MyApp({super.key});
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
builder: (BuildContext context, Widget? child) {
|
builder: (BuildContext context, Widget? child) {
|
||||||
return MediaQuery(
|
return MediaQuery(
|
||||||
@ -35,32 +71,9 @@ class MyApp extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
title: 'Openlib',
|
title: 'Openlib',
|
||||||
theme: ThemeData(
|
theme: lightTheme,
|
||||||
primaryColor: Colors.white,
|
darkTheme: darkTheme,
|
||||||
colorScheme: ColorScheme.light(
|
themeMode: ref.watch(themeModeProvider),
|
||||||
primary: Colors.white,
|
|
||||||
secondary: '#FB0101'.toColor(),
|
|
||||||
tertiary: Colors.black,
|
|
||||||
tertiaryContainer: '#F2F2F2'.toColor(),
|
|
||||||
),
|
|
||||||
textTheme: const TextTheme(
|
|
||||||
displayLarge: TextStyle(
|
|
||||||
color: Colors.black,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 21,
|
|
||||||
),
|
|
||||||
displayMedium: TextStyle(
|
|
||||||
fontSize: 13,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Colors.black,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
fontFamily: GoogleFonts.nunito().fontFamily,
|
|
||||||
useMaterial3: true,
|
|
||||||
textSelectionTheme: TextSelectionThemeData(
|
|
||||||
selectionColor: '#FB0101'.toColor(),
|
|
||||||
selectionHandleColor: '#FB0101'.toColor())),
|
|
||||||
home: const HomePage(),
|
home: const HomePage(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -77,7 +90,8 @@ class _HomePageState extends ConsumerState<HomePage> {
|
|||||||
static const List<Widget> _widgetOptions = <Widget>[
|
static const List<Widget> _widgetOptions = <Widget>[
|
||||||
TrendingPage(),
|
TrendingPage(),
|
||||||
SearchPage(),
|
SearchPage(),
|
||||||
MyLibraryPage()
|
MyLibraryPage(),
|
||||||
|
SettingsPage()
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -101,14 +115,14 @@ class _HomePageState extends ConsumerState<HomePage> {
|
|||||||
color: Theme.of(context).colorScheme.secondary,
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
),
|
),
|
||||||
tabMargin: const EdgeInsets.fromLTRB(13, 6, 13, 2.5),
|
tabMargin: const EdgeInsets.fromLTRB(13, 6, 13, 2.5),
|
||||||
curve: Curves.easeInOut, // tab animation curves
|
curve: Curves.easeIn,
|
||||||
duration: const Duration(milliseconds: 150),
|
duration: const Duration(milliseconds: 125),
|
||||||
gap: 5,
|
gap: 5,
|
||||||
color: const Color.fromARGB(255, 255, 255, 255),
|
color: const Color.fromARGB(255, 255, 255, 255),
|
||||||
activeColor: const Color.fromARGB(255, 255, 255, 255),
|
activeColor: const Color.fromARGB(255, 255, 255, 255),
|
||||||
iconSize: 21, // tab button icon size
|
iconSize: 19, // tab button icon size
|
||||||
tabBackgroundColor: Theme.of(context).colorScheme.secondary,
|
tabBackgroundColor: Theme.of(context).colorScheme.secondary,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 6.5),
|
padding: const EdgeInsets.symmetric(horizontal: 13, vertical: 6.5),
|
||||||
tabs: const [
|
tabs: const [
|
||||||
GButton(
|
GButton(
|
||||||
icon: Icons.trending_up,
|
icon: Icons.trending_up,
|
||||||
@ -117,7 +131,7 @@ class _HomePageState extends ConsumerState<HomePage> {
|
|||||||
textStyle: TextStyle(
|
textStyle: TextStyle(
|
||||||
fontWeight: FontWeight.w900,
|
fontWeight: FontWeight.w900,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 13,
|
fontSize: 11,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
GButton(
|
GButton(
|
||||||
@ -127,7 +141,7 @@ class _HomePageState extends ConsumerState<HomePage> {
|
|||||||
textStyle: TextStyle(
|
textStyle: TextStyle(
|
||||||
fontWeight: FontWeight.w900,
|
fontWeight: FontWeight.w900,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 13,
|
fontSize: 11,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
GButton(
|
GButton(
|
||||||
@ -137,7 +151,17 @@ class _HomePageState extends ConsumerState<HomePage> {
|
|||||||
textStyle: TextStyle(
|
textStyle: TextStyle(
|
||||||
fontWeight: FontWeight.w900,
|
fontWeight: FontWeight.w900,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 13,
|
fontSize: 11,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GButton(
|
||||||
|
icon: Icons.build,
|
||||||
|
text: 'Settings',
|
||||||
|
iconColor: Colors.white,
|
||||||
|
textStyle: TextStyle(
|
||||||
|
fontWeight: FontWeight.w900,
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 11,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -127,7 +127,7 @@ class AnnasArchieve {
|
|||||||
String? link = pTag?.querySelector('a')?.attributes['href'];
|
String? link = pTag?.querySelector('a')?.attributes['href'];
|
||||||
return link;
|
return link;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
// print(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,14 +135,19 @@ class AnnasArchieve {
|
|||||||
Future<BookInfoData?> _bookInfoParser(resData, url) async {
|
Future<BookInfoData?> _bookInfoParser(resData, url) async {
|
||||||
var document = parse(resData.toString());
|
var document = parse(resData.toString());
|
||||||
var main = document.querySelector('main[class="main"]');
|
var main = document.querySelector('main[class="main"]');
|
||||||
var ul = main?.querySelector('ul[class="mb-4"]');
|
var ul = main?.querySelectorAll('ul[class="mb-4"]');
|
||||||
|
|
||||||
List<String> mirrors = [];
|
List<String> mirrors = [];
|
||||||
|
|
||||||
if (ul != null) {
|
if (ul != null) {
|
||||||
var a = ul.querySelectorAll('a');
|
var anchorTags = [];
|
||||||
|
if (ul.length == 2) {
|
||||||
|
anchorTags = ul[1].querySelectorAll('a');
|
||||||
|
} else {
|
||||||
|
anchorTags = ul[0].querySelectorAll('a');
|
||||||
|
}
|
||||||
|
|
||||||
for (var element in a) {
|
for (var element in anchorTags) {
|
||||||
if (element.attributes['href']!.startsWith('https://')) {
|
if (element.attributes['href']!.startsWith('https://')) {
|
||||||
if (element.attributes['href'] != null) {
|
if (element.attributes['href'] != null) {
|
||||||
mirrors.add(element.attributes['href']!);
|
mirrors.add(element.attributes['href']!);
|
||||||
|
@ -1,15 +1,40 @@
|
|||||||
|
import 'dart:io';
|
||||||
import 'package:sqflite/sqflite.dart';
|
import 'package:sqflite/sqflite.dart';
|
||||||
|
|
||||||
class Sqlite {
|
class Sqlite {
|
||||||
static Future<Database> initDb() async {
|
static Future<Database> initDb() async {
|
||||||
var databasesPath = await getDatabasesPath();
|
var databasesPath = await getDatabasesPath();
|
||||||
String path = '$databasesPath/mylibrary.db';
|
String path = '$databasesPath/mylibrary.db';
|
||||||
|
bool isMobile = Platform.isAndroid || Platform.isIOS;
|
||||||
|
|
||||||
Database dbInstance = await openDatabase(path, version: 1,
|
Database dbInstance = await openDatabase(
|
||||||
onCreate: (Database db, int version) async {
|
path,
|
||||||
await db.execute(
|
version: 3,
|
||||||
'CREATE TABLE mybooks (id TEXT PRIMARY KEY, title TEXT,author TEXT,thumbnail TEXT,link TEXT,publisher TEXT,info TEXT,format TEXT,description TEXT)');
|
onCreate: (Database db, int version) async {
|
||||||
});
|
await db.execute(
|
||||||
|
'CREATE TABLE mybooks (id TEXT PRIMARY KEY, title TEXT,author TEXT,thumbnail TEXT,link TEXT,publisher TEXT,info TEXT,format TEXT,description TEXT)');
|
||||||
|
await db.execute(
|
||||||
|
'CREATE TABLE preferences (name TEXT PRIMARY KEY,value BOOLEAN)');
|
||||||
|
if (isMobile) {
|
||||||
|
await db.execute(
|
||||||
|
'CREATE TABLE bookposition (fileName TEXT PRIMARY KEY,position TEXT)');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onUpgrade: (db, oldVersion, newVersion) async {
|
||||||
|
List<dynamic> isTableExist = await db.query('sqlite_master',
|
||||||
|
where: 'name = ?', whereArgs: ['bookposition']);
|
||||||
|
List<dynamic> isPreferenceTableExist = await db.query('sqlite_master',
|
||||||
|
where: 'name = ?', whereArgs: ['preferences']);
|
||||||
|
if (isPreferenceTableExist.isEmpty) {
|
||||||
|
await db.execute(
|
||||||
|
'CREATE TABLE preferences (name TEXT PRIMARY KEY,value BOOLEAN)');
|
||||||
|
}
|
||||||
|
if (isMobile && isTableExist.isEmpty) {
|
||||||
|
await db.execute(
|
||||||
|
'CREATE TABLE bookposition (fileName TEXT PRIMARY KEY,position TEXT)');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
return dbInstance;
|
return dbInstance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,4 +143,55 @@ class MyLibraryDb {
|
|||||||
});
|
});
|
||||||
return myBookList.reversed.toList();
|
return myBookList.reversed.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> saveBookState(String fileName, String position) async {
|
||||||
|
await dbInstance.insert(
|
||||||
|
'bookposition',
|
||||||
|
{'fileName': fileName, 'position': position},
|
||||||
|
conflictAlgorithm: ConflictAlgorithm.replace,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteBookState(String fileName) async {
|
||||||
|
await dbInstance.delete(
|
||||||
|
'bookposition',
|
||||||
|
where: 'fileName = ?',
|
||||||
|
whereArgs: [fileName],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String?> getBookState(String fileName) async {
|
||||||
|
List<Map<String, dynamic>> data = await dbInstance
|
||||||
|
.query('bookposition', where: 'fileName = ?', whereArgs: [fileName]);
|
||||||
|
List<dynamic> dataList = List.generate(data.length, (i) {
|
||||||
|
return {'fileName': data[i]['fileName'], 'position': data[i]['position']};
|
||||||
|
});
|
||||||
|
if (dataList.isNotEmpty) {
|
||||||
|
return dataList[0]['position'];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> savePreference(String name, bool value) async {
|
||||||
|
int boolInt = value ? 1 : 0;
|
||||||
|
await dbInstance.insert(
|
||||||
|
'preferences',
|
||||||
|
{'name': name, 'value': boolInt},
|
||||||
|
conflictAlgorithm: ConflictAlgorithm.replace,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> getPreference(String name) async {
|
||||||
|
List<Map<String, dynamic>> data = await dbInstance
|
||||||
|
.query('preferences', where: 'name = ?', whereArgs: [name]);
|
||||||
|
List<dynamic> dataList = List.generate(data.length, (i) {
|
||||||
|
return {'name': data[i]['name'], 'value': data[i]['value']};
|
||||||
|
});
|
||||||
|
if (dataList.isNotEmpty) {
|
||||||
|
return dataList[0]['value'] == 0 ? false : true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import 'package:path_provider/path_provider.dart';
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
import 'files.dart';
|
||||||
|
|
||||||
Future<String> _getFilePath(String fileName) async {
|
Future<String> _getFilePath(String fileName) async {
|
||||||
final path = await getApplicationDocumentsDirectory();
|
final path = await getAppDirectoryPath;
|
||||||
return '${path.path}/$fileName';
|
return '$path/$fileName';
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> _reorderMirrors(List<String> mirrors) {
|
List<String> _reorderMirrors(List<String> mirrors) {
|
||||||
@ -14,7 +14,8 @@ List<String> _reorderMirrors(List<String> mirrors) {
|
|||||||
if (element.contains('ipfs') == true) {
|
if (element.contains('ipfs') == true) {
|
||||||
ipfsMirrors.add(element);
|
ipfsMirrors.add(element);
|
||||||
} else {
|
} else {
|
||||||
if (element.startsWith('https://annas-archive.gs') != true) {
|
if (element.startsWith('https://annas-archive.gs') != true &&
|
||||||
|
element.startsWith('https://1lib.sk') != true) {
|
||||||
httpsMirrors.add(element);
|
httpsMirrors.add(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,32 @@ import 'package:path_provider/path_provider.dart';
|
|||||||
import 'package:openlib/state/state.dart' show dbProvider, myLibraryProvider;
|
import 'package:openlib/state/state.dart' show dbProvider, myLibraryProvider;
|
||||||
|
|
||||||
Future<String> get getAppDirectoryPath async {
|
Future<String> get getAppDirectoryPath async {
|
||||||
final directory = await getApplicationDocumentsDirectory();
|
if (Platform.isAndroid) {
|
||||||
return directory.path;
|
final directory = await getExternalStorageDirectory();
|
||||||
|
return directory!.path;
|
||||||
|
} else {
|
||||||
|
final directory = await getApplicationDocumentsDirectory();
|
||||||
|
return directory.path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> moveFilesToAndroidInternalStorage() async {
|
||||||
|
try {
|
||||||
|
final directory = await getApplicationDocumentsDirectory();
|
||||||
|
final directoryExternal = await getExternalStorageDirectory();
|
||||||
|
List<FileSystemEntity> 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) {
|
||||||
|
// ignore: avoid_print
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> isFileExists(String filePath) async {
|
Future<bool> isFileExists(String filePath) async {
|
||||||
@ -35,9 +59,11 @@ Future<void> deleteFileWithDbData(
|
|||||||
String appDirPath = await getAppDirectoryPath;
|
String appDirPath = await getAppDirectoryPath;
|
||||||
await deleteFile('$appDirPath/$fileName');
|
await deleteFile('$appDirPath/$fileName');
|
||||||
await ref.read(dbProvider).delete(md5);
|
await ref.read(dbProvider).delete(md5);
|
||||||
|
await ref.read(dbProvider).deleteBookState(fileName);
|
||||||
// ignore: unused_result
|
// ignore: unused_result
|
||||||
ref.refresh(myLibraryProvider);
|
ref.refresh(myLibraryProvider);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
// print(e);
|
||||||
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:openlib/services/database.dart';
|
import 'package:openlib/services/database.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
@ -31,6 +32,8 @@ Map<String, String> sortValues = {
|
|||||||
|
|
||||||
final selectedIndexProvider = StateProvider<int>((ref) => 0);
|
final selectedIndexProvider = StateProvider<int>((ref) => 0);
|
||||||
|
|
||||||
|
final themeModeProvider = StateProvider<ThemeMode>((ref) => ThemeMode.light);
|
||||||
|
|
||||||
final selectedTypeState = StateProvider<String>((ref) => "All");
|
final selectedTypeState = StateProvider<String>((ref) => "All");
|
||||||
|
|
||||||
final getTypeValue = Provider.autoDispose<String>((ref) {
|
final getTypeValue = Provider.autoDispose<String>((ref) {
|
||||||
@ -125,6 +128,25 @@ final deleteFileFromMyLib =
|
|||||||
final pdfCurrentPage = StateProvider.autoDispose<int>((ref) => 0);
|
final pdfCurrentPage = StateProvider.autoDispose<int>((ref) => 0);
|
||||||
final totalPdfPage = StateProvider.autoDispose<int>((ref) => 0);
|
final totalPdfPage = StateProvider.autoDispose<int>((ref) => 0);
|
||||||
|
|
||||||
|
Future<void> savePdfState(String fileName, WidgetRef ref) async {
|
||||||
|
String position = ref.watch(pdfCurrentPage).toString();
|
||||||
|
await ref.watch(dbProvider).saveBookState(fileName, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> saveEpubState(
|
||||||
|
String fileName, String? position, WidgetRef ref) async {
|
||||||
|
String pos = position ?? '';
|
||||||
|
await ref.watch(dbProvider).saveBookState(fileName, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
final getBookPosition =
|
||||||
|
FutureProvider.family.autoDispose<String?, String>((ref, fileName) async {
|
||||||
|
return await ref.read(dbProvider).getBookState(fileName);
|
||||||
|
});
|
||||||
|
|
||||||
|
final openPdfWithExternalAppProvider = StateProvider<bool>((ref) => false);
|
||||||
|
final openEpubWithExternalAppProvider = StateProvider<bool>((ref) => false);
|
||||||
|
|
||||||
final filePathProvider =
|
final filePathProvider =
|
||||||
FutureProvider.family<String, String>((ref, fileName) async {
|
FutureProvider.family<String, String>((ref, fileName) async {
|
||||||
String path = await getFilePath(fileName);
|
String path = await getFilePath(fileName);
|
||||||
|
131
lib/ui/about_page.dart
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
import 'package:openlib/ui/components/snack_bar_widget.dart';
|
||||||
|
import 'package:openlib/ui/components/page_title_widget.dart';
|
||||||
|
|
||||||
|
class AboutPage extends StatelessWidget {
|
||||||
|
const AboutPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||||
|
title: const Text("Openlib"),
|
||||||
|
titleTextStyle: Theme.of(context).textTheme.displayLarge,
|
||||||
|
),
|
||||||
|
body: const SingleChildScrollView(
|
||||||
|
physics: BouncingScrollPhysics(),
|
||||||
|
scrollDirection: Axis.vertical,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(left: 5, right: 5, top: 10),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
TitleText("About"),
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsets.only(left: 7, right: 7, top: 13, bottom: 10),
|
||||||
|
child: Text(
|
||||||
|
"An Open source app to download and read books from shadow library (Anna`s Archive)",
|
||||||
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 7, right: 7, top: 10),
|
||||||
|
child: Text(
|
||||||
|
"Version",
|
||||||
|
style: TextStyle(fontSize: 19, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 7, right: 7, top: 5),
|
||||||
|
child: Text(
|
||||||
|
"1.0.2",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.grey),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 7, right: 7, top: 15),
|
||||||
|
child: Text(
|
||||||
|
"Github",
|
||||||
|
style: TextStyle(fontSize: 19, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_UrlText(
|
||||||
|
text: 'Open Github Page',
|
||||||
|
url: 'https://github.com/dstark5/Openlib',
|
||||||
|
),
|
||||||
|
_UrlText(
|
||||||
|
text: 'Contribute To Openlib',
|
||||||
|
url:
|
||||||
|
'https://github.com/dstark5/Openlib/blob/main/CONTRIBUTING.md'),
|
||||||
|
_UrlText(
|
||||||
|
text: 'Report An Issue',
|
||||||
|
url: 'https://github.com/dstark5/Openlib/issues'),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 7, right: 7, top: 15),
|
||||||
|
child: Text(
|
||||||
|
"Licence",
|
||||||
|
style: TextStyle(fontSize: 19, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_UrlText(
|
||||||
|
text: "GPL v3.0 license",
|
||||||
|
url: 'https://www.gnu.org/licenses/gpl-3.0.en.html'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _UrlText extends StatelessWidget {
|
||||||
|
const _UrlText({Key? key, required this.text, required this.url})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
final String url;
|
||||||
|
final String text;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 7, right: 7, top: 5),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () async {
|
||||||
|
final Uri uri = Uri.parse(url);
|
||||||
|
if (!await launchUrl(uri, mode: LaunchMode.externalApplication)) {
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
|
showSnackBar(context: context, message: 'Could not launch $uri');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
text,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.blueAccent,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
const Icon(
|
||||||
|
Icons.launch,
|
||||||
|
size: 17,
|
||||||
|
color: Colors.blueAccent,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -200,7 +200,7 @@ class _ShowDialog extends ConsumerWidget {
|
|||||||
height: 255,
|
height: 255,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(15),
|
borderRadius: BorderRadius.circular(15),
|
||||||
color: Colors.white,
|
color: Theme.of(context).colorScheme.tertiaryContainer,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
|
padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
@ -208,14 +208,14 @@ class _ShowDialog extends ConsumerWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Text(
|
child: Text(
|
||||||
"Downloading Book",
|
"Downloading Book",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 19,
|
fontSize: 19,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Color.fromARGB(255, 54, 54, 54),
|
color: Theme.of(context).colorScheme.tertiary,
|
||||||
decoration: TextDecoration.none),
|
decoration: TextDecoration.none),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -223,10 +223,13 @@ class _ShowDialog extends ConsumerWidget {
|
|||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Text(
|
child: Text(
|
||||||
title,
|
title,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Colors.black54,
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.tertiary
|
||||||
|
.withAlpha(170),
|
||||||
decoration: TextDecoration.none),
|
decoration: TextDecoration.none),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
@ -259,7 +262,10 @@ class _ShowDialog extends ConsumerWidget {
|
|||||||
borderRadius: const BorderRadius.all(Radius.circular(50)),
|
borderRadius: const BorderRadius.all(Radius.circular(50)),
|
||||||
child: LinearProgressIndicator(
|
child: LinearProgressIndicator(
|
||||||
color: Theme.of(context).colorScheme.secondary,
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
backgroundColor: Colors.black26,
|
backgroundColor: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.tertiary
|
||||||
|
.withAlpha(50),
|
||||||
value: downloadProgress,
|
value: downloadProgress,
|
||||||
minHeight: 4,
|
minHeight: 4,
|
||||||
),
|
),
|
||||||
|
@ -81,10 +81,10 @@ class BookInfoCard extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Colors.black,
|
color: Theme.of(context).colorScheme.tertiary,
|
||||||
),
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
@ -94,7 +94,8 @@ class BookInfoCard extends StatelessWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: "#4D4D4D".toColor(),
|
color:
|
||||||
|
Theme.of(context).textTheme.headlineMedium?.color,
|
||||||
),
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
@ -104,7 +105,7 @@ class BookInfoCard extends StatelessWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: "#7B7B7B".toColor(),
|
color: Theme.of(context).textTheme.headlineSmall?.color,
|
||||||
),
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:openlib/ui/extensions.dart';
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
|
||||||
class BookInfoWidget extends StatelessWidget {
|
class BookInfoWidget extends StatelessWidget {
|
||||||
@ -11,6 +10,9 @@ class BookInfoWidget extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
String description = data.description.toString().length < 3
|
||||||
|
? "No Description available"
|
||||||
|
: data.description.toString();
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
physics: const BouncingScrollPhysics(),
|
physics: const BouncingScrollPhysics(),
|
||||||
scrollDirection: Axis.vertical,
|
scrollDirection: Axis.vertical,
|
||||||
@ -65,28 +67,32 @@ class BookInfoWidget extends StatelessWidget {
|
|||||||
text: data.title,
|
text: data.title,
|
||||||
fontSize: 19,
|
fontSize: 19,
|
||||||
topPadding: 15,
|
topPadding: 15,
|
||||||
color: Colors.black,
|
color: Theme.of(context).colorScheme.tertiary,
|
||||||
maxLines: 7,
|
maxLines: 7,
|
||||||
),
|
),
|
||||||
_TopPaddedText(
|
_TopPaddedText(
|
||||||
text: data.publisher ?? "unknown",
|
text: data.publisher ?? "unknown",
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
topPadding: 7,
|
topPadding: 7,
|
||||||
color: "#595E60".toColor(),
|
color: Theme.of(context).textTheme.headlineMedium!.color!,
|
||||||
maxLines: 4,
|
maxLines: 4,
|
||||||
),
|
),
|
||||||
_TopPaddedText(
|
_TopPaddedText(
|
||||||
text: data.author ?? "unknown",
|
text: data.author ?? "unknown",
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
topPadding: 7,
|
topPadding: 7,
|
||||||
color: "#7F7F7F".toColor(),
|
color: Theme.of(context).textTheme.headlineSmall!.color!,
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
),
|
),
|
||||||
_TopPaddedText(
|
_TopPaddedText(
|
||||||
text: data.info ?? "",
|
text: data.info ?? "",
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
topPadding: 9,
|
topPadding: 9,
|
||||||
color: "#A9A8A2".toColor(),
|
color: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.headlineSmall!
|
||||||
|
.color!
|
||||||
|
.withAlpha(155),
|
||||||
maxLines: 4,
|
maxLines: 4,
|
||||||
),
|
),
|
||||||
// child slot of page
|
// child slot of page
|
||||||
@ -108,11 +114,12 @@ class BookInfoWidget extends StatelessWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 7, bottom: 10),
|
padding: const EdgeInsets.only(top: 7, bottom: 10),
|
||||||
child: Text(
|
child: Text(
|
||||||
data.description ?? "",
|
description,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: "#6B6B6B".toColor(),
|
color:
|
||||||
|
Theme.of(context).colorScheme.tertiary.withAlpha(150),
|
||||||
letterSpacing: 1.5,
|
letterSpacing: 1.5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -26,7 +26,7 @@ class ShowDeleteDialog extends ConsumerWidget {
|
|||||||
height: 219,
|
height: 219,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(15),
|
borderRadius: BorderRadius.circular(15),
|
||||||
color: Colors.white,
|
color: Theme.of(context).colorScheme.tertiaryContainer,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.fromLTRB(20, 50, 20, 20),
|
padding: const EdgeInsets.fromLTRB(20, 50, 20, 20),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
@ -34,25 +34,28 @@ class ShowDeleteDialog extends ConsumerWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Text(
|
child: Text(
|
||||||
"Delete Book",
|
"Delete Book",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 19,
|
fontSize: 19,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Color.fromARGB(255, 54, 54, 54),
|
color: Theme.of(context).colorScheme.tertiary,
|
||||||
decoration: TextDecoration.none),
|
decoration: TextDecoration.none),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Text(
|
child: Text(
|
||||||
"This is permanent and cannot be undone",
|
"This is permanent and cannot be undone",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Colors.black54,
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.tertiary
|
||||||
|
.withAlpha(170),
|
||||||
decoration: TextDecoration.none),
|
decoration: TextDecoration.none),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
@ -88,14 +91,14 @@ class ShowDeleteDialog extends ConsumerWidget {
|
|||||||
|
|
||||||
onDelete();
|
onDelete();
|
||||||
},
|
},
|
||||||
child: const Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.all(5.0),
|
padding: const EdgeInsets.all(5.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Delete',
|
'Delete',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Colors.black,
|
color: Theme.of(context).colorScheme.tertiary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import 'package:openlib/ui/components/delete_dialog_widget.dart';
|
import 'package:openlib/ui/components/delete_dialog_widget.dart';
|
||||||
import 'package:openlib/ui/epub_viewer.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 StatelessWidget {
|
class FileOpenAndDeleteButtons extends ConsumerWidget {
|
||||||
final String id;
|
final String id;
|
||||||
final String format;
|
final String format;
|
||||||
final Function onDelete;
|
final Function onDelete;
|
||||||
@ -17,7 +18,7 @@ class FileOpenAndDeleteButtons extends StatelessWidget {
|
|||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(top: 21, bottom: 21),
|
padding: const EdgeInsets.only(top: 21, bottom: 21),
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -27,30 +28,19 @@ class FileOpenAndDeleteButtons extends StatelessWidget {
|
|||||||
TextButton(
|
TextButton(
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
backgroundColor: Theme.of(context).colorScheme.secondary,
|
backgroundColor: Theme.of(context).colorScheme.secondary,
|
||||||
textStyle: const TextStyle(
|
textStyle: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontWeight: FontWeight.w900,
|
fontWeight: FontWeight.w900,
|
||||||
color: Colors.white,
|
color: Theme.of(context).colorScheme.primary,
|
||||||
)),
|
)),
|
||||||
onPressed: () => {
|
onPressed: () async {
|
||||||
if (format == 'pdf')
|
if (format == 'pdf') {
|
||||||
{
|
await launchPdfViewer(
|
||||||
Navigator.push(context,
|
fileName: '$id.$format', context: context, ref: ref);
|
||||||
MaterialPageRoute(builder: (BuildContext context) {
|
} else {
|
||||||
return PdfView(
|
await launchEpubViewer(
|
||||||
fileName: '$id.$format',
|
fileName: '$id.$format', context: context, ref: ref);
|
||||||
);
|
}
|
||||||
}))
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Navigator.push(context,
|
|
||||||
MaterialPageRoute(builder: (BuildContext context) {
|
|
||||||
return EpubViewerWidget(
|
|
||||||
fileName: '$id.$format',
|
|
||||||
);
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
child: const Padding(
|
child: const Padding(
|
||||||
padding: EdgeInsets.fromLTRB(17, 8, 17, 8),
|
padding: EdgeInsets.fromLTRB(17, 8, 17, 8),
|
||||||
@ -82,14 +72,14 @@ class FileOpenAndDeleteButtons extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: const Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.all(5.3),
|
padding: const EdgeInsets.all(5.3),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Delete',
|
'Delete',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Colors.black,
|
color: Theme.of(context).colorScheme.tertiary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,9 +1,67 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:convert';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:epub_view/epub_view.dart';
|
import 'package:epub_view/epub_view.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.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/state/state.dart' show filePathProvider;
|
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,
|
||||||
|
openEpubWithExternalAppProvider;
|
||||||
|
|
||||||
|
Future<void> launchEpubViewer(
|
||||||
|
{required String fileName,
|
||||||
|
required BuildContext context,
|
||||||
|
required WidgetRef ref}) async {
|
||||||
|
if (Platform.isAndroid || Platform.isIOS) {
|
||||||
|
String path = await getFilePath(fileName);
|
||||||
|
String? epubConfig = await ref.read(dbProvider).getBookState(fileName);
|
||||||
|
bool openWithExternalApp = ref.watch(openEpubWithExternalAppProvider);
|
||||||
|
|
||||||
|
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
|
||||||
|
showSnackBar(context: context, message: 'Unable to open pdf!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
|
||||||
|
return EpubViewerWidget(
|
||||||
|
fileName: fileName,
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class EpubViewerWidget extends ConsumerStatefulWidget {
|
class EpubViewerWidget extends ConsumerStatefulWidget {
|
||||||
const EpubViewerWidget({super.key, required this.fileName});
|
const EpubViewerWidget({super.key, required this.fileName});
|
||||||
@ -19,7 +77,7 @@ class _EpubViewState extends ConsumerState<EpubViewerWidget> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final filePath = ref.watch(filePathProvider(widget.fileName));
|
final filePath = ref.watch(filePathProvider(widget.fileName));
|
||||||
return filePath.when(data: (data) {
|
return filePath.when(data: (data) {
|
||||||
return EpubViewer(filePath: data);
|
return EpubViewer(filePath: data, fileName: widget.fileName);
|
||||||
}, error: (error, stack) {
|
}, error: (error, stack) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
@ -37,30 +95,34 @@ class _EpubViewState extends ConsumerState<EpubViewerWidget> {
|
|||||||
titleTextStyle: Theme.of(context).textTheme.displayLarge,
|
titleTextStyle: Theme.of(context).textTheme.displayLarge,
|
||||||
),
|
),
|
||||||
body: Center(
|
body: Center(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 25,
|
width: 25,
|
||||||
height: 25,
|
height: 25,
|
||||||
child: CircularProgressIndicator(
|
child: CircularProgressIndicator(
|
||||||
color: Theme.of(context).colorScheme.secondary,
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EpubViewer extends StatefulWidget {
|
class EpubViewer extends ConsumerStatefulWidget {
|
||||||
const EpubViewer({Key? key, required this.filePath}) : super(key: key);
|
const EpubViewer({Key? key, required this.filePath, required this.fileName})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
final String filePath;
|
final String filePath;
|
||||||
|
final String fileName;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// ignore: library_private_types_in_public_api
|
// ignore: library_private_types_in_public_api
|
||||||
_EpubViewerState createState() => _EpubViewerState();
|
_EpubViewerState createState() => _EpubViewerState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EpubViewerState extends State<EpubViewer> {
|
class _EpubViewerState extends ConsumerState<EpubViewer> {
|
||||||
late EpubController _epubReaderController;
|
late EpubController _epubReaderController;
|
||||||
|
String? epubConf;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -70,6 +132,14 @@ class _EpubViewerState extends State<EpubViewer> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void deactivate() {
|
||||||
|
if (Platform.isAndroid || Platform.isIOS) {
|
||||||
|
saveEpubState(widget.fileName, epubConf, ref);
|
||||||
|
}
|
||||||
|
super.deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_epubReaderController.dispose();
|
_epubReaderController.dispose();
|
||||||
@ -78,6 +148,7 @@ class _EpubViewerState extends State<EpubViewer> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final position = ref.watch(getBookPosition(widget.fileName));
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||||
@ -87,14 +158,48 @@ class _EpubViewerState extends State<EpubViewer> {
|
|||||||
endDrawer: Drawer(
|
endDrawer: Drawer(
|
||||||
child: EpubViewTableOfContents(controller: _epubReaderController),
|
child: EpubViewTableOfContents(controller: _epubReaderController),
|
||||||
),
|
),
|
||||||
body: EpubView(
|
body: position.when(
|
||||||
onDocumentLoaded: (doc) {},
|
data: (data) {
|
||||||
onChapterChanged: (value) {},
|
return EpubView(
|
||||||
builders: EpubViewBuilders<DefaultBuilderOptions>(
|
onDocumentLoaded: (doc) {
|
||||||
options: const DefaultBuilderOptions(),
|
Future.delayed(const Duration(milliseconds: 20), () {
|
||||||
chapterDividerBuilder: (_) => const Divider(),
|
String pos = data ?? "";
|
||||||
),
|
_epubReaderController.gotoEpubCfi(pos);
|
||||||
controller: _epubReaderController,
|
});
|
||||||
|
},
|
||||||
|
onChapterChanged: (value) {
|
||||||
|
epubConf = _epubReaderController.generateEpubCfi();
|
||||||
|
},
|
||||||
|
builders: EpubViewBuilders<DefaultBuilderOptions>(
|
||||||
|
options: const DefaultBuilderOptions(),
|
||||||
|
chapterDividerBuilder: (_) => const Divider(),
|
||||||
|
),
|
||||||
|
controller: _epubReaderController,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
error: (err, _) {
|
||||||
|
return EpubView(
|
||||||
|
onChapterChanged: (value) {
|
||||||
|
epubConf = _epubReaderController.generateEpubCfi();
|
||||||
|
},
|
||||||
|
builders: EpubViewBuilders<DefaultBuilderOptions>(
|
||||||
|
options: const DefaultBuilderOptions(),
|
||||||
|
chapterDividerBuilder: (_) => const Divider(),
|
||||||
|
),
|
||||||
|
controller: _epubReaderController,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading: () {
|
||||||
|
return Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 25,
|
||||||
|
height: 25,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ class MyLibraryPage extends ConsumerWidget {
|
|||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(left: 5, right: 5, top: 10),
|
padding: const EdgeInsets.only(left: 5, right: 5, top: 10),
|
||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
|
physics: const BouncingScrollPhysics(),
|
||||||
slivers: <Widget>[
|
slivers: <Widget>[
|
||||||
const SliverToBoxAdapter(
|
const SliverToBoxAdapter(
|
||||||
child: TitleText("My Library"),
|
child: TitleText("My Library"),
|
||||||
|
@ -2,7 +2,35 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_pdfview/flutter_pdfview.dart';
|
import 'package:flutter_pdfview/flutter_pdfview.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:openlib/state/state.dart'
|
import 'package:openlib/state/state.dart'
|
||||||
show filePathProvider, pdfCurrentPage, totalPdfPage;
|
show
|
||||||
|
filePathProvider,
|
||||||
|
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<void> 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 {
|
class PdfView extends ConsumerStatefulWidget {
|
||||||
const PdfView({super.key, required this.fileName});
|
const PdfView({super.key, required this.fileName});
|
||||||
@ -18,7 +46,7 @@ class _PdfViewState extends ConsumerState<PdfView> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final filePath = ref.watch(filePathProvider(widget.fileName));
|
final filePath = ref.watch(filePathProvider(widget.fileName));
|
||||||
return filePath.when(data: (data) {
|
return filePath.when(data: (data) {
|
||||||
return PdfViewer(filePath: data);
|
return PdfViewer(filePath: data, fileName: widget.fileName);
|
||||||
}, error: (error, stack) {
|
}, error: (error, stack) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
@ -49,9 +77,11 @@ class _PdfViewState extends ConsumerState<PdfView> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PdfViewer extends ConsumerStatefulWidget {
|
class PdfViewer extends ConsumerStatefulWidget {
|
||||||
const PdfViewer({Key? key, required this.filePath}) : super(key: key);
|
const PdfViewer({Key? key, required this.filePath, required this.fileName})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
final String filePath;
|
final String filePath;
|
||||||
|
final String fileName;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ConsumerState<ConsumerStatefulWidget> createState() => _PdfViewerState();
|
ConsumerState<ConsumerStatefulWidget> createState() => _PdfViewerState();
|
||||||
@ -60,8 +90,44 @@ class PdfViewer extends ConsumerStatefulWidget {
|
|||||||
class _PdfViewerState extends ConsumerState<PdfViewer> {
|
class _PdfViewerState extends ConsumerState<PdfViewer> {
|
||||||
late PDFViewController controller;
|
late PDFViewController controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void deactivate() {
|
||||||
|
if (Platform.isAndroid || Platform.isIOS) {
|
||||||
|
savePdfState(widget.fileName, ref);
|
||||||
|
}
|
||||||
|
super.deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _openPdfWithDefaultViewer(String fileName) async {
|
||||||
|
debugPrint("Opening : $fileName");
|
||||||
|
final fileUrl = Uri.parse(fileName);
|
||||||
|
if (await canLaunchUrl(fileUrl)) {
|
||||||
|
await launchUrl(fileUrl);
|
||||||
|
} else {
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text(
|
||||||
|
'Could not open the PDF',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
bool isMobile = Platform.isAndroid || Platform.isIOS;
|
||||||
final currentPage = ref.watch(pdfCurrentPage);
|
final currentPage = ref.watch(pdfCurrentPage);
|
||||||
final totalPages = ref.watch(totalPdfPage);
|
final totalPages = ref.watch(totalPdfPage);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@ -69,51 +135,109 @@ class _PdfViewerState extends ConsumerState<PdfViewer> {
|
|||||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||||
title: const Text("Openlib"),
|
title: const Text("Openlib"),
|
||||||
titleTextStyle: Theme.of(context).textTheme.displayLarge,
|
titleTextStyle: Theme.of(context).textTheme.displayLarge,
|
||||||
actions: [
|
actions: isMobile
|
||||||
IconButton(
|
? [
|
||||||
onPressed: () {
|
IconButton(
|
||||||
if (currentPage != 0) {
|
onPressed: () {
|
||||||
ref.read(pdfCurrentPage.notifier).state = currentPage - 1;
|
if (currentPage != 0) {
|
||||||
controller.setPage(currentPage - 1);
|
ref.read(pdfCurrentPage.notifier).state =
|
||||||
} else {
|
currentPage - 1;
|
||||||
ref.read(pdfCurrentPage.notifier).state = totalPages;
|
controller.setPage(currentPage - 1);
|
||||||
controller.setPage(totalPages - 1);
|
} else {
|
||||||
}
|
ref.read(pdfCurrentPage.notifier).state = totalPages;
|
||||||
},
|
controller.setPage(totalPages - 1);
|
||||||
icon: const Icon(
|
}
|
||||||
Icons.arrow_left,
|
},
|
||||||
size: 25,
|
icon: const Icon(
|
||||||
)),
|
Icons.arrow_left,
|
||||||
Text('${(currentPage + 1).toString()} / ${totalPages.toString()}'),
|
size: 25,
|
||||||
IconButton(
|
)),
|
||||||
onPressed: () {
|
Text(
|
||||||
if (currentPage + 1 < totalPages) {
|
'${(currentPage + 1).toString()} / ${totalPages.toString()}'),
|
||||||
ref.read(pdfCurrentPage.notifier).state = currentPage + 1;
|
IconButton(
|
||||||
controller.setPage(currentPage + 1);
|
onPressed: () {
|
||||||
} else {
|
if (currentPage + 1 < totalPages) {
|
||||||
ref.read(pdfCurrentPage.notifier).state = 0;
|
ref.read(pdfCurrentPage.notifier).state =
|
||||||
controller.setPage(0);
|
currentPage + 1;
|
||||||
}
|
controller.setPage(currentPage + 1);
|
||||||
},
|
} else {
|
||||||
icon: const Icon(
|
ref.read(pdfCurrentPage.notifier).state = 0;
|
||||||
Icons.arrow_right,
|
controller.setPage(0);
|
||||||
size: 25,
|
}
|
||||||
)),
|
},
|
||||||
],
|
icon: const Icon(
|
||||||
),
|
Icons.arrow_right,
|
||||||
body: PDFView(
|
size: 25,
|
||||||
swipeHorizontal: true,
|
)),
|
||||||
fitEachPage: true,
|
]
|
||||||
fitPolicy: FitPolicy.BOTH,
|
: [],
|
||||||
filePath: widget.filePath,
|
|
||||||
onViewCreated: (controller) {
|
|
||||||
this.controller = controller;
|
|
||||||
},
|
|
||||||
onPageChanged: (page, total) {
|
|
||||||
ref.read(pdfCurrentPage.notifier).state = page ?? 0;
|
|
||||||
ref.read(totalPdfPage.notifier).state = total ?? 0;
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
|
body: isMobile
|
||||||
|
? ref.watch(getBookPosition(widget.fileName)).when(
|
||||||
|
data: (data) {
|
||||||
|
return PDFView(
|
||||||
|
swipeHorizontal: true,
|
||||||
|
fitEachPage: true,
|
||||||
|
fitPolicy: FitPolicy.BOTH,
|
||||||
|
filePath: widget.filePath,
|
||||||
|
onViewCreated: (controller) {
|
||||||
|
this.controller = controller;
|
||||||
|
},
|
||||||
|
defaultPage: int.parse(data ?? '0'),
|
||||||
|
onPageChanged: (page, total) {
|
||||||
|
ref.read(pdfCurrentPage.notifier).state = page ?? 0;
|
||||||
|
ref.read(totalPdfPage.notifier).state = total ?? 0;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
error: (error, stackTrace) {
|
||||||
|
return PDFView(
|
||||||
|
swipeHorizontal: true,
|
||||||
|
fitEachPage: true,
|
||||||
|
fitPolicy: FitPolicy.BOTH,
|
||||||
|
filePath: widget.filePath,
|
||||||
|
onViewCreated: (controller) {
|
||||||
|
this.controller = controller;
|
||||||
|
},
|
||||||
|
onPageChanged: (page, total) {
|
||||||
|
ref.read(pdfCurrentPage.notifier).state = page ?? 0;
|
||||||
|
ref.read(totalPdfPage.notifier).state = total ?? 0;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading: () {
|
||||||
|
return Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 25,
|
||||||
|
height: 25,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: Center(
|
||||||
|
child: TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.secondary,
|
||||||
|
textStyle: const TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.w900,
|
||||||
|
color: Colors.white,
|
||||||
|
)),
|
||||||
|
onPressed: () async {
|
||||||
|
await _openPdfWithDefaultViewer("file://${widget.filePath}");
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
"Open with System's PDF Viewer",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,12 +42,14 @@ class SearchPage extends ConsumerWidget {
|
|||||||
cursorColor: Theme.of(context).colorScheme.secondary,
|
cursorColor: Theme.of(context).colorScheme.secondary,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
enabledBorder: const OutlineInputBorder(
|
enabledBorder: const OutlineInputBorder(
|
||||||
borderSide: BorderSide(color: Colors.black45, width: 2),
|
borderSide: BorderSide(color: Colors.grey, width: 2),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(50)),
|
borderRadius: BorderRadius.all(Radius.circular(50)),
|
||||||
),
|
),
|
||||||
focusedBorder: const OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderSide: BorderSide(color: Colors.black54, width: 2),
|
borderSide: BorderSide(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(50)),
|
color: Theme.of(context).colorScheme.tertiary,
|
||||||
|
width: 2),
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(50)),
|
||||||
),
|
),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
padding: const EdgeInsets.only(right: 5),
|
padding: const EdgeInsets.only(right: 5),
|
||||||
@ -88,12 +90,14 @@ class SearchPage extends ConsumerWidget {
|
|||||||
color: Theme.of(context).colorScheme.secondary,
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
),
|
),
|
||||||
enabledBorder: const OutlineInputBorder(
|
enabledBorder: const OutlineInputBorder(
|
||||||
borderSide: BorderSide(color: Colors.black54, width: 2),
|
borderSide: BorderSide(color: Colors.grey, width: 2),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(50)),
|
borderRadius: BorderRadius.all(Radius.circular(50)),
|
||||||
),
|
),
|
||||||
focusedBorder: const OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderSide: BorderSide(color: Colors.black54, width: 2),
|
borderSide: BorderSide(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(50)),
|
color: Theme.of(context).colorScheme.tertiary,
|
||||||
|
width: 2),
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(50)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
icon: const Icon(Icons.arrow_drop_down),
|
icon: const Icon(Icons.arrow_drop_down),
|
||||||
@ -105,7 +109,8 @@ class SearchPage extends ConsumerWidget {
|
|||||||
value: value,
|
value: value,
|
||||||
child: Text(
|
child: Text(
|
||||||
value,
|
value,
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(
|
||||||
|
fontSize: 12, fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
@ -128,12 +133,14 @@ class SearchPage extends ConsumerWidget {
|
|||||||
color: Theme.of(context).colorScheme.secondary,
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
),
|
),
|
||||||
enabledBorder: const OutlineInputBorder(
|
enabledBorder: const OutlineInputBorder(
|
||||||
borderSide: BorderSide(color: Colors.black45, width: 2),
|
borderSide: BorderSide(color: Colors.grey, width: 2),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(50)),
|
borderRadius: BorderRadius.all(Radius.circular(50)),
|
||||||
),
|
),
|
||||||
focusedBorder: const OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderSide: BorderSide(color: Colors.black54, width: 2),
|
borderSide: BorderSide(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(50)),
|
color: Theme.of(context).colorScheme.tertiary,
|
||||||
|
width: 2),
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(50)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
value: dropdownSortValue,
|
value: dropdownSortValue,
|
||||||
@ -144,7 +151,8 @@ class SearchPage extends ConsumerWidget {
|
|||||||
value: value,
|
value: value,
|
||||||
child: Text(
|
child: Text(
|
||||||
value,
|
value,
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(
|
||||||
|
fontSize: 12, fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
|
155
lib/ui/settings_page.dart
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
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,
|
||||||
|
openPdfWithExternalAppProvider,
|
||||||
|
openEpubWithExternalAppProvider,
|
||||||
|
dbProvider;
|
||||||
|
|
||||||
|
class SettingsPage extends ConsumerWidget {
|
||||||
|
const SettingsPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 5, right: 5, top: 10),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.vertical,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const TitleText("Settings"),
|
||||||
|
_PaddedContainer(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Dark Mode",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Theme.of(context).colorScheme.tertiary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Switch(
|
||||||
|
// This bool value toggles the switch.
|
||||||
|
value: ref.watch(themeModeProvider) == ThemeMode.dark,
|
||||||
|
activeColor: Colors.red,
|
||||||
|
onChanged: (bool value) {
|
||||||
|
ref.read(themeModeProvider.notifier).state =
|
||||||
|
value == true ? ThemeMode.dark : ThemeMode.light;
|
||||||
|
ref.read(dbProvider).savePreference('darkMode', value);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
_PaddedContainer(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Open PDF with External Reader",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
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: 15,
|
||||||
|
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,
|
||||||
|
MaterialPageRoute(builder: (BuildContext context) {
|
||||||
|
return const AboutPage();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"About",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Theme.of(context).colorScheme.tertiary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PaddedContainer extends StatelessWidget {
|
||||||
|
const _PaddedContainer({Key? key, this.onClick, required this.children})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
final VoidCallback? onClick;
|
||||||
|
final List<Widget> children;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 5, right: 5, top: 10),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: onClick,
|
||||||
|
child: Container(
|
||||||
|
height: 61,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
color: Theme.of(context).colorScheme.tertiaryContainer,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: children,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
72
lib/ui/themes.dart
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:openlib/ui/extensions.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
|
||||||
|
ThemeData lightTheme = ThemeData(
|
||||||
|
primaryColor: Colors.white,
|
||||||
|
colorScheme: ColorScheme.light(
|
||||||
|
primary: Colors.white,
|
||||||
|
secondary: '#FB0101'.toColor(),
|
||||||
|
tertiary: Colors.black,
|
||||||
|
tertiaryContainer: '#F2F2F2'.toColor(),
|
||||||
|
),
|
||||||
|
textTheme: TextTheme(
|
||||||
|
displayLarge: const TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 21,
|
||||||
|
),
|
||||||
|
displayMedium: const TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
headlineMedium: TextStyle(
|
||||||
|
color: "#595E60".toColor(),
|
||||||
|
),
|
||||||
|
headlineSmall: TextStyle(
|
||||||
|
color: "#7F7F7F".toColor(),
|
||||||
|
)),
|
||||||
|
fontFamily: GoogleFonts.nunito().fontFamily,
|
||||||
|
useMaterial3: true,
|
||||||
|
textSelectionTheme: TextSelectionThemeData(
|
||||||
|
selectionColor: '#FB0101'.toColor(),
|
||||||
|
selectionHandleColor: '#FB0101'.toColor(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
ThemeData darkTheme = ThemeData(
|
||||||
|
primaryColor: Colors.black,
|
||||||
|
colorScheme: ColorScheme.dark(
|
||||||
|
primary: Colors.black,
|
||||||
|
secondary: '#FB0101'.toColor(),
|
||||||
|
tertiary: Colors.white,
|
||||||
|
tertiaryContainer: '#2B2B2B'.toColor(),
|
||||||
|
),
|
||||||
|
textTheme: TextTheme(
|
||||||
|
displayLarge: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 21,
|
||||||
|
),
|
||||||
|
displayMedium: const TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
headlineMedium: TextStyle(
|
||||||
|
color: "#F5F5F5".toColor(),
|
||||||
|
),
|
||||||
|
headlineSmall: TextStyle(
|
||||||
|
color: "#E8E2E2".toColor(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
fontFamily: GoogleFonts.nunito().fontFamily,
|
||||||
|
useMaterial3: true,
|
||||||
|
textSelectionTheme: TextSelectionThemeData(
|
||||||
|
selectionColor: '#FB0101'.toColor(),
|
||||||
|
selectionHandleColor: '#FB0101'.toColor(),
|
||||||
|
),
|
||||||
|
);
|
@ -21,6 +21,7 @@ class TrendingPage extends ConsumerWidget {
|
|||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(left: 5, right: 5, top: 10),
|
padding: const EdgeInsets.only(left: 5, right: 5, top: 10),
|
||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
|
physics: const BouncingScrollPhysics(),
|
||||||
slivers: [
|
slivers: [
|
||||||
const SliverToBoxAdapter(
|
const SliverToBoxAdapter(
|
||||||
child: TitleText("Trending"),
|
child: TitleText("Trending"),
|
||||||
@ -45,10 +46,9 @@ class TrendingPage extends ConsumerWidget {
|
|||||||
);
|
);
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
child: Container(
|
child: SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: double.infinity,
|
height: double.infinity,
|
||||||
color: const Color.fromARGB(255, 255, 255, 255),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
|
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||||
|
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
url_launcher_linux
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
@ -7,8 +7,10 @@ import Foundation
|
|||||||
|
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
import sqflite
|
import sqflite
|
||||||
|
import url_launcher_macos
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||||
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
}
|
}
|
||||||
|
257
pubspec.lock
@ -5,10 +5,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: archive
|
name: archive
|
||||||
sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a"
|
sha256: "49b1fad315e57ab0bbc15bcbb874e83116a1d78f77ebd500a4af6c9407d6b28e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.3.7"
|
version: "3.3.8"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -93,10 +93,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
|
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.1"
|
version: "1.17.2"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -125,10 +125,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: cupertino_icons
|
name: cupertino_icons
|
||||||
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
|
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5"
|
version: "1.0.6"
|
||||||
dev:
|
dev:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -141,10 +141,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: dio
|
name: dio
|
||||||
sha256: "3866d67f93523161b643187af65f5ac08bc991a5bcdaf41a2d587fe4ccb49993"
|
sha256: ce75a1b40947fea0a0e16ce73337122a86762e38b982e1ccb909daa3b9bc4197
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.3.0"
|
version: "5.3.2"
|
||||||
epub_view:
|
epub_view:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -181,10 +181,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: ffi
|
name: ffi
|
||||||
sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99
|
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.1.0"
|
||||||
file:
|
file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -234,10 +234,10 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: flutter_lints
|
name: flutter_lints
|
||||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.0.3"
|
||||||
flutter_pdfview:
|
flutter_pdfview:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -250,10 +250,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_riverpod
|
name: flutter_riverpod
|
||||||
sha256: b83ac5827baadefd331ea1d85110f34645827ea234ccabf53a655f41901a9bf4
|
sha256: b04d4e9435a563673746ccb328d22018c6c9496bb547e11dd56c1b0cc9829fe5
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.6"
|
version: "2.3.10"
|
||||||
flutter_svg:
|
flutter_svg:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -267,6 +267,11 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_web_plugins:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
gestures:
|
gestures:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -359,18 +364,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
|
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.15"
|
version: "0.12.16"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
|
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
version: "0.5.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -387,6 +392,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
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:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -407,50 +420,90 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path_provider
|
name: path_provider
|
||||||
sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2"
|
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.15"
|
version: "2.1.1"
|
||||||
path_provider_android:
|
path_provider_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86"
|
sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.27"
|
version: "2.2.0"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_foundation
|
name: path_provider_foundation
|
||||||
sha256: "916731ccbdce44d545414dd9961f26ba5fbaa74bcbb55237d8e65a623a8c7297"
|
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.4"
|
version: "2.3.1"
|
||||||
path_provider_linux:
|
path_provider_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_linux
|
name: path_provider_linux
|
||||||
sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57
|
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.11"
|
version: "2.2.1"
|
||||||
path_provider_platform_interface:
|
path_provider_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_platform_interface
|
name: path_provider_platform_interface
|
||||||
sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec"
|
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.6"
|
version: "2.1.1"
|
||||||
path_provider_windows:
|
path_provider_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_windows
|
name: path_provider_windows
|
||||||
sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96"
|
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.7"
|
version: "2.2.1"
|
||||||
|
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:
|
petitparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -463,18 +516,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: platform
|
name: platform
|
||||||
sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
|
sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "3.1.2"
|
||||||
plugin_platform_interface:
|
plugin_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc"
|
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.6"
|
||||||
pointycastle:
|
pointycastle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -495,10 +548,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: riverpod
|
name: riverpod
|
||||||
sha256: "80e48bebc83010d5e67a11c9514af6b44bbac1ec77b4333c8ea65dbc79e2d8ef"
|
sha256: "6c0a2c30c04206ac05494bcccd8148b76866e1a9248a5a8c84ca7b16fbcb3f6a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.6"
|
version: "2.3.10"
|
||||||
rxdart:
|
rxdart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -524,10 +577,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.10.0"
|
||||||
|
sprintf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sprintf
|
||||||
|
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
sqflite:
|
sqflite:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -544,6 +605,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.0"
|
version: "2.5.0"
|
||||||
|
sqflite_common_ffi:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: sqflite_common_ffi
|
||||||
|
sha256: "0d5cc1be2eb18400ac6701c31211d44164393aa75886093002ecdd947be04f93"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.0+2"
|
||||||
|
sqlite3:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sqlite3
|
||||||
|
sha256: db65233e6b99e99b2548932f55a987961bc06d82a31a0665451fa0b4fff4c3fb
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -556,10 +633,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: state_notifier
|
name: state_notifier
|
||||||
sha256: "8fe42610f179b843b12371e40db58c9444f8757f8b69d181c97e50787caed289"
|
sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.2+1"
|
version: "1.0.0"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -596,10 +673,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
|
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.1"
|
version: "0.6.0"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -616,14 +693,78 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
|
url_launcher:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: url_launcher
|
||||||
|
sha256: "47e208a6711459d813ba18af120d9663c20bdf6985d6ad39fe165d2538378d27"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.14"
|
||||||
|
url_launcher_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_android
|
||||||
|
sha256: b04af59516ab45762b2ca6da40fa830d72d0f6045cd97744450b73493fa76330
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.0"
|
||||||
|
url_launcher_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_ios
|
||||||
|
sha256: "7c65021d5dee51813d652357bc65b8dd4a6177082a9966bc8ba6ee477baa795f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.5"
|
||||||
|
url_launcher_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_linux
|
||||||
|
sha256: b651aad005e0cb06a01dbd84b428a301916dc75f0e7ea6165f80057fee2d8e8e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.6"
|
||||||
|
url_launcher_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_macos
|
||||||
|
sha256: b55486791f666e62e0e8ff825e58a023fd6b1f71c49926483f1128d3bbd8fe88
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.7"
|
||||||
|
url_launcher_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_platform_interface
|
||||||
|
sha256: "95465b39f83bfe95fcb9d174829d6476216f2d548b79c38ab2506e0458787618"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.5"
|
||||||
|
url_launcher_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_web
|
||||||
|
sha256: "2942294a500b4fa0b918685aff406773ba0a4cd34b7f42198742a94083020ce5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.20"
|
||||||
|
url_launcher_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_windows
|
||||||
|
sha256: "95fef3129dc7cfaba2bc3d5ba2e16063bb561fc6d78e63eee16162bc70029069"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.8"
|
||||||
uuid:
|
uuid:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: uuid
|
name: uuid
|
||||||
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"
|
sha256: e03928880bdbcbf496fb415573f5ab7b1ea99b9b04f669c01104d085893c3134
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.7"
|
version: "4.0.0"
|
||||||
vector_graphics:
|
vector_graphics:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -656,22 +797,38 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
|
vocsy_epub_viewer:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: vocsy_epub_viewer
|
||||||
|
sha256: "30aab4a5be22e8c98f22fed3345f6989caaca861178c38cab2a8b8cd66ad53de"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
|
web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web
|
||||||
|
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.4-beta"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee
|
sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.5"
|
version: "5.0.7"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: xdg_directories
|
name: xdg_directories
|
||||||
sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff
|
sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.3"
|
||||||
xml:
|
xml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -689,5 +846,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.0.5 <4.0.0"
|
dart: ">=3.1.0 <4.0.0"
|
||||||
flutter: ">=3.7.0-0"
|
flutter: ">=3.13.0"
|
||||||
|
@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.0.0+1
|
version: 1.0.2+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.0.5 <4.0.0'
|
sdk: '>=3.0.5 <4.0.0'
|
||||||
@ -36,6 +36,7 @@ dependencies:
|
|||||||
|
|
||||||
epub_view: ^3.2.0
|
epub_view: ^3.2.0
|
||||||
flutter_pdfview: ^1.2.7
|
flutter_pdfview: ^1.2.7
|
||||||
|
vocsy_epub_viewer: ^2.0.0
|
||||||
# syncfusion_flutter_pdfviewer: ^22.2.5
|
# syncfusion_flutter_pdfviewer: ^22.2.5
|
||||||
# pdfx: ^2.4.0
|
# pdfx: ^2.4.0
|
||||||
|
|
||||||
@ -44,11 +45,16 @@ dependencies:
|
|||||||
|
|
||||||
sqflite: ^2.3.0
|
sqflite: ^2.3.0
|
||||||
path_provider: ^2.0.15
|
path_provider: ^2.0.15
|
||||||
|
permission_handler: ^10.4.3
|
||||||
|
open_file: ^3.3.2
|
||||||
|
|
||||||
flutter_svg: ^2.0.7
|
flutter_svg: ^2.0.7
|
||||||
google_fonts: ^5.1.0
|
google_fonts: ^5.1.0
|
||||||
|
|
||||||
cached_network_image: ^3.2.3
|
cached_network_image: ^3.2.3
|
||||||
|
|
||||||
|
sqflite_common_ffi: ^2.3.0+2
|
||||||
|
url_launcher: ^6.1.12
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
|
@ -6,6 +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>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||||
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
permission_handler_windows
|
||||||
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|