Compare commits
20 Commits
v1.0.3-bet
...
v1.0.5-bet
Author | SHA1 | Date | |
---|---|---|---|
4c557ed28d | |||
61a4e566df | |||
2a2e5df118 | |||
aac2e807f0 | |||
95288271fa | |||
73a294fb89 | |||
c068714e52 | |||
5fa66ba42f | |||
034c3aaa5e | |||
c7ed1a3c4a | |||
7d550ea399 | |||
dfc70cfce0 | |||
1aedffc919 | |||
7364f69b60 | |||
a342f80fee | |||
3d56cd2c65 | |||
74793e5d65 | |||
88c1612184 | |||
2924020eb7 | |||
3bda1a7284 |
28
README.md
@ -1,16 +1,25 @@
|
||||
<p align="center"><img src="assets/icons/appIcon.png" width="150"></p>
|
||||
<h1 align="center"><b>Openlib</b></h1>
|
||||
<div align="center">
|
||||
|
||||
<img src="assets/icons/appIcon.png" width="150">
|
||||
|
||||
# Openlib
|
||||
|
||||
#### 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/)
|
||||
[](https://github.com/dstark5/Openlib/releases)
|
||||
|
||||
[<img src="github_releases.png"
|
||||
alt="Download from GitHub"
|
||||
alt="Get it on GitHub"
|
||||
height="60">](https://github.com/dstark5/Openlib/releases) [<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png"
|
||||
alt="Get it on IzzyDroid"
|
||||
height="60">](https://android.izzysoft.de/repo/apk/com.app.openlib)
|
||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||
alt="Get it on F-Droid"
|
||||
height="60">](https://f-droid.org/en/packages/com.app.openlib/)
|
||||
|
||||
</div>
|
||||
|
||||
## Note
|
||||
|
||||
@ -18,11 +27,6 @@
|
||||
|
||||
#### Publishing Openlib, Or Any Fork Of It In The Google Play Store Violates Their Terms And Conditions.
|
||||
|
||||
## Download
|
||||
- Download and install APK from [GitHub Releases](https://github.com/dstark5/Openlib/releases).
|
||||
- Download and install APK from [ IzzyOnDroid ](https://android.izzysoft.de/repo/apk/com.app.openlib).
|
||||
|
||||
|
||||
## Screenshots
|
||||
|
||||
[<img src="screenshots/Screenshot_1.png" width=160>](screenshots/Screenshot_1.png)
|
||||
@ -35,11 +39,13 @@
|
||||
[<img src="screenshots/Screenshot_8.png" width=160>](screenshots/Screenshot_8.png)
|
||||
|
||||
## Description
|
||||
|
||||
##### Openlib Is An Open Source App To Download And Read Books From Shadow Library ([Anna’s Archive](https://annas-archive.org/)). The App Has Built In Reader to Read Books.
|
||||
|
||||
##### As [Anna’s Archive](https://annas-archive.org/) Doesn't Have An API. The App Works By Sending Request To Anna’s Archive And Parses The Response To objects. The App Extracts The Mirrors From Response And Downloads The Book.
|
||||
|
||||
## Features
|
||||
|
||||
- Trending Books
|
||||
- Download And Read Books With In-Built Viewer
|
||||
- Supports Epub And Pdf Formats
|
||||
@ -78,6 +84,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 See [CONTRIBUTING.md](./CONTRIBUTING.md) for the guidelines.
|
||||
@ -87,10 +94,13 @@ If you'd like to get involved See [CONTRIBUTING.md](./CONTRIBUTING.md) for the g
|
||||
Please report bugs via the [issue tracker](https://github.com/dstark5/Openlib/issues).
|
||||
|
||||
## Donate
|
||||
|
||||
If you like Openlib, you're welcome to send a donation.
|
||||
|
||||
#### [Donate To Anna’s Archive](https://annas-archive.org/donate?tier=1).
|
||||
|
||||
## License
|
||||
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
Openlib is a free software licensed under GPL v3.0 It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. [GNU General Public License](https://www.gnu.org/licenses/gpl.html) as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
@ -24,7 +24,6 @@
|
||||
android:label="Openlib"
|
||||
android:name="${applicationName}"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:icon="@mipmap/launcher_icon">
|
||||
|
||||
|
32
android/app/src/main/res/raw/annas_archive
Normal file
@ -0,0 +1,32 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFfTCCBGWgAwIBAgIRAI0YQRVveHeTEYLPgc2CDXowDQYJKoZIhvcNAQELBQAw
|
||||
RjELMAkGA1UEBhMCVVMxIjAgBgNVBAoTGUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBM
|
||||
TEMxEzARBgNVBAMTCkdUUyBDQSAxUDUwHhcNMjMxMDMwMjMwOTExWhcNMjQwMTI4
|
||||
MjMwOTEwWjAcMRowGAYDVQQDExFhbm5hcy1hcmNoaXZlLm9yZzCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBAKl79Oj7GW10c1ikBC/sSkyr2tmmIl1/iszu
|
||||
9DN5w3lbX3q5hLeSB2xPaW6FWPB0u+YR8tgXyk6jG8jkzSe2cdkW0pjKaxSNiQgW
|
||||
rXipoonUbaceSDd3aFQFGhqe0urkM+84Sgspy39REdxXuQeL2hXH8fouRPA65/pn
|
||||
2nipwkpZHOezEQfE7BbUYwt4/YQaWXD3ScBLNx0PJuZdL4sfVC41IP8Ml/i5zzU7
|
||||
mupl6EGgw5IuXwyHN1AC1NHQBU5/8X062/NdVhW/letbsR52Z6DJ727+nWLpdwq4
|
||||
WgowHui6PthI6h+F4LCu+g3V5akAibsNffqVyWssxaMWFXjMuDECAwEAAaOCAo4w
|
||||
ggKKMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMB
|
||||
Af8EAjAAMB0GA1UdDgQWBBSIWJPHr1GutuUbnUApJ/vU3TQP9DAfBgNVHSMEGDAW
|
||||
gBTV/J4N3x7K3QiXl24rxV/FK/XsuDB4BggrBgEFBQcBAQRsMGowNQYIKwYBBQUH
|
||||
MAGGKWh0dHA6Ly9vY3NwLnBraS5nb29nL3MvZ3RzMXA1L1VfN25sRDJPX1JRMDEG
|
||||
CCsGAQUFBzAChiVodHRwOi8vcGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxcDUuZGVy
|
||||
MDEGA1UdEQQqMCiCEWFubmFzLWFyY2hpdmUub3JnghMqLmFubmFzLWFyY2hpdmUu
|
||||
b3JnMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYDVR0fBDUw
|
||||
MzAxoC+gLYYraHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMXA1L19ZUS1xNlF1bEJB
|
||||
LmNybDCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB2AHb/iD8KtvuVUcJhzPWHujS0
|
||||
pM27KdxoQgqf5mdMWjp0AAABi4MQGPAAAAQDAEcwRQIhALVAeepoK0WtUPs01yzZ
|
||||
XjAkdE7WYGw2QNzSkvywFRoIAiAnp1Lec4PqwGPbg/ppC8PgGxb8+yvSlVT0ChUt
|
||||
NMinWgB3ANq2v2s/tbYin5vCu1xr6HCRcWy7UYSFNL2kPTBI1/urAAABi4MQGP0A
|
||||
AAQDAEgwRgIhAKbAEYr9qDmiafcnkXIG7xObbI4fz3IsLSht8etA/jSlAiEAkQ7G
|
||||
t6x81Onpl4RcTtrXLptI0fDkrAZ66hAPWbIH8SAwDQYJKoZIhvcNAQELBQADggEB
|
||||
AGfvZYtIOPKRvVyfI4tJpetCJmU/DEMbCIyX05M+2P1n2uY1D4tweAMmYf4trh5Z
|
||||
cuTK3QDeoICus3WK08L3Ni/699QbQ0uonp0IIIOi2NlP2rLhvtETWpmLoX6jM55W
|
||||
cYGiQldhCgWYEXoANrJshUbjkyM81QMNzSrn33JPkzWUdgVoS/KfABaeymLekXO4
|
||||
ndLp4ktLlYQZr3JJU39FvwgN8IcmeLWUnpSWsekH+nHSW9e8vOsNQoZyHw0minqz
|
||||
ZzFbS10reX1kG56+AxDf5fOOM+C+MAozSUnXUjrkpXXakwUooMTklKtYbBiwR2R0
|
||||
wrcYmVHymn07AUliDOalu2I=
|
||||
-----END CERTIFICATE-----
|
17
android/app/src/main/res/xml/network_security_config.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<base-config cleartextTrafficPermitted="false">
|
||||
<trust-anchors>
|
||||
<certificates src="@raw/annas_archive"/>
|
||||
<certificates src="system"/>
|
||||
</trust-anchors>
|
||||
</base-config>
|
||||
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain includeSubdomains="true">secure.example.com</domain>
|
||||
<domain includeSubdomains="true">127.0.0.1</domain>
|
||||
</domain-config>
|
||||
<domain-config cleartextTrafficPermitted="false">
|
||||
<domain includeSubdomains="true">annas-archive.org</domain>
|
||||
</domain-config>
|
||||
</network-security-config>
|
@ -1,10 +1,14 @@
|
||||
<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.
|
||||
<b><i>Openlib</i></b> 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>
|
||||
<p>
|
||||
<b>Note :</b>
|
||||
The app requires VPN to function properly . Without VPN the might show the captcha required page even after completing the captcha
|
||||
</p>
|
||||
<b><p>Main Features:</p></b>
|
||||
<ul>
|
||||
<li>Trending Books</li>
|
||||
<li>Download And Read Books With In-Built Viewer</li>
|
||||
|
Before Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 447 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 271 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 28 KiB |
@ -76,7 +76,7 @@ class MyApp extends ConsumerWidget {
|
||||
builder: (BuildContext context, Widget? child) {
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
textScaleFactor: 1.0,
|
||||
textScaler: const TextScaler.linear(1.0),
|
||||
),
|
||||
child: child!,
|
||||
);
|
||||
@ -114,7 +114,7 @@ class _HomePageState extends ConsumerState<HomePage> {
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
backgroundColor: Theme.of(context).colorScheme.background,
|
||||
title: const Text("Openlib"),
|
||||
titleTextStyle: Theme.of(context).textTheme.displayLarge,
|
||||
),
|
||||
|
@ -28,24 +28,16 @@ class BookInfoData extends BookData {
|
||||
final String? format;
|
||||
|
||||
BookInfoData(
|
||||
{required String title,
|
||||
required String? author,
|
||||
required String? thumbnail,
|
||||
required String? publisher,
|
||||
required String? info,
|
||||
required String link,
|
||||
required String md5,
|
||||
{required super.title,
|
||||
required super.author,
|
||||
required super.thumbnail,
|
||||
required super.publisher,
|
||||
required super.info,
|
||||
required super.link,
|
||||
required super.md5,
|
||||
required this.mirrors,
|
||||
required this.format,
|
||||
required this.description})
|
||||
: super(
|
||||
title: title,
|
||||
author: author,
|
||||
thumbnail: thumbnail,
|
||||
publisher: publisher,
|
||||
info: info,
|
||||
link: link,
|
||||
md5: md5);
|
||||
required this.description});
|
||||
}
|
||||
|
||||
class AnnasArchieve {
|
||||
@ -66,8 +58,7 @@ class AnnasArchieve {
|
||||
List<BookData> _parser(resData, String fileType) {
|
||||
var document =
|
||||
parse(resData.toString().replaceAll(RegExp(r"<!--|-->"), ''));
|
||||
var books = document.querySelectorAll(
|
||||
'a[class="js-vim-focus custom-a flex items-center relative left-[-10px] w-[calc(100%+20px)] px-[10px] outline-offset-[-2px] outline-2 rounded-[3px] hover:bg-[#00000011] focus:outline "]');
|
||||
var books = document.querySelectorAll('a');
|
||||
|
||||
List<BookData> bookList = [];
|
||||
|
||||
@ -246,18 +237,39 @@ class AnnasArchieve {
|
||||
}
|
||||
}
|
||||
|
||||
String urlEncoder(
|
||||
{required String searchQuery,
|
||||
required String content,
|
||||
required String sort,
|
||||
required String fileType,
|
||||
required bool enableFilters}) {
|
||||
searchQuery = searchQuery.replaceAll(" ", "+");
|
||||
if (enableFilters == false) return '$baseUrl/search?q=$searchQuery';
|
||||
if (content == "" && sort == "" && fileType == "") {
|
||||
return '$baseUrl/search?q=$searchQuery';
|
||||
}
|
||||
return '$baseUrl/search?index=&q=$searchQuery&content=$content&ext=$fileType&sort=$sort';
|
||||
}
|
||||
|
||||
Future<List<BookData>> searchBooks(
|
||||
{required String searchQuery,
|
||||
String content = "",
|
||||
String sort = "",
|
||||
String fileType = ""}) async {
|
||||
String fileType = "",
|
||||
bool enableFilters = true}) async {
|
||||
try {
|
||||
final String encodedURL = content == ""
|
||||
? '$baseUrl/search?index=&q=$searchQuery&ext=$fileType&sort=$sort'
|
||||
: '$baseUrl/search?index=&q=$searchQuery&content=$content&ext=$fileType&sort=$sort';
|
||||
final String encodedURL = urlEncoder(
|
||||
searchQuery: searchQuery,
|
||||
content: content,
|
||||
sort: sort,
|
||||
fileType: fileType,
|
||||
enableFilters: enableFilters);
|
||||
|
||||
final response = await dio.get(encodedURL,
|
||||
options: Options(headers: defaultDioHeaders));
|
||||
if (!enableFilters) {
|
||||
return _parser(response.data, "");
|
||||
}
|
||||
return _parser(response.data, fileType);
|
||||
} on DioException catch (e) {
|
||||
if (e.type == DioExceptionType.unknown) {
|
||||
|
@ -1,3 +1,5 @@
|
||||
import 'dart:io';
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'files.dart';
|
||||
|
||||
@ -23,15 +25,17 @@ List<String> _reorderMirrors(List<String> mirrors) {
|
||||
return [...ipfsMirrors, ...httpsMirrors];
|
||||
}
|
||||
|
||||
Future<String?> _getAliveMirror(List<String> mirrors, Dio dio) async {
|
||||
Future<String?> _getAliveMirror(List<String> mirrors) async {
|
||||
Dio dio = Dio();
|
||||
for (var url in mirrors) {
|
||||
try {
|
||||
final response = await dio.head(url,
|
||||
options: Options(receiveTimeout: const Duration(seconds: 5)));
|
||||
options: Options(receiveTimeout: const Duration(seconds: 10)));
|
||||
if (response.statusCode == 200) {
|
||||
dio.close();
|
||||
return url;
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (_) {
|
||||
// print("timeOut");
|
||||
}
|
||||
}
|
||||
@ -42,16 +46,20 @@ Future<void> downloadFile(
|
||||
{required List<String> mirrors,
|
||||
required String md5,
|
||||
required String format,
|
||||
required Function onStart,
|
||||
required Function onProgress,
|
||||
required Function cancelDownlaod,
|
||||
required Function mirrorStatus,
|
||||
required Function onDownlaodFailed}) async {
|
||||
if (mirrors.isEmpty) {
|
||||
onDownlaodFailed('No mirrors available!');
|
||||
} else {
|
||||
Dio dio = Dio();
|
||||
|
||||
String path = await _getFilePath('$md5.$format');
|
||||
List<String> orderedMirrors = _reorderMirrors(mirrors);
|
||||
|
||||
String? workingMirror = await _getAliveMirror(orderedMirrors, dio);
|
||||
String? workingMirror = await _getAliveMirror(orderedMirrors);
|
||||
|
||||
// print(workingMirror);
|
||||
// print(path);
|
||||
@ -59,9 +67,9 @@ Future<void> downloadFile(
|
||||
// print(orderedMirrors[0]);
|
||||
|
||||
if (workingMirror != null) {
|
||||
onStart();
|
||||
try {
|
||||
CancelToken cancelToken = CancelToken();
|
||||
|
||||
dio.download(
|
||||
workingMirror,
|
||||
path,
|
||||
@ -71,13 +79,16 @@ Future<void> downloadFile(
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
|
||||
}),
|
||||
onReceiveProgress: (rcv, total) {
|
||||
if (!(rcv.isNaN || rcv.isInfinite) &&
|
||||
!(total.isNaN || total.isInfinite)) {
|
||||
onProgress(rcv, total);
|
||||
}
|
||||
},
|
||||
deleteOnError: true,
|
||||
cancelToken: cancelToken,
|
||||
).catchError((err) {
|
||||
if (err.type != DioExceptionType.cancel) {
|
||||
onDownlaodFailed();
|
||||
onDownlaodFailed('downloaded Failed! try again...');
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
@ -85,10 +96,28 @@ Future<void> downloadFile(
|
||||
mirrorStatus(true);
|
||||
|
||||
cancelDownlaod(cancelToken);
|
||||
} catch (e) {
|
||||
onDownlaodFailed();
|
||||
} catch (_) {
|
||||
onDownlaodFailed('downloaded Failed! try again...');
|
||||
}
|
||||
} else {
|
||||
onDownlaodFailed();
|
||||
onDownlaodFailed('No working mirrors available to download book!');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> verifyFileCheckSum(
|
||||
{required String md5Hash, required String format}) async {
|
||||
try {
|
||||
final path = await getAppDirectoryPath;
|
||||
final filePath = '$path/$md5Hash.$format';
|
||||
final file = File(filePath);
|
||||
final stream = file.openRead();
|
||||
final hash = await md5.bind(stream).first;
|
||||
if (md5Hash == hash.toString()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -52,3 +52,99 @@ class OpenLibrary {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GoodReads {
|
||||
String url = "https://www.goodreads.com/shelf/show/trending";
|
||||
|
||||
List<TrendingBookData> _parser(data) {
|
||||
var document = parse(data.toString());
|
||||
var bookList = document.querySelectorAll('div[class="elementList"]');
|
||||
List<TrendingBookData> trendingBooks = [];
|
||||
for (var element in bookList) {
|
||||
if (element
|
||||
.querySelector('a[class="leftAlignedImage"]')
|
||||
?.attributes['title'] !=
|
||||
null &&
|
||||
element.querySelector('img')?.attributes['src'] != null) {
|
||||
String? thumbnail = element.querySelector('img')?.attributes['src'];
|
||||
trendingBooks.add(
|
||||
TrendingBookData(
|
||||
title: element
|
||||
.querySelector('a[class="leftAlignedImage"]')
|
||||
?.attributes['title']
|
||||
.toString()
|
||||
.trim(),
|
||||
thumbnail: thumbnail
|
||||
.toString()
|
||||
.replaceAll("._SY75_.", "._SY225_.")
|
||||
.replaceAll("._SX50_.", "._SX148_.")),
|
||||
);
|
||||
}
|
||||
}
|
||||
return trendingBooks;
|
||||
}
|
||||
|
||||
Future<List<TrendingBookData>> trendingBooks() async {
|
||||
try {
|
||||
final dio = Dio();
|
||||
final response = await dio.get(url,
|
||||
options: Options(
|
||||
sendTimeout: const Duration(seconds: 20),
|
||||
receiveTimeout: const Duration(seconds: 20)));
|
||||
return _parser(response.data.toString());
|
||||
} on DioException catch (e) {
|
||||
if (e.type == DioExceptionType.unknown) {
|
||||
throw "socketException";
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PenguinRandomHouse {
|
||||
String url =
|
||||
"https://www.penguinrandomhouse.com/ajaxc/categories/books/?from=0&to=50&contentId=&elClass=book&dataType=html&catFilter=best-sellers";
|
||||
|
||||
List<TrendingBookData> _parser(data) {
|
||||
var document = parse(data.toString());
|
||||
var bookList = document.querySelectorAll('div[class="book"]');
|
||||
List<TrendingBookData> trendingBooks = [];
|
||||
for (var element in bookList) {
|
||||
if (element.querySelector('div[class="title"]')?.text != null &&
|
||||
element
|
||||
.querySelector('img[class="responsive_img"]')
|
||||
?.attributes['src'] !=
|
||||
null) {
|
||||
String? thumbnail = element
|
||||
.querySelector('img[class="responsive_img"]')
|
||||
?.attributes['src'];
|
||||
trendingBooks.add(
|
||||
TrendingBookData(
|
||||
title: element
|
||||
.querySelector('div[class="title"]')
|
||||
?.text
|
||||
.toString()
|
||||
.trim(),
|
||||
thumbnail: thumbnail.toString()),
|
||||
);
|
||||
}
|
||||
}
|
||||
return trendingBooks;
|
||||
}
|
||||
|
||||
Future<List<TrendingBookData>> trendingBooks() async {
|
||||
try {
|
||||
final dio = Dio();
|
||||
final response = await dio.get(url,
|
||||
options: Options(
|
||||
sendTimeout: const Duration(seconds: 20),
|
||||
receiveTimeout: const Duration(seconds: 20)));
|
||||
return _parser(response.data.toString());
|
||||
} on DioException catch (e) {
|
||||
if (e.type == DioExceptionType.unknown) {
|
||||
throw "socketException";
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,9 +65,22 @@ final searchQueryProvider = StateProvider<String>((ref) => "");
|
||||
|
||||
final getTrendingBooks = FutureProvider<List<TrendingBookData>>((ref) async {
|
||||
OpenLibrary openLibrary = OpenLibrary();
|
||||
return await openLibrary.trendingBooks();
|
||||
GoodReads goodReads = GoodReads();
|
||||
PenguinRandomHouse penguinTrending = PenguinRandomHouse();
|
||||
List<TrendingBookData> trendingBooks =
|
||||
await Future.wait<List<TrendingBookData>>([
|
||||
openLibrary.trendingBooks(),
|
||||
goodReads.trendingBooks(),
|
||||
penguinTrending.trendingBooks()
|
||||
]).then((List<List<TrendingBookData>> listOfData) =>
|
||||
listOfData.expand((element) => element).toList());
|
||||
|
||||
trendingBooks.shuffle();
|
||||
return trendingBooks;
|
||||
});
|
||||
|
||||
final enableFiltersState = StateProvider<bool>((ref) => true);
|
||||
|
||||
//Provider for Trending Books
|
||||
final searchProvider = FutureProvider.family
|
||||
.autoDispose<List<BookData>, String>((ref, searchQuery) async {
|
||||
@ -76,7 +89,8 @@ final searchProvider = FutureProvider.family
|
||||
searchQuery: searchQuery,
|
||||
content: ref.watch(getTypeValue),
|
||||
sort: ref.watch(getSortValue),
|
||||
fileType: ref.watch(getFileTypeValue));
|
||||
fileType: ref.watch(getFileTypeValue),
|
||||
enableFilters: ref.watch(enableFiltersState));
|
||||
return data;
|
||||
});
|
||||
|
||||
@ -122,6 +136,15 @@ final cancelCurrentDownload = StateProvider<CancelToken>((ref) {
|
||||
return CancelToken();
|
||||
});
|
||||
|
||||
enum ProcessState { waiting, running, complete }
|
||||
|
||||
enum CheckSumProcessState { waiting, running, failed, success }
|
||||
|
||||
final downloadState =
|
||||
StateProvider.autoDispose<ProcessState>((ref) => ProcessState.waiting);
|
||||
final checkSumState = StateProvider.autoDispose<CheckSumProcessState>(
|
||||
(ref) => CheckSumProcessState.waiting);
|
||||
|
||||
final dbProvider = Provider<MyLibraryDb>((ref) => throw UnimplementedError());
|
||||
|
||||
final myLibraryProvider = FutureProvider((ref) async {
|
||||
|
@ -5,13 +5,13 @@ 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);
|
||||
const AboutPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
backgroundColor: Theme.of(context).colorScheme.background,
|
||||
title: const Text("Openlib"),
|
||||
titleTextStyle: Theme.of(context).textTheme.displayLarge,
|
||||
),
|
||||
@ -43,7 +43,7 @@ class AboutPage extends StatelessWidget {
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 7, right: 7, top: 5),
|
||||
child: Text(
|
||||
"1.0.3",
|
||||
"1.0.5",
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.bold,
|
||||
@ -87,8 +87,7 @@ class AboutPage extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _UrlText extends StatelessWidget {
|
||||
const _UrlText({Key? key, required this.text, required this.url})
|
||||
: super(key: key);
|
||||
const _UrlText({required this.text, required this.url});
|
||||
|
||||
final String url;
|
||||
final String text;
|
||||
|
@ -1,8 +1,8 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:dio/dio.dart' show CancelToken;
|
||||
|
||||
import 'package:openlib/services/database.dart';
|
||||
import 'package:openlib/ui/components/error_widget.dart';
|
||||
@ -18,9 +18,14 @@ import 'package:openlib/state/state.dart'
|
||||
getDownloadedFileSize,
|
||||
cancelCurrentDownload,
|
||||
mirrorStatusProvider,
|
||||
ProcessState,
|
||||
CheckSumProcessState,
|
||||
downloadState,
|
||||
checkSumState,
|
||||
dbProvider,
|
||||
checkIdExists,
|
||||
myLibraryProvider;
|
||||
|
||||
import 'package:openlib/ui/components/book_info_widget.dart';
|
||||
import 'package:openlib/ui/components/file_buttons_widget.dart';
|
||||
import 'package:openlib/ui/components/snack_bar_widget.dart';
|
||||
@ -28,7 +33,7 @@ import 'package:flutter_svg/svg.dart';
|
||||
import 'package:openlib/ui/webview_page.dart';
|
||||
|
||||
class BookInfoPage extends ConsumerWidget {
|
||||
const BookInfoPage({Key? key, required this.url}) : super(key: key);
|
||||
const BookInfoPage({super.key, required this.url});
|
||||
|
||||
final String url;
|
||||
|
||||
@ -37,7 +42,7 @@ class BookInfoPage extends ConsumerWidget {
|
||||
final bookInfo = ref.watch(bookInfoProvider(url));
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
backgroundColor: Theme.of(context).colorScheme.background,
|
||||
title: const Text("Openlib"),
|
||||
titleTextStyle: Theme.of(context).textTheme.displayLarge,
|
||||
),
|
||||
@ -141,6 +146,7 @@ class BookInfoPage extends ConsumerWidget {
|
||||
height: 25,
|
||||
child: CircularProgressIndicator(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
strokeCap: StrokeCap.round,
|
||||
),
|
||||
));
|
||||
},
|
||||
@ -203,6 +209,7 @@ class _ActionButtonWidgetState extends ConsumerState<ActionButtonWidget> {
|
||||
loading: () {
|
||||
return CircularProgressIndicator(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
strokeCap: StrokeCap.round,
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -211,16 +218,27 @@ class _ActionButtonWidgetState extends ConsumerState<ActionButtonWidget> {
|
||||
|
||||
Future<void> downloadFileWidget(
|
||||
WidgetRef ref, BuildContext context, dynamic data) async {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return _ShowDialog(title: data.title);
|
||||
});
|
||||
|
||||
downloadFile(
|
||||
mirrors: data.mirrors!,
|
||||
md5: data.md5,
|
||||
format: data.format!,
|
||||
onStart: () {
|
||||
ref.read(downloadState.notifier).state = ProcessState.running;
|
||||
},
|
||||
onProgress: (int rcv, int total) async {
|
||||
if (ref.read(totalFileSizeInBytes) != total) {
|
||||
ref.read(totalFileSizeInBytes.notifier).state = total;
|
||||
}
|
||||
ref.read(downloadedFileSizeInBytes.notifier).state = rcv;
|
||||
ref.read(downloadProgressProvider.notifier).state = rcv / total;
|
||||
|
||||
if (rcv / total == 1.0) {
|
||||
await ref.read(dbProvider).insert(MyBook(
|
||||
id: data.md5,
|
||||
@ -233,6 +251,23 @@ Future<void> downloadFileWidget(
|
||||
format: data.format,
|
||||
description: data.description));
|
||||
|
||||
ref.read(downloadState.notifier).state = ProcessState.complete;
|
||||
ref.read(checkSumState.notifier).state = CheckSumProcessState.running;
|
||||
|
||||
try {
|
||||
final checkSum = await verifyFileCheckSum(
|
||||
md5Hash: data.md5, format: data.format);
|
||||
if (checkSum == true) {
|
||||
ref.read(checkSumState.notifier).state =
|
||||
CheckSumProcessState.success;
|
||||
} else {
|
||||
ref.read(checkSumState.notifier).state =
|
||||
CheckSumProcessState.failed;
|
||||
}
|
||||
} catch (_) {
|
||||
ref.read(checkSumState.notifier).state =
|
||||
CheckSumProcessState.failed;
|
||||
}
|
||||
// ignore: unused_result
|
||||
ref.refresh(checkIdExists(data.md5));
|
||||
// ignore: unused_result
|
||||
@ -247,17 +282,9 @@ Future<void> downloadFileWidget(
|
||||
mirrorStatus: (val) {
|
||||
ref.read(mirrorStatusProvider.notifier).state = val;
|
||||
},
|
||||
onDownlaodFailed: () {
|
||||
onDownlaodFailed: (msg) {
|
||||
Navigator.of(context).pop();
|
||||
showSnackBar(
|
||||
context: context, message: 'downloaded Failed! try again...');
|
||||
});
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return _ShowDialog(title: data.title);
|
||||
showSnackBar(context: context, message: msg.toString());
|
||||
});
|
||||
}
|
||||
|
||||
@ -272,9 +299,18 @@ class _ShowDialog extends ConsumerWidget {
|
||||
final fileSize = ref.watch(getTotalFileSize);
|
||||
final downloadedFileSize = ref.watch(getDownloadedFileSize);
|
||||
final mirrorStatus = ref.watch(mirrorStatusProvider);
|
||||
final downloadProcessState = ref.watch(downloadState);
|
||||
final checkSumVerifyState = ref.watch(checkSumState);
|
||||
|
||||
if (downloadProgress == 1.0) {
|
||||
if (downloadProgress == 1.0 &&
|
||||
(checkSumVerifyState == CheckSumProcessState.failed ||
|
||||
checkSumVerifyState == CheckSumProcessState.success)) {
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
Navigator.of(context).pop();
|
||||
if (checkSumVerifyState == CheckSumProcessState.failed) {
|
||||
_showWarningFileDialog(context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Stack(
|
||||
@ -284,7 +320,7 @@ class _ShowDialog extends ConsumerWidget {
|
||||
padding: const EdgeInsets.all(15.0),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 285,
|
||||
height: 345,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
color: Theme.of(context).colorScheme.tertiaryContainer,
|
||||
@ -341,6 +377,7 @@ class _ShowDialog extends ConsumerWidget {
|
||||
color:
|
||||
Theme.of(context).colorScheme.secondary,
|
||||
strokeWidth: 2.5,
|
||||
strokeCap: StrokeCap.round,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
@ -362,6 +399,109 @@ class _ShowDialog extends ConsumerWidget {
|
||||
),
|
||||
]),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
switch (downloadProcessState) {
|
||||
ProcessState.waiting => Icon(
|
||||
Icons.timer_sharp,
|
||||
size: 15,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.tertiary
|
||||
.withAlpha(140),
|
||||
),
|
||||
ProcessState.running => SizedBox(
|
||||
width: 9,
|
||||
height: 9,
|
||||
child: CircularProgressIndicator(
|
||||
color:
|
||||
Theme.of(context).colorScheme.secondary,
|
||||
strokeWidth: 2.5,
|
||||
strokeCap: StrokeCap.round,
|
||||
),
|
||||
),
|
||||
ProcessState.complete => const Icon(
|
||||
Icons.check_circle,
|
||||
size: 15,
|
||||
color: Colors.green,
|
||||
),
|
||||
},
|
||||
const SizedBox(
|
||||
width: 3,
|
||||
),
|
||||
Text(
|
||||
"Downloading",
|
||||
style: TextStyle(
|
||||
fontSize: 11.5,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.tertiary
|
||||
.withAlpha(140),
|
||||
decoration: TextDecoration.none),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 2,
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
]),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
switch (checkSumVerifyState) {
|
||||
CheckSumProcessState.waiting => Icon(
|
||||
Icons.timer_sharp,
|
||||
size: 15,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.tertiary
|
||||
.withAlpha(140),
|
||||
),
|
||||
CheckSumProcessState.running => SizedBox(
|
||||
width: 9,
|
||||
height: 9,
|
||||
child: CircularProgressIndicator(
|
||||
color:
|
||||
Theme.of(context).colorScheme.secondary,
|
||||
strokeWidth: 2.5,
|
||||
strokeCap: StrokeCap.round,
|
||||
),
|
||||
),
|
||||
CheckSumProcessState.failed => const Icon(
|
||||
Icons.close,
|
||||
size: 15,
|
||||
color: Colors.red,
|
||||
),
|
||||
CheckSumProcessState.success => const Icon(
|
||||
Icons.check_circle,
|
||||
size: 15,
|
||||
color: Colors.green,
|
||||
),
|
||||
},
|
||||
const SizedBox(
|
||||
width: 3,
|
||||
),
|
||||
Text(
|
||||
"Verifying file checksum",
|
||||
style: TextStyle(
|
||||
fontSize: 11.5,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.tertiary
|
||||
.withAlpha(140),
|
||||
decoration: TextDecoration.none),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 2,
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
]),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
@ -432,3 +572,52 @@ class _ShowDialog extends ConsumerWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showWarningFileDialog(BuildContext context) async {
|
||||
return showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
'Checksum failed!',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
decoration: TextDecoration.none,
|
||||
letterSpacing: 1),
|
||||
),
|
||||
content: SingleChildScrollView(
|
||||
child: ListBody(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'The downloaded book may be malicious. Delete it and get the same book from another source, or use the book at your own risk.',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.tertiary.withAlpha(170),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
child: Text(
|
||||
'Okay',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
decoration: TextDecoration.none,
|
||||
letterSpacing: 1),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -16,15 +16,14 @@ String? getFileType(String? info) {
|
||||
|
||||
class BookInfoCard extends StatelessWidget {
|
||||
const BookInfoCard(
|
||||
{Key? key,
|
||||
{super.key,
|
||||
required this.title,
|
||||
required this.author,
|
||||
required this.publisher,
|
||||
required this.thumbnail,
|
||||
required this.info,
|
||||
required this.link,
|
||||
required this.onClick})
|
||||
: super(key: key);
|
||||
required this.onClick});
|
||||
|
||||
final String title;
|
||||
final String author;
|
||||
|
@ -5,8 +5,7 @@ class BookInfoWidget extends StatelessWidget {
|
||||
final Widget child;
|
||||
final dynamic data;
|
||||
|
||||
const BookInfoWidget({Key? key, required this.child, required this.data})
|
||||
: super(key: key);
|
||||
const BookInfoWidget({super.key, required this.child, required this.data});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -145,9 +144,7 @@ class _TopPaddedText extends StatelessWidget {
|
||||
required this.fontSize,
|
||||
required this.topPadding,
|
||||
required this.color,
|
||||
required this.maxLines,
|
||||
Key? key})
|
||||
: super(key: key);
|
||||
required this.maxLines});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -9,8 +9,10 @@ class CustomErrorWidget extends StatelessWidget {
|
||||
VoidCallback? onRefresh;
|
||||
|
||||
CustomErrorWidget(
|
||||
{Key? key, required this.error, required this.stackTrace, this.onRefresh})
|
||||
: super(key: key);
|
||||
{super.key,
|
||||
required this.error,
|
||||
required this.stackTrace,
|
||||
this.onRefresh});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -14,11 +14,10 @@ class FileOpenAndDeleteButtons extends ConsumerWidget {
|
||||
final Function onDelete;
|
||||
|
||||
const FileOpenAndDeleteButtons(
|
||||
{Key? key,
|
||||
{super.key,
|
||||
required this.id,
|
||||
required this.format,
|
||||
required this.onDelete})
|
||||
: super(key: key);
|
||||
required this.onDelete});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
@ -109,8 +109,7 @@ class _EpubViewState extends ConsumerState<EpubViewerWidget> {
|
||||
}
|
||||
|
||||
class EpubViewer extends ConsumerStatefulWidget {
|
||||
const EpubViewer({Key? key, required this.filePath, required this.fileName})
|
||||
: super(key: key);
|
||||
const EpubViewer({super.key, required this.filePath, required this.fileName});
|
||||
|
||||
final String filePath;
|
||||
final String fileName;
|
||||
|
@ -7,7 +7,7 @@ import 'package:openlib/ui/components/book_info_widget.dart';
|
||||
import 'package:openlib/ui/components/file_buttons_widget.dart';
|
||||
|
||||
class BookPage extends StatelessWidget {
|
||||
const BookPage({Key? key, required this.id}) : super(key: key);
|
||||
const BookPage({super.key, required this.id});
|
||||
|
||||
final String id;
|
||||
|
||||
@ -15,7 +15,7 @@ class BookPage extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
backgroundColor: Theme.of(context).colorScheme.background,
|
||||
title: const Text("Openlib"),
|
||||
titleTextStyle: Theme.of(context).textTheme.displayLarge,
|
||||
),
|
||||
|
@ -77,8 +77,7 @@ class _PdfViewState extends ConsumerState<PdfView> {
|
||||
}
|
||||
|
||||
class PdfViewer extends ConsumerStatefulWidget {
|
||||
const PdfViewer({Key? key, required this.filePath, required this.fileName})
|
||||
: super(key: key);
|
||||
const PdfViewer({super.key, required this.filePath, required this.fileName});
|
||||
|
||||
final String filePath;
|
||||
final String fileName;
|
||||
|
@ -10,10 +10,7 @@ import 'package:openlib/ui/components/book_card_widget.dart';
|
||||
import 'package:openlib/state/state.dart' show searchProvider;
|
||||
|
||||
class ResultPage extends ConsumerWidget {
|
||||
const ResultPage({
|
||||
super.key,
|
||||
required this.searchQuery,
|
||||
});
|
||||
const ResultPage({super.key, required this.searchQuery});
|
||||
|
||||
final String searchQuery;
|
||||
|
||||
@ -23,7 +20,7 @@ class ResultPage extends ConsumerWidget {
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
backgroundColor: Theme.of(context).colorScheme.background,
|
||||
title: const Text("Openlib"),
|
||||
titleTextStyle: Theme.of(context).textTheme.displayLarge,
|
||||
),
|
||||
@ -119,6 +116,7 @@ class ResultPage extends ConsumerWidget {
|
||||
height: 25,
|
||||
child: CircularProgressIndicator(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
strokeCap: StrokeCap.round,
|
||||
),
|
||||
))
|
||||
],
|
||||
|
@ -10,19 +10,19 @@ import 'package:openlib/state/state.dart'
|
||||
selectedFileTypeState,
|
||||
typeValues,
|
||||
fileType,
|
||||
sortValues;
|
||||
sortValues,
|
||||
enableFiltersState;
|
||||
import 'components/snack_bar_widget.dart';
|
||||
|
||||
class SearchPage extends ConsumerWidget {
|
||||
const SearchPage({Key? key}) : super(key: key);
|
||||
const SearchPage({super.key});
|
||||
|
||||
void onSubmit(BuildContext context, WidgetRef ref) {
|
||||
if (ref.read(searchQueryProvider).isNotEmpty) {
|
||||
ref.read(enableFiltersState.notifier).state = true;
|
||||
Navigator.push(context,
|
||||
MaterialPageRoute(builder: (BuildContext context) {
|
||||
return ResultPage(
|
||||
searchQuery: ref.read(searchQueryProvider),
|
||||
);
|
||||
return ResultPage(searchQuery: ref.read(searchQueryProvider));
|
||||
}));
|
||||
} else {
|
||||
showSnackBar(context: context, message: 'Search field is empty');
|
||||
|
@ -13,7 +13,7 @@ import 'package:openlib/state/state.dart'
|
||||
dbProvider;
|
||||
|
||||
class SettingsPage extends ConsumerWidget {
|
||||
const SettingsPage({Key? key}) : super(key: key);
|
||||
const SettingsPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@ -130,8 +130,7 @@ class SettingsPage extends ConsumerWidget {
|
||||
}
|
||||
|
||||
class _PaddedContainer extends StatelessWidget {
|
||||
const _PaddedContainer({Key? key, this.onClick, required this.children})
|
||||
: super(key: key);
|
||||
const _PaddedContainer({this.onClick, required this.children});
|
||||
|
||||
final VoidCallback? onClick;
|
||||
final List<Widget> children;
|
||||
|
@ -6,7 +6,8 @@ import 'extensions.dart';
|
||||
import 'package:openlib/ui/components/page_title_widget.dart';
|
||||
import 'package:openlib/ui/components/error_widget.dart';
|
||||
import 'package:openlib/ui/results_page.dart';
|
||||
import 'package:openlib/state/state.dart' show getTrendingBooks;
|
||||
import 'package:openlib/state/state.dart'
|
||||
show getTrendingBooks, enableFiltersState;
|
||||
|
||||
class TrendingPage extends ConsumerWidget {
|
||||
const TrendingPage({super.key});
|
||||
@ -42,11 +43,11 @@ class TrendingPage extends ConsumerWidget {
|
||||
(BuildContext context, int index) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
ref.read(enableFiltersState.notifier).state = false;
|
||||
Navigator.push(context, MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return ResultPage(
|
||||
searchQuery: data[index].title!,
|
||||
);
|
||||
searchQuery: data[index].title!);
|
||||
}));
|
||||
},
|
||||
child: SizedBox(
|
||||
@ -142,6 +143,7 @@ class TrendingPage extends ConsumerWidget {
|
||||
height: 25,
|
||||
child: CircularProgressIndicator(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
strokeCap: StrokeCap.round,
|
||||
),
|
||||
));
|
||||
});
|
||||
|
@ -8,7 +8,7 @@ import 'package:openlib/state/state.dart'
|
||||
show cookieProvider, userAgentProvider, dbProvider, bookInfoProvider;
|
||||
|
||||
class Webview extends ConsumerStatefulWidget {
|
||||
const Webview({Key? key, required this.url}) : super(key: key);
|
||||
const Webview({super.key, required this.url});
|
||||
final String url;
|
||||
@override
|
||||
// ignore: library_private_types_in_public_api
|
||||
|
258
pubspec.lock
@ -5,10 +5,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
sha256: "49b1fad315e57ab0bbc15bcbb874e83116a1d78f77ebd500a4af6c9407d6b28e"
|
||||
sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.3.8"
|
||||
version: "3.4.10"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -37,26 +37,26 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cached_network_image
|
||||
sha256: fd3d0dc1d451f9a252b32d95d3f0c3c487bc41a75eba2e6097cb0b9c71491b15
|
||||
sha256: f98972704692ba679db144261172a8e20feb145636c617af0eb4022132a6797f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.3"
|
||||
version: "3.3.0"
|
||||
cached_network_image_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cached_network_image_platform_interface
|
||||
sha256: bb2b8403b4ccdc60ef5f25c70dead1f3d32d24b9d6117cfc087f496b178594a7
|
||||
sha256: "56aa42a7a01e3c9db8456d9f3f999931f1e05535b5a424271e9a38cabf066613"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
version: "3.0.0"
|
||||
cached_network_image_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cached_network_image_web
|
||||
sha256: b8eb814ebfcb4dea049680f8c1ffb2df399e4d03bf7a352c775e26fa06e02fa0
|
||||
sha256: "759b9a9f8f6ccbb66c185df805fac107f05730b1dab9c64626d1008cca532257"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
version: "1.1.0"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -93,10 +93,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
|
||||
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.17.2"
|
||||
version: "1.18.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -106,7 +106,7 @@ packages:
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: crypto
|
||||
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
|
||||
@ -141,10 +141,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dio
|
||||
sha256: ce75a1b40947fea0a0e16ce73337122a86762e38b982e1ccb909daa3b9bc4197
|
||||
sha256: "797e1e341c3dd2f69f2dad42564a6feff3bfb87187d05abb93b9609e6f1645c3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.3.2"
|
||||
version: "5.4.0"
|
||||
epub_view:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -193,19 +193,19 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fixnum
|
||||
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_blurhash:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_blurhash
|
||||
sha256: "05001537bd3fac7644fa6558b09ec8c0a3f2eba78c0765f88912882b1331a5c6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.0"
|
||||
flutter_cache_manager:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -234,34 +234,34 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
|
||||
sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
version: "3.0.1"
|
||||
flutter_pdfview:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_pdfview
|
||||
sha256: d9735fd8991609910742a25c63a5f87060849e57e60112c677b802ddb64bed72
|
||||
sha256: a9055bf920c7095bf08c2781db431ba23577aa5da5a056a7152dc89a18fbec6f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
version: "1.3.2"
|
||||
flutter_riverpod:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_riverpod
|
||||
sha256: b04d4e9435a563673746ccb328d22018c6c9496bb547e11dd56c1b0cc9829fe5
|
||||
sha256: "4bce556b7ecbfea26109638d5237684538d4abc509d253e6c5c4c5733b360098"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.10"
|
||||
version: "2.4.10"
|
||||
flutter_svg:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_svg
|
||||
sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338"
|
||||
sha256: d39e7f95621fc84376bc0f7d504f05c3a41488c562f4a8ad410569127507402c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.7"
|
||||
version: "2.0.9"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@ -284,10 +284,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: google_fonts
|
||||
sha256: e20ff62b158b96f392bfc8afe29dee1503c94fbea2cbe8186fd59b756b8ae982
|
||||
sha256: f0b8d115a13ecf827013ec9fc883390ccc0e87a96ed5347a3114cac177ef18e8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.0"
|
||||
version: "6.1.0"
|
||||
google_nav_bar:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -308,10 +308,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.2.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -348,10 +348,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: lints
|
||||
sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
|
||||
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "3.0.0"
|
||||
list_counter:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -380,18 +380,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
||||
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
version: "1.10.0"
|
||||
octo_image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: octo_image
|
||||
sha256: "107f3ed1330006a3bea63615e81cf637433f5135a52466c7caa0e7152bca9143"
|
||||
sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
version: "2.0.0"
|
||||
open_file:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -420,26 +420,26 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
|
||||
sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1"
|
||||
sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.2.2"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
|
||||
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
version: "2.3.2"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -452,10 +452,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
|
||||
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -468,74 +468,82 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: permission_handler
|
||||
sha256: "63e5216aae014a72fe9579ccd027323395ce7a98271d9defa9d57320d001af81"
|
||||
sha256: "45ff3fbcb99040fde55c528d5e3e6ca29171298a85436274d49c6201002087d6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.4.3"
|
||||
version: "11.2.0"
|
||||
permission_handler_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_android
|
||||
sha256: d74e77a5ecd38649905db0a7d05ef16bed42ff263b9efb73ed794317c5764ec3
|
||||
sha256: "758284a0976772f9c744d6384fc5dc4834aa61e3f7aa40492927f244767374eb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.3.4"
|
||||
version: "12.0.3"
|
||||
permission_handler_apple:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_apple
|
||||
sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5"
|
||||
sha256: c6bf440f80acd2a873d3d91a699e4cc770f86e7e6b576dda98759e8b92b39830
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.1.4"
|
||||
version: "9.3.0"
|
||||
permission_handler_html:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_html
|
||||
sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.1"
|
||||
permission_handler_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_platform_interface
|
||||
sha256: "7c6b1500385dd1d2ca61bb89e2488ca178e274a69144d26bbd65e33eae7c02a9"
|
||||
sha256: "5c43148f2bfb6d14c5a8162c0a712afe891f2d847f35fcff29c406b37da43c3c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.11.3"
|
||||
version: "4.1.0"
|
||||
permission_handler_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_windows
|
||||
sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098
|
||||
sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.3"
|
||||
version: "0.2.1"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: petitparser
|
||||
sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
|
||||
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.4.0"
|
||||
version: "6.0.2"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102
|
||||
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
version: "3.1.4"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.6"
|
||||
version: "2.1.8"
|
||||
pointycastle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pointycastle
|
||||
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
|
||||
sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.7.3"
|
||||
version: "3.7.4"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -548,10 +556,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: riverpod
|
||||
sha256: "6c0a2c30c04206ac05494bcccd8148b76866e1a9248a5a8c84ca7b16fbcb3f6a"
|
||||
sha256: "548e2192eb7aeb826eb89387f814edb76594f3363e2c0bb99dd733d795ba3589"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.10"
|
||||
version: "2.5.0"
|
||||
rxdart:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -593,42 +601,42 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqflite
|
||||
sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a"
|
||||
sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.3.2"
|
||||
sqflite_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_common
|
||||
sha256: "1b92f368f44b0dee2425bb861cfa17b6f6cf3961f762ff6f941d20b33355660a"
|
||||
sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.0"
|
||||
version: "2.5.3"
|
||||
sqflite_common_ffi:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqflite_common_ffi
|
||||
sha256: "0d5cc1be2eb18400ac6701c31211d44164393aa75886093002ecdd947be04f93"
|
||||
sha256: "754927d82de369a6b9e760fb60640aa81da650f35ffd468d5a992814d6022908"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0+2"
|
||||
version: "2.3.2+1"
|
||||
sqlite3:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlite3
|
||||
sha256: db65233e6b99e99b2548932f55a987961bc06d82a31a0665451fa0b4fff4c3fb
|
||||
sha256: c4a4c5a4b2a32e2d0f6837b33d7c91a67903891a5b7dbe706cf4b1f6b0c798c5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.3.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
||||
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.0"
|
||||
version: "1.11.1"
|
||||
state_notifier:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -641,10 +649,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
||||
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -657,10 +665,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: synchronized
|
||||
sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60"
|
||||
sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.1.0+1"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -673,10 +681,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
|
||||
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.0"
|
||||
version: "0.6.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -697,98 +705,98 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: url_launcher
|
||||
sha256: "47e208a6711459d813ba18af120d9663c20bdf6985d6ad39fe165d2538378d27"
|
||||
sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.14"
|
||||
version: "6.2.4"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: b04af59516ab45762b2ca6da40fa830d72d0f6045cd97744450b73493fa76330
|
||||
sha256: "507dc655b1d9cb5ebc756032eb785f114e415f91557b73bf60b7e201dfedeb2f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.0"
|
||||
version: "6.2.2"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
sha256: "7c65021d5dee51813d652357bc65b8dd4a6177082a9966bc8ba6ee477baa795f"
|
||||
sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.5"
|
||||
version: "6.2.4"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_linux
|
||||
sha256: b651aad005e0cb06a01dbd84b428a301916dc75f0e7ea6165f80057fee2d8e8e
|
||||
sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.6"
|
||||
version: "3.1.1"
|
||||
url_launcher_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
sha256: b55486791f666e62e0e8ff825e58a023fd6b1f71c49926483f1128d3bbd8fe88
|
||||
sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.7"
|
||||
version: "3.1.0"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_platform_interface
|
||||
sha256: "95465b39f83bfe95fcb9d174829d6476216f2d548b79c38ab2506e0458787618"
|
||||
sha256: a932c3a8082e118f80a475ce692fde89dc20fddb24c57360b96bc56f7035de1f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
version: "2.3.1"
|
||||
url_launcher_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_web
|
||||
sha256: "2942294a500b4fa0b918685aff406773ba0a4cd34b7f42198742a94083020ce5"
|
||||
sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.20"
|
||||
version: "2.2.3"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_windows
|
||||
sha256: "95fef3129dc7cfaba2bc3d5ba2e16063bb561fc6d78e63eee16162bc70029069"
|
||||
sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.8"
|
||||
version: "3.1.1"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uuid
|
||||
sha256: e03928880bdbcbf496fb415573f5ab7b1ea99b9b04f669c01104d085893c3134
|
||||
sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
version: "4.3.3"
|
||||
vector_graphics:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics
|
||||
sha256: "670f6e07aca990b4a2bcdc08a784193c4ccdd1932620244c3a86bb72a0eac67f"
|
||||
sha256: "18f6690295af52d081f6808f2f7c69f0eed6d7e23a71539d75f4aeb8f0062172"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.7"
|
||||
version: "1.1.9+2"
|
||||
vector_graphics_codec:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_codec
|
||||
sha256: "7451721781d967db9933b63f5733b1c4533022c0ba373a01bdd79d1a5457f69f"
|
||||
sha256: "531d20465c10dfac7f5cd90b60bbe4dd9921f1ec4ca54c83ebb176dbacb7bb2d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.7"
|
||||
version: "1.1.9+2"
|
||||
vector_graphics_compiler:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_compiler
|
||||
sha256: "80a13c613c8bde758b1464a1755a7b3a8f2b6cec61fbf0f5a53c94c30f03ba2e"
|
||||
sha256: "03012b0a33775c5530576b70240308080e1d5050f0faf000118c20e6463bc0ad"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.7"
|
||||
version: "1.1.9+2"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -809,10 +817,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
|
||||
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.4-beta"
|
||||
version: "0.3.0"
|
||||
webview_cookie_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -825,58 +833,58 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: webview_flutter
|
||||
sha256: c1ab9b81090705c6069197d9fdc1625e587b52b8d70cdde2339d177ad0dbb98e
|
||||
sha256: d81b68e88cc353e546afb93fb38958e3717282c5ac6e5d3be4a4aef9fc3c1413
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.4.1"
|
||||
version: "4.5.0"
|
||||
webview_flutter_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_android
|
||||
sha256: b0cd33dd7d3dd8e5f664e11a19e17ba12c352647269921a3b568406b001f1dff
|
||||
sha256: "4ea3c4e1b8ed590162b15b8a61b41b1ef3ff179a314627c16ce40c086d94b8af"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.12.0"
|
||||
version: "3.14.0"
|
||||
webview_flutter_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_platform_interface
|
||||
sha256: "6d9213c65f1060116757a7c473247c60f3f7f332cac33dc417c9e362a9a13e4f"
|
||||
sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.0"
|
||||
version: "2.10.0"
|
||||
webview_flutter_wkwebview:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_wkwebview
|
||||
sha256: "30b9af6bdd457b44c08748b9190d23208b5165357cc2eb57914fee1366c42974"
|
||||
sha256: b99ca8d8bae9c6b43d568218691aa537fb0aeae1d7d34eadf112a6aa36d26506
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.9.1"
|
||||
version: "3.11.0"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa"
|
||||
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.7"
|
||||
version: "5.2.0"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xdg_directories
|
||||
sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
|
||||
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
version: "1.0.4"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xml
|
||||
sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84"
|
||||
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.0"
|
||||
version: "6.5.0"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -886,5 +894,5 @@ packages:
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
sdks:
|
||||
dart: ">=3.1.0 <4.0.0"
|
||||
flutter: ">=3.13.0"
|
||||
dart: ">=3.2.3 <4.0.0"
|
||||
flutter: ">=3.16.6"
|
||||
|
15
pubspec.yaml
@ -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.3+5
|
||||
version: 1.0.5+8
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.5 <4.0.0'
|
||||
@ -34,26 +34,26 @@ dependencies:
|
||||
|
||||
google_nav_bar: ^5.0.6
|
||||
|
||||
epub_view: ^3.2.0
|
||||
flutter_pdfview: ^1.2.7
|
||||
vocsy_epub_viewer: ^2.0.0
|
||||
epub_view: ^3.2.0
|
||||
# syncfusion_flutter_pdfviewer: ^22.2.5
|
||||
# pdfx: ^2.4.0
|
||||
|
||||
dio: ^5.3.0
|
||||
dio: ^5.4.0
|
||||
html: ^0.15.4
|
||||
|
||||
sqflite: ^2.3.0
|
||||
path_provider: ^2.0.15
|
||||
permission_handler: ^10.4.3
|
||||
permission_handler: ^11.2.0
|
||||
open_file: ^3.3.2
|
||||
webview_flutter: ^4.4.1
|
||||
webview_cookie_manager: ^2.0.6
|
||||
|
||||
flutter_svg: ^2.0.7
|
||||
google_fonts: ^5.1.0
|
||||
google_fonts: ^6.1.0
|
||||
|
||||
cached_network_image: ^3.2.3
|
||||
cached_network_image: 3.3.0
|
||||
|
||||
sqflite_common_ffi: ^2.3.0+2
|
||||
url_launcher: ^6.1.12
|
||||
@ -61,6 +61,7 @@ dependencies:
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.2
|
||||
dev: ^1.0.0
|
||||
crypto: ^3.0.3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@ -72,7 +73,7 @@ dev_dependencies:
|
||||
# activated in the `analysis_options.yaml` file located at the root of your
|
||||
# package. See that file for information about deactivating specific lint
|
||||
# rules and activating additional ones.
|
||||
flutter_lints: ^2.0.0
|
||||
flutter_lints: ^3.0.1
|
||||
|
||||
|
||||
flutter_icons:
|
||||
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 447 KiB |
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 536 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 378 KiB After Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 227 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 379 KiB After Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 271 KiB |
Before Width: | Height: | Size: 231 KiB After Width: | Height: | Size: 28 KiB |