36 Commits

Author SHA1 Message Date
ccd260d451 Fixed download failing due to change in Anna's archive website 2023-09-10 22:50:57 -07:00
546805be20 updated packages 2023-09-03 07:46:52 -07:00
250f0f8b7b openwith support 2023-09-03 07:29:57 -07:00
f0d0178a2d added openwith feature 2023-09-02 05:38:27 -07:00
f4f86a1353 openwith feature added 2023-09-02 04:59:01 -07:00
93013fe6bb added open with feature 2023-09-02 03:53:03 -07:00
1de126104d Migated to new epub viewer for android and ios 2023-08-30 00:56:02 -07:00
e4c8ddaa88 fixed crashing 2023-08-29 06:36:55 -07:00
82798bb749 added resume reading in new epub reader 2023-08-29 06:24:20 -07:00
16fc051219 added new epub reader 2023-08-29 05:23:38 -07:00
da399604bf added new epub viewer 2023-08-27 23:28:33 -07:00
1b87e89470 finished settings and dark theme 2023-08-25 05:20:13 -07:00
0db7794455 added about page 2023-08-25 05:02:47 -07:00
6b31a63e86 adjusted bottombar transitions 2023-08-24 23:17:02 -07:00
27061a1922 added db to persist theme modes 2023-08-24 23:12:30 -07:00
162ea41196 theme change added 2023-08-23 01:18:12 -07:00
010dc1dfdb added dark mode 2023-08-23 01:02:21 -07:00
b2a1be7a7e init settings page design 2023-08-22 23:29:07 -07:00
1507656944 settings page 2023-08-22 20:13:03 -07:00
9cc3c3dde5 implemented resume reading for pdf and epub 2023-08-21 22:52:19 -07:00
e7b6a9d40f added resume reading for pdf viewer 2023-08-18 07:03:23 -07:00
60df4afac2 improved code readability 2023-08-14 23:13:10 -07:00
bcfb35ab14 Fixed a bug with Sqflite_ffi 2023-08-13 22:56:01 -07:00
4ac80f08d8 Merge pull request #6 from bipinkrish/main
View for non mobile platforms
2023-08-13 22:31:14 -07:00
a9fde1c561 view for non mobile platforms 2023-08-13 20:49:19 +05:30
110d089b8d Merge branch 'main' of https://github.com/dstark5/Openlib 2023-08-13 05:04:50 -07:00
4445fc4d84 added wake lock to permissions and commented unused lines 2023-08-13 05:04:41 -07:00
11d19b3001 Update README.md 2023-08-13 05:01:13 -07:00
052c5993b1 Update README.md 2023-08-13 04:34:07 -07:00
bc36a350ab Update README.md 2023-08-13 04:28:54 -07:00
9102b0be7b Add files via upload 2023-08-13 04:24:43 -07:00
365d29c19e Update README.md 2023-08-13 04:23:42 -07:00
52c742e8d0 Update README.md 2023-08-13 04:21:54 -07:00
d2c992bf80 Merge pull request #1 from IzzySoft/fastlane
initial fastlane structure
2023-08-12 06:27:20 -07:00
39a91b9992 initial fastlane structure 2023-08-12 14:32:43 +02:00
19df3b4f7b Update README.md 2023-08-11 04:59:59 -07:00
41 changed files with 1229 additions and 253 deletions

View File

@ -3,7 +3,13 @@
#### An Open source app to download and read books from shadow library ([Annas Archive](https://annas-archive.org/)).
[![made-with-flutter](https://img.shields.io/badge/Made%20with-Flutter-4361ee.svg)](https://flutter.dev/) [![GPLv3 License](https://img.shields.io/badge/License-GPL%20v3-e63946.svg)](https://opensource.org/licenses/)
[![made-with-flutter](https://img.shields.io/badge/Made%20with-Flutter-4361ee.svg)](https://flutter.dev/) [![GPLv3 License](https://img.shields.io/badge/License-GPL%20v3-e63946.svg)](https://opensource.org/licenses/) ![version](https://img.shields.io/badge/version-1.0_beta-06d6a0)
[<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
@ -43,6 +49,7 @@
- Adding Support For Multiple Downloads
## 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.
## Building from Source
@ -69,7 +76,7 @@ flutter build
- The Build Will Be In './build/app/outputs/flutter-apk/app-release.apk'
## 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

View File

@ -79,6 +79,8 @@ android {
// Signing with the debug keys for now, so `flutter run --release` works.
// replace with "debug" when running on debug version
signingConfig signingConfigs.release
minifyEnabled false
shrinkResources false
}
}
}

View File

@ -1,6 +1,22 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<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
android:label="Openlib"
android:name="${applicationName}"

View 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'>Annas Archive</a>). The App Has Built In Reader to Read Books.
</p>
<p>
As <i>Annas Archive</i> doesn't have an API, the app works by sending requests to <i>Annas 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1 @@
download and read books from shadow library (Annas Archive)

BIN
github_releases.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,29 +1,65 @@
import 'package:flutter/material.dart';
import 'dart:io' show Platform;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_nav_bar/google_nav_bar.dart';
import 'package:sqflite/sqflite.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'package:openlib/ui/extensions.dart';
import 'package:openlib/ui/themes.dart';
import 'package:openlib/ui/trending_page.dart';
import 'package:openlib/ui/search_page.dart';
import 'package:openlib/ui/mylibrary_page.dart';
import 'package:openlib/ui/settings_page.dart';
import 'package:openlib/services/database.dart' show Sqlite, MyLibraryDb;
import 'package:openlib/services/files.dart'
show moveFilesToAndroidInternalStorage;
import 'package:openlib/state/state.dart'
show selectedIndexProvider, dbProvider;
show
selectedIndexProvider,
themeModeProvider,
openPdfWithExternalAppProvider,
openEpubWithExternalAppProvider,
dbProvider;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
Database db = await Sqlite.initDb();
runApp(ProviderScope(
overrides: [dbProvider.overrideWithValue(MyLibraryDb(dbInstance: db))],
child: const MyApp()));
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
sqfliteFfiInit();
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});
@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
return MaterialApp(
builder: (BuildContext context, Widget? child) {
return MediaQuery(
@ -35,32 +71,9 @@ class MyApp extends StatelessWidget {
},
debugShowCheckedModeBanner: false,
title: 'Openlib',
theme: ThemeData(
primaryColor: Colors.white,
colorScheme: ColorScheme.light(
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())),
theme: lightTheme,
darkTheme: darkTheme,
themeMode: ref.watch(themeModeProvider),
home: const HomePage(),
);
}
@ -77,7 +90,8 @@ class _HomePageState extends ConsumerState<HomePage> {
static const List<Widget> _widgetOptions = <Widget>[
TrendingPage(),
SearchPage(),
MyLibraryPage()
MyLibraryPage(),
SettingsPage()
];
@override
@ -101,14 +115,14 @@ class _HomePageState extends ConsumerState<HomePage> {
color: Theme.of(context).colorScheme.secondary,
),
tabMargin: const EdgeInsets.fromLTRB(13, 6, 13, 2.5),
curve: Curves.easeInOut, // tab animation curves
duration: const Duration(milliseconds: 150),
curve: Curves.easeIn,
duration: const Duration(milliseconds: 125),
gap: 5,
color: 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,
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 6.5),
padding: const EdgeInsets.symmetric(horizontal: 13, vertical: 6.5),
tabs: const [
GButton(
icon: Icons.trending_up,
@ -117,7 +131,7 @@ class _HomePageState extends ConsumerState<HomePage> {
textStyle: TextStyle(
fontWeight: FontWeight.w900,
color: Colors.white,
fontSize: 13,
fontSize: 11,
),
),
GButton(
@ -127,7 +141,7 @@ class _HomePageState extends ConsumerState<HomePage> {
textStyle: TextStyle(
fontWeight: FontWeight.w900,
color: Colors.white,
fontSize: 13,
fontSize: 11,
),
),
GButton(
@ -137,7 +151,17 @@ class _HomePageState extends ConsumerState<HomePage> {
textStyle: TextStyle(
fontWeight: FontWeight.w900,
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,
),
),
],

View File

@ -127,7 +127,7 @@ class AnnasArchieve {
String? link = pTag?.querySelector('a')?.attributes['href'];
return link;
} catch (e) {
print(e);
// print(e);
return null;
}
}
@ -135,14 +135,19 @@ class AnnasArchieve {
Future<BookInfoData?> _bookInfoParser(resData, url) async {
var document = parse(resData.toString());
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 = [];
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'] != null) {
mirrors.add(element.attributes['href']!);

View File

@ -1,15 +1,40 @@
import 'dart:io';
import 'package:sqflite/sqflite.dart';
class Sqlite {
static Future<Database> initDb() async {
var databasesPath = await getDatabasesPath();
String path = '$databasesPath/mylibrary.db';
bool isMobile = Platform.isAndroid || Platform.isIOS;
Database dbInstance = await openDatabase(path, version: 1,
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)');
});
Database dbInstance = await openDatabase(
path,
version: 3,
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;
}
}
@ -118,4 +143,55 @@ class MyLibraryDb {
});
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;
}
}
}

View File

@ -1,9 +1,9 @@
import 'package:path_provider/path_provider.dart';
import 'package:dio/dio.dart';
import 'files.dart';
Future<String> _getFilePath(String fileName) async {
final path = await getApplicationDocumentsDirectory();
return '${path.path}/$fileName';
final path = await getAppDirectoryPath;
return '$path/$fileName';
}
List<String> _reorderMirrors(List<String> mirrors) {
@ -14,7 +14,8 @@ List<String> _reorderMirrors(List<String> mirrors) {
if (element.contains('ipfs') == true) {
ipfsMirrors.add(element);
} 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);
}
}

View File

@ -4,8 +4,32 @@ import 'package:path_provider/path_provider.dart';
import 'package:openlib/state/state.dart' show dbProvider, myLibraryProvider;
Future<String> get getAppDirectoryPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
if (Platform.isAndroid) {
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 {
@ -35,9 +59,11 @@ Future<void> deleteFileWithDbData(
String appDirPath = await getAppDirectoryPath;
await deleteFile('$appDirPath/$fileName');
await ref.read(dbProvider).delete(md5);
await ref.read(dbProvider).deleteBookState(fileName);
// ignore: unused_result
ref.refresh(myLibraryProvider);
} catch (e) {
print(e);
// print(e);
rethrow;
}
}

View File

@ -1,4 +1,5 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:openlib/services/database.dart';
import 'package:dio/dio.dart';
@ -31,6 +32,8 @@ Map<String, String> sortValues = {
final selectedIndexProvider = StateProvider<int>((ref) => 0);
final themeModeProvider = StateProvider<ThemeMode>((ref) => ThemeMode.light);
final selectedTypeState = StateProvider<String>((ref) => "All");
final getTypeValue = Provider.autoDispose<String>((ref) {
@ -125,6 +128,25 @@ final deleteFileFromMyLib =
final pdfCurrentPage = 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 =
FutureProvider.family<String, String>((ref, fileName) async {
String path = await getFilePath(fileName);

131
lib/ui/about_page.dart Normal file
View 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,
)
],
),
),
);
}
}

View File

@ -200,7 +200,7 @@ class _ShowDialog extends ConsumerWidget {
height: 255,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
color: Theme.of(context).colorScheme.tertiaryContainer,
),
padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
child: SingleChildScrollView(
@ -208,14 +208,14 @@ class _ShowDialog extends ConsumerWidget {
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.all(8),
Padding(
padding: const EdgeInsets.all(8),
child: Text(
"Downloading Book",
style: TextStyle(
fontSize: 19,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 54, 54, 54),
color: Theme.of(context).colorScheme.tertiary,
decoration: TextDecoration.none),
),
),
@ -223,10 +223,13 @@ class _ShowDialog extends ConsumerWidget {
padding: const EdgeInsets.all(8),
child: Text(
title,
style: const TextStyle(
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.bold,
color: Colors.black54,
color: Theme.of(context)
.colorScheme
.tertiary
.withAlpha(170),
decoration: TextDecoration.none),
overflow: TextOverflow.ellipsis,
maxLines: 2,
@ -259,7 +262,10 @@ class _ShowDialog extends ConsumerWidget {
borderRadius: const BorderRadius.all(Radius.circular(50)),
child: LinearProgressIndicator(
color: Theme.of(context).colorScheme.secondary,
backgroundColor: Colors.black26,
backgroundColor: Theme.of(context)
.colorScheme
.tertiary
.withAlpha(50),
value: downloadProgress,
minHeight: 4,
),

View File

@ -81,10 +81,10 @@ class BookInfoCard extends StatelessWidget {
children: [
Text(
title,
style: const TextStyle(
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
color: Colors.black,
color: Theme.of(context).colorScheme.tertiary,
),
overflow: TextOverflow.ellipsis,
maxLines: 2,
@ -94,7 +94,8 @@ class BookInfoCard extends StatelessWidget {
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: "#4D4D4D".toColor(),
color:
Theme.of(context).textTheme.headlineMedium?.color,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
@ -104,7 +105,7 @@ class BookInfoCard extends StatelessWidget {
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: "#7B7B7B".toColor(),
color: Theme.of(context).textTheme.headlineSmall?.color,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:openlib/ui/extensions.dart';
import 'package:cached_network_image/cached_network_image.dart';
class BookInfoWidget extends StatelessWidget {
@ -11,6 +10,9 @@ class BookInfoWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
String description = data.description.toString().length < 3
? "No Description available"
: data.description.toString();
return SingleChildScrollView(
physics: const BouncingScrollPhysics(),
scrollDirection: Axis.vertical,
@ -65,28 +67,32 @@ class BookInfoWidget extends StatelessWidget {
text: data.title,
fontSize: 19,
topPadding: 15,
color: Colors.black,
color: Theme.of(context).colorScheme.tertiary,
maxLines: 7,
),
_TopPaddedText(
text: data.publisher ?? "unknown",
fontSize: 15,
topPadding: 7,
color: "#595E60".toColor(),
color: Theme.of(context).textTheme.headlineMedium!.color!,
maxLines: 4,
),
_TopPaddedText(
text: data.author ?? "unknown",
fontSize: 13,
topPadding: 7,
color: "#7F7F7F".toColor(),
color: Theme.of(context).textTheme.headlineSmall!.color!,
maxLines: 3,
),
_TopPaddedText(
text: data.info ?? "",
fontSize: 11,
topPadding: 9,
color: "#A9A8A2".toColor(),
color: Theme.of(context)
.textTheme
.headlineSmall!
.color!
.withAlpha(155),
maxLines: 4,
),
// child slot of page
@ -108,11 +114,12 @@ class BookInfoWidget extends StatelessWidget {
Padding(
padding: const EdgeInsets.only(top: 7, bottom: 10),
child: Text(
data.description ?? "",
description,
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: "#6B6B6B".toColor(),
color:
Theme.of(context).colorScheme.tertiary.withAlpha(150),
letterSpacing: 1.5,
),
),

View File

@ -26,7 +26,7 @@ class ShowDeleteDialog extends ConsumerWidget {
height: 219,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
color: Theme.of(context).colorScheme.tertiaryContainer,
),
padding: const EdgeInsets.fromLTRB(20, 50, 20, 20),
child: SingleChildScrollView(
@ -34,25 +34,28 @@ class ShowDeleteDialog extends ConsumerWidget {
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.all(8),
Padding(
padding: const EdgeInsets.all(8),
child: Text(
"Delete Book",
style: TextStyle(
fontSize: 19,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 54, 54, 54),
color: Theme.of(context).colorScheme.tertiary,
decoration: TextDecoration.none),
),
),
const Padding(
padding: EdgeInsets.all(8),
Padding(
padding: const EdgeInsets.all(8),
child: Text(
"This is permanent and cannot be undone",
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.bold,
color: Colors.black54,
color: Theme.of(context)
.colorScheme
.tertiary
.withAlpha(170),
decoration: TextDecoration.none),
overflow: TextOverflow.ellipsis,
maxLines: 2,
@ -88,14 +91,14 @@ class ShowDeleteDialog extends ConsumerWidget {
onDelete();
},
child: const Padding(
padding: EdgeInsets.all(5.0),
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Text(
'Delete',
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: Colors.black,
color: Theme.of(context).colorScheme.tertiary,
),
),
),

View File

@ -1,10 +1,11 @@
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/epub_viewer.dart';
import 'package:openlib/ui/pdf_viewer.dart';
import 'package:openlib/ui/epub_viewer.dart' show launchEpubViewer;
import 'package:openlib/ui/pdf_viewer.dart' show launchPdfViewer;
class FileOpenAndDeleteButtons extends StatelessWidget {
class FileOpenAndDeleteButtons extends ConsumerWidget {
final String id;
final String format;
final Function onDelete;
@ -17,7 +18,7 @@ class FileOpenAndDeleteButtons extends StatelessWidget {
: super(key: key);
@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
return Padding(
padding: const EdgeInsets.only(top: 21, bottom: 21),
child: Row(
@ -27,30 +28,19 @@ class FileOpenAndDeleteButtons extends StatelessWidget {
TextButton(
style: TextButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.secondary,
textStyle: const TextStyle(
textStyle: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w900,
color: Colors.white,
color: Theme.of(context).colorScheme.primary,
)),
onPressed: () => {
if (format == 'pdf')
{
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return PdfView(
fileName: '$id.$format',
);
}))
}
else
{
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return EpubViewerWidget(
fileName: '$id.$format',
);
}))
}
onPressed: () async {
if (format == 'pdf') {
await launchPdfViewer(
fileName: '$id.$format', context: context, ref: ref);
} else {
await launchEpubViewer(
fileName: '$id.$format', context: context, ref: ref);
}
},
child: const Padding(
padding: EdgeInsets.fromLTRB(17, 8, 17, 8),
@ -82,14 +72,14 @@ class FileOpenAndDeleteButtons extends StatelessWidget {
);
});
},
child: const Padding(
padding: EdgeInsets.all(5.3),
child: Padding(
padding: const EdgeInsets.all(5.3),
child: Text(
'Delete',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.bold,
color: Colors.black,
color: Theme.of(context).colorScheme.tertiary,
),
),
),

View File

@ -1,9 +1,67 @@
import 'dart:io';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:epub_view/epub_view.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:vocsy_epub_viewer/epub_viewer.dart';
import 'package:open_file/open_file.dart';
import 'package:openlib/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 {
const EpubViewerWidget({super.key, required this.fileName});
@ -19,7 +77,7 @@ class _EpubViewState extends ConsumerState<EpubViewerWidget> {
Widget build(BuildContext context) {
final filePath = ref.watch(filePathProvider(widget.fileName));
return filePath.when(data: (data) {
return EpubViewer(filePath: data);
return EpubViewer(filePath: data, fileName: widget.fileName);
}, error: (error, stack) {
return Scaffold(
appBar: AppBar(
@ -37,30 +95,34 @@ class _EpubViewState extends ConsumerState<EpubViewerWidget> {
titleTextStyle: Theme.of(context).textTheme.displayLarge,
),
body: Center(
child: SizedBox(
width: 25,
height: 25,
child: CircularProgressIndicator(
color: Theme.of(context).colorScheme.secondary,
child: SizedBox(
width: 25,
height: 25,
child: CircularProgressIndicator(
color: Theme.of(context).colorScheme.secondary,
),
),
)),
),
);
});
}
}
class EpubViewer extends StatefulWidget {
const EpubViewer({Key? key, required this.filePath}) : super(key: key);
class EpubViewer extends ConsumerStatefulWidget {
const EpubViewer({Key? key, required this.filePath, required this.fileName})
: super(key: key);
final String filePath;
final String fileName;
@override
// ignore: library_private_types_in_public_api
_EpubViewerState createState() => _EpubViewerState();
}
class _EpubViewerState extends State<EpubViewer> {
class _EpubViewerState extends ConsumerState<EpubViewer> {
late EpubController _epubReaderController;
String? epubConf;
@override
void initState() {
@ -70,6 +132,14 @@ class _EpubViewerState extends State<EpubViewer> {
super.initState();
}
@override
void deactivate() {
if (Platform.isAndroid || Platform.isIOS) {
saveEpubState(widget.fileName, epubConf, ref);
}
super.deactivate();
}
@override
void dispose() {
_epubReaderController.dispose();
@ -78,6 +148,7 @@ class _EpubViewerState extends State<EpubViewer> {
@override
Widget build(BuildContext context) {
final position = ref.watch(getBookPosition(widget.fileName));
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.primary,
@ -87,14 +158,48 @@ class _EpubViewerState extends State<EpubViewer> {
endDrawer: Drawer(
child: EpubViewTableOfContents(controller: _epubReaderController),
),
body: EpubView(
onDocumentLoaded: (doc) {},
onChapterChanged: (value) {},
builders: EpubViewBuilders<DefaultBuilderOptions>(
options: const DefaultBuilderOptions(),
chapterDividerBuilder: (_) => const Divider(),
),
controller: _epubReaderController,
body: position.when(
data: (data) {
return EpubView(
onDocumentLoaded: (doc) {
Future.delayed(const Duration(milliseconds: 20), () {
String pos = data ?? "";
_epubReaderController.gotoEpubCfi(pos);
});
},
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,
),
),
);
},
),
);
}

View File

@ -21,6 +21,7 @@ class MyLibraryPage extends ConsumerWidget {
return Padding(
padding: const EdgeInsets.only(left: 5, right: 5, top: 10),
child: CustomScrollView(
physics: const BouncingScrollPhysics(),
slivers: <Widget>[
const SliverToBoxAdapter(
child: TitleText("My Library"),

View File

@ -2,7 +2,35 @@ import 'package:flutter/material.dart';
import 'package:flutter_pdfview/flutter_pdfview.dart';
import 'package:flutter_riverpod/flutter_riverpod.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 {
const PdfView({super.key, required this.fileName});
@ -18,7 +46,7 @@ class _PdfViewState extends ConsumerState<PdfView> {
Widget build(BuildContext context) {
final filePath = ref.watch(filePathProvider(widget.fileName));
return filePath.when(data: (data) {
return PdfViewer(filePath: data);
return PdfViewer(filePath: data, fileName: widget.fileName);
}, error: (error, stack) {
return Scaffold(
appBar: AppBar(
@ -49,9 +77,11 @@ class _PdfViewState extends ConsumerState<PdfView> {
}
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 fileName;
@override
ConsumerState<ConsumerStatefulWidget> createState() => _PdfViewerState();
@ -60,8 +90,44 @@ class PdfViewer extends ConsumerStatefulWidget {
class _PdfViewerState extends ConsumerState<PdfViewer> {
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
Widget build(BuildContext context) {
bool isMobile = Platform.isAndroid || Platform.isIOS;
final currentPage = ref.watch(pdfCurrentPage);
final totalPages = ref.watch(totalPdfPage);
return Scaffold(
@ -69,51 +135,109 @@ class _PdfViewerState extends ConsumerState<PdfViewer> {
backgroundColor: Theme.of(context).colorScheme.primary,
title: const Text("Openlib"),
titleTextStyle: Theme.of(context).textTheme.displayLarge,
actions: [
IconButton(
onPressed: () {
if (currentPage != 0) {
ref.read(pdfCurrentPage.notifier).state = currentPage - 1;
controller.setPage(currentPage - 1);
} else {
ref.read(pdfCurrentPage.notifier).state = totalPages;
controller.setPage(totalPages - 1);
}
},
icon: const Icon(
Icons.arrow_left,
size: 25,
)),
Text('${(currentPage + 1).toString()} / ${totalPages.toString()}'),
IconButton(
onPressed: () {
if (currentPage + 1 < totalPages) {
ref.read(pdfCurrentPage.notifier).state = currentPage + 1;
controller.setPage(currentPage + 1);
} else {
ref.read(pdfCurrentPage.notifier).state = 0;
controller.setPage(0);
}
},
icon: const Icon(
Icons.arrow_right,
size: 25,
)),
],
),
body: 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;
},
actions: isMobile
? [
IconButton(
onPressed: () {
if (currentPage != 0) {
ref.read(pdfCurrentPage.notifier).state =
currentPage - 1;
controller.setPage(currentPage - 1);
} else {
ref.read(pdfCurrentPage.notifier).state = totalPages;
controller.setPage(totalPages - 1);
}
},
icon: const Icon(
Icons.arrow_left,
size: 25,
)),
Text(
'${(currentPage + 1).toString()} / ${totalPages.toString()}'),
IconButton(
onPressed: () {
if (currentPage + 1 < totalPages) {
ref.read(pdfCurrentPage.notifier).state =
currentPage + 1;
controller.setPage(currentPage + 1);
} else {
ref.read(pdfCurrentPage.notifier).state = 0;
controller.setPage(0);
}
},
icon: const Icon(
Icons.arrow_right,
size: 25,
)),
]
: [],
),
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",
),
),
),
),
);
}
}

View File

@ -42,12 +42,14 @@ class SearchPage extends ConsumerWidget {
cursorColor: Theme.of(context).colorScheme.secondary,
decoration: InputDecoration(
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black45, width: 2),
borderSide: BorderSide(color: Colors.grey, width: 2),
borderRadius: BorderRadius.all(Radius.circular(50)),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black54, width: 2),
borderRadius: BorderRadius.all(Radius.circular(50)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.tertiary,
width: 2),
borderRadius: const BorderRadius.all(Radius.circular(50)),
),
suffixIcon: IconButton(
padding: const EdgeInsets.only(right: 5),
@ -88,12 +90,14 @@ class SearchPage extends ConsumerWidget {
color: Theme.of(context).colorScheme.secondary,
),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black54, width: 2),
borderSide: BorderSide(color: Colors.grey, width: 2),
borderRadius: BorderRadius.all(Radius.circular(50)),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black54, width: 2),
borderRadius: BorderRadius.all(Radius.circular(50)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.tertiary,
width: 2),
borderRadius: const BorderRadius.all(Radius.circular(50)),
),
),
icon: const Icon(Icons.arrow_drop_down),
@ -105,7 +109,8 @@ class SearchPage extends ConsumerWidget {
value: value,
child: Text(
value,
style: const TextStyle(fontSize: 12),
style: const TextStyle(
fontSize: 12, fontWeight: FontWeight.bold),
),
);
}).toList(),
@ -128,12 +133,14 @@ class SearchPage extends ConsumerWidget {
color: Theme.of(context).colorScheme.secondary,
),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black45, width: 2),
borderSide: BorderSide(color: Colors.grey, width: 2),
borderRadius: BorderRadius.all(Radius.circular(50)),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black54, width: 2),
borderRadius: BorderRadius.all(Radius.circular(50)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.tertiary,
width: 2),
borderRadius: const BorderRadius.all(Radius.circular(50)),
),
),
value: dropdownSortValue,
@ -144,7 +151,8 @@ class SearchPage extends ConsumerWidget {
value: value,
child: Text(
value,
style: const TextStyle(fontSize: 12),
style: const TextStyle(
fontSize: 12, fontWeight: FontWeight.bold),
),
);
}).toList(),

155
lib/ui/settings_page.dart Normal file
View 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
View 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(),
),
);

View File

@ -21,6 +21,7 @@ class TrendingPage extends ConsumerWidget {
return Padding(
padding: const EdgeInsets.only(left: 5, right: 5, top: 10),
child: CustomScrollView(
physics: const BouncingScrollPhysics(),
slivers: [
const SliverToBoxAdapter(
child: TitleText("Trending"),
@ -45,10 +46,9 @@ class TrendingPage extends ConsumerWidget {
);
}));
},
child: Container(
child: SizedBox(
width: double.infinity,
height: double.infinity,
color: const Color.fromARGB(255, 255, 255, 255),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,

View File

@ -6,6 +6,10 @@
#include "generated_plugin_registrant.h"
#include <url_launcher_linux/url_launcher_plugin.h>
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);
}

View File

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
url_launcher_linux
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST

View File

@ -7,8 +7,10 @@ import Foundation
import path_provider_foundation
import sqflite
import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
}

View File

@ -5,10 +5,10 @@ packages:
dependency: transitive
description:
name: archive
sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a"
sha256: "49b1fad315e57ab0bbc15bcbb874e83116a1d78f77ebd500a4af6c9407d6b28e"
url: "https://pub.dev"
source: hosted
version: "3.3.7"
version: "3.3.8"
args:
dependency: transitive
description:
@ -93,10 +93,10 @@ packages:
dependency: transitive
description:
name: collection
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
url: "https://pub.dev"
source: hosted
version: "1.17.1"
version: "1.17.2"
convert:
dependency: transitive
description:
@ -125,10 +125,10 @@ packages:
dependency: "direct main"
description:
name: cupertino_icons
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
url: "https://pub.dev"
source: hosted
version: "1.0.5"
version: "1.0.6"
dev:
dependency: "direct main"
description:
@ -141,10 +141,10 @@ packages:
dependency: "direct main"
description:
name: dio
sha256: "3866d67f93523161b643187af65f5ac08bc991a5bcdaf41a2d587fe4ccb49993"
sha256: ce75a1b40947fea0a0e16ce73337122a86762e38b982e1ccb909daa3b9bc4197
url: "https://pub.dev"
source: hosted
version: "5.3.0"
version: "5.3.2"
epub_view:
dependency: "direct main"
description:
@ -181,10 +181,10 @@ packages:
dependency: transitive
description:
name: ffi
sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
version: "2.1.0"
file:
dependency: transitive
description:
@ -234,10 +234,10 @@ packages:
dependency: "direct dev"
description:
name: flutter_lints
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
url: "https://pub.dev"
source: hosted
version: "2.0.2"
version: "2.0.3"
flutter_pdfview:
dependency: "direct main"
description:
@ -250,10 +250,10 @@ packages:
dependency: "direct main"
description:
name: flutter_riverpod
sha256: b83ac5827baadefd331ea1d85110f34645827ea234ccabf53a655f41901a9bf4
sha256: b04d4e9435a563673746ccb328d22018c6c9496bb547e11dd56c1b0cc9829fe5
url: "https://pub.dev"
source: hosted
version: "2.3.6"
version: "2.3.10"
flutter_svg:
dependency: "direct main"
description:
@ -267,6 +267,11 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
gestures:
dependency: transitive
description:
@ -359,18 +364,18 @@ packages:
dependency: transitive
description:
name: matcher
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
url: "https://pub.dev"
source: hosted
version: "0.12.15"
version: "0.12.16"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
version: "0.5.0"
meta:
dependency: transitive
description:
@ -387,6 +392,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.2"
open_file:
dependency: "direct main"
description:
name: open_file
sha256: a5a32d44acb7c899987d0999e1e3cbb0a0f1adebbf41ac813ec6d2d8faa0af20
url: "https://pub.dev"
source: hosted
version: "3.3.2"
path:
dependency: transitive
description:
@ -407,50 +420,90 @@ packages:
dependency: "direct main"
description:
name: path_provider
sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2"
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
url: "https://pub.dev"
source: hosted
version: "2.0.15"
version: "2.1.1"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86"
sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1"
url: "https://pub.dev"
source: hosted
version: "2.0.27"
version: "2.2.0"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: "916731ccbdce44d545414dd9961f26ba5fbaa74bcbb55237d8e65a623a8c7297"
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
url: "https://pub.dev"
source: hosted
version: "2.2.4"
version: "2.3.1"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.dev"
source: hosted
version: "2.1.11"
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec"
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
url: "https://pub.dev"
source: hosted
version: "2.0.6"
version: "2.1.1"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96"
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
url: "https://pub.dev"
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:
dependency: transitive
description:
@ -463,18 +516,18 @@ packages:
dependency: transitive
description:
name: platform
sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102
url: "https://pub.dev"
source: hosted
version: "3.1.0"
version: "3.1.2"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc"
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.6"
pointycastle:
dependency: transitive
description:
@ -495,10 +548,10 @@ packages:
dependency: transitive
description:
name: riverpod
sha256: "80e48bebc83010d5e67a11c9514af6b44bbac1ec77b4333c8ea65dbc79e2d8ef"
sha256: "6c0a2c30c04206ac05494bcccd8148b76866e1a9248a5a8c84ca7b16fbcb3f6a"
url: "https://pub.dev"
source: hosted
version: "2.3.6"
version: "2.3.10"
rxdart:
dependency: transitive
description:
@ -524,10 +577,18 @@ packages:
dependency: transitive
description:
name: source_span
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
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:
dependency: "direct main"
description:
@ -544,6 +605,22 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
@ -556,10 +633,10 @@ packages:
dependency: transitive
description:
name: state_notifier
sha256: "8fe42610f179b843b12371e40db58c9444f8757f8b69d181c97e50787caed289"
sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb
url: "https://pub.dev"
source: hosted
version: "0.7.2+1"
version: "1.0.0"
stream_channel:
dependency: transitive
description:
@ -596,10 +673,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
url: "https://pub.dev"
source: hosted
version: "0.5.1"
version: "0.6.0"
typed_data:
dependency: transitive
description:
@ -616,14 +693,78 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
name: uuid
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"
sha256: e03928880bdbcbf496fb415573f5ab7b1ea99b9b04f669c01104d085893c3134
url: "https://pub.dev"
source: hosted
version: "3.0.7"
version: "4.0.0"
vector_graphics:
dependency: transitive
description:
@ -656,22 +797,38 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
name: win32
sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee
sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa"
url: "https://pub.dev"
source: hosted
version: "5.0.5"
version: "5.0.7"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff
sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "1.0.3"
xml:
dependency: transitive
description:
@ -689,5 +846,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.0.5 <4.0.0"
flutter: ">=3.7.0-0"
dart: ">=3.1.0 <4.0.0"
flutter: ">=3.13.0"

View File

@ -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
# 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.
version: 1.0.0+1
version: 1.0.2+1
environment:
sdk: '>=3.0.5 <4.0.0'
@ -36,6 +36,7 @@ dependencies:
epub_view: ^3.2.0
flutter_pdfview: ^1.2.7
vocsy_epub_viewer: ^2.0.0
# syncfusion_flutter_pdfviewer: ^22.2.5
# pdfx: ^2.4.0
@ -44,11 +45,16 @@ dependencies:
sqflite: ^2.3.0
path_provider: ^2.0.15
permission_handler: ^10.4.3
open_file: ^3.3.2
flutter_svg: ^2.0.7
google_fonts: ^5.1.0
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.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2

View File

@ -6,6 +6,12 @@
#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) {
PermissionHandlerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
}

View File

@ -3,6 +3,8 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
permission_handler_windows
url_launcher_windows
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST