30 Commits

Author SHA1 Message Date
fbe1ee70c9 changed some styles and fixed search layout overflow 2023-08-22 04:00:11 -07:00
c7b1fec73e Merge pull request #13 from PiyushSuthar/main
Shifting to Material You
2023-08-22 03:18:24 -07:00
9cc3c3dde5 implemented resume reading for pdf and epub 2023-08-21 22:52:19 -07:00
72abde09e0 added: autogenerated platform files 2023-08-21 21:56:00 +05:30
3d3097152d fixed: trending page card ui and colors 2023-08-21 20:31:36 +05:30
c5b1fc54d9 fixed & replaced with material you components 2023-08-21 20:31:01 +05:30
d253e52971 fixed search page 2023-08-21 20:30:10 +05:30
0b502629fb fixed: result page and redesigned card 2023-08-21 20:29:43 +05:30
8ec03ba5d7 fixed: alert dialog and button layouts 2023-08-21 20:28:07 +05:30
068a2c68e0 fixed: Loading Indicator 2023-08-21 20:27:04 +05:30
59d467c692 fixed: fontsize and background color 2023-08-21 20:25:23 +05:30
9fffb3829f removed media query 2023-08-21 20:22:40 +05:30
e25a12b684 shifted to material you style widgets 2023-08-21 01:24:24 +05:30
86684c5436 added material dynamic color 2023-08-21 01:23:29 +05:30
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
40 changed files with 791 additions and 625 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

@ -1,6 +1,6 @@
<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" />
<application
android:label="Openlib"
android:name="${applicationName}"

View File

@ -0,0 +1 @@
<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>Features include a.o.:</p><ul><li>Trending Books</li><li>Download And Read Books With In-Built Viewer</li><li>Supports Epub And Pdf Formats</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,7 +1,10 @@
import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.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:sqflite_common_ffi/sqflite_ffi.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:openlib/ui/extensions.dart';
@ -14,55 +17,49 @@ import 'package:openlib/state/state.dart'
void main() async {
WidgetsFlutterBinding.ensureInitialized();
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
sqfliteFfiInit();
databaseFactory = databaseFactoryFfi;
}
Database db = await Sqlite.initDb();
runApp(ProviderScope(
runApp(
ProviderScope(
overrides: [dbProvider.overrideWithValue(MyLibraryDb(dbInstance: db))],
child: const MyApp()));
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return DynamicColorBuilder(
builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
return MaterialApp(
builder: (BuildContext context, Widget? child) {
return MediaQuery(
data: MediaQuery.of(context).copyWith(
textScaleFactor: 1.0,
),
child: child!,
);
},
// builder: (BuildContext context, Widget? child) {
// return MediaQuery(
// data: MediaQuery.of(context).copyWith(
// textScaleFactor: 1.0,
// ),
// child: child!,
// );
// },
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())),
colorScheme: lightDynamic,
),
darkTheme: ThemeData(
useMaterial3: true,
colorScheme: darkDynamic,
),
home: const HomePage(),
);
});
}
}
@ -84,67 +81,37 @@ class _HomePageState extends ConsumerState<HomePage> {
Widget build(BuildContext context) {
final selectedIndex = ref.watch(selectedIndexProvider);
return Scaffold(
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
systemNavigationBarColor: ElevationOverlay.applySurfaceTint(
Theme.of(context).colorScheme.surface,
Theme.of(context).colorScheme.surfaceTint,
3)),
child: Scaffold(
backgroundColor: Theme.of(context).colorScheme.background,
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.primary,
title: const Text("Openlib"),
titleTextStyle: Theme.of(context).textTheme.displayLarge,
leading:
Icon(Icons.book, color: Theme.of(context).colorScheme.primary),
title: const Text(
"Openlib",
style: TextStyle(fontWeight: FontWeight.w600),
),
titleSpacing: 1,
),
body: _widgetOptions.elementAt(selectedIndex),
bottomNavigationBar: SafeArea(
child: GNav(
rippleColor: Colors.redAccent,
backgroundColor: Colors.black,
haptic: true,
tabBorderRadius: 50,
tabActiveBorder: Border.all(
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),
gap: 5,
color: const Color.fromARGB(255, 255, 255, 255),
activeColor: const Color.fromARGB(255, 255, 255, 255),
iconSize: 21, // tab button icon size
tabBackgroundColor: Theme.of(context).colorScheme.secondary,
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 6.5),
tabs: const [
GButton(
icon: Icons.trending_up,
text: 'Trending',
iconColor: Colors.white,
textStyle: TextStyle(
fontWeight: FontWeight.w900,
color: Colors.white,
fontSize: 13,
),
),
GButton(
icon: Icons.search,
text: 'Search',
iconColor: Colors.white,
textStyle: TextStyle(
fontWeight: FontWeight.w900,
color: Colors.white,
fontSize: 13,
),
),
GButton(
icon: Icons.collections_bookmark,
text: 'My Library',
iconColor: Colors.white,
textStyle: TextStyle(
fontWeight: FontWeight.w900,
color: Colors.white,
fontSize: 13,
),
),
bottomNavigationBar: NavigationBar(
destinations: const [
NavigationDestination(
icon: Icon(Icons.trending_up), label: "Trending"),
NavigationDestination(icon: Icon(Icons.search), label: "Search"),
NavigationDestination(
icon: Icon(Icons.collections_bookmark), label: "My Library"),
],
selectedIndex: selectedIndex,
onTabChange: (index) async {
onDestinationSelected: (index) async {
ref.read(selectedIndexProvider.notifier).state = index;
},
labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected,
),
),
);

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;
}
}

View File

@ -1,15 +1,32 @@
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,
Database dbInstance = await openDatabase(
path,
version: 2,
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)');
});
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']);
if (isMobile && isTableExist.isEmpty) {
await db.execute(
'CREATE TABLE bookposition (fileName TEXT PRIMARY KEY,position TEXT)');
}
},
);
return dbInstance;
}
}
@ -118,4 +135,33 @@ 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;
}
}
}

View File

@ -35,9 +35,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

@ -125,6 +125,22 @@ 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 filePathProvider =
FutureProvider.family<String, String>((ref, fileName) async {
String path = await getFilePath(fileName);

View File

@ -23,18 +23,21 @@ import 'package:openlib/ui/components/file_buttons_widget.dart';
import 'package:openlib/ui/components/snack_bar_widget.dart';
class BookInfoPage extends ConsumerWidget {
const BookInfoPage({Key? key, required this.url}) : super(key: key);
const BookInfoPage({Key? key, required this.url, required this.title})
: super(key: key);
final String url;
final String title;
@override
Widget build(BuildContext context, WidgetRef ref) {
final bookInfo = ref.watch(bookInfoProvider(url));
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.primary,
title: const Text("Openlib"),
titleTextStyle: Theme.of(context).textTheme.displayLarge,
// backgroundColor: Theme.of(context).colorScheme.primary,
title: Text(title),
titleSpacing: 0,
// titleTextStyle: Theme.of(context).textTheme.displayLarge,
),
body: bookInfo.when(
data: (data) {
@ -95,21 +98,23 @@ class _ActionButtonWidgetState extends ConsumerState<ActionButtonWidget> {
} else {
return Padding(
padding: const EdgeInsets.only(top: 21, bottom: 21),
child: TextButton(
style: TextButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.secondary,
textStyle: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w900,
color: Colors.white,
)),
child: ElevatedButton(
// style: ElevatedButton.styleFrom(
// // backgroundColor: Theme.of(context).colorScheme.secondary,
// textStyle: const TextStyle(
// // fontSize: 13,
// fontWeight: FontWeight.w500,
// // color: Colors.white,
// )),
onPressed: () async {
await downloadFileWidget(ref, context, widget.data);
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text('Add To My Library'),
),
child: const Text('Add To My Library',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
// color: Colors.white,
)),
),
);
}
@ -190,111 +195,33 @@ class _ShowDialog extends ConsumerWidget {
Navigator.of(context).pop();
}
return Stack(
alignment: Alignment.center,
return AlertDialog(
title: const Text("Downloading Book"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.all(15.0),
child: Container(
width: double.infinity,
height: 255,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
Text(title),
const SizedBox(
height: 20,
),
padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.all(8),
child: Text(
"Downloading Book",
style: TextStyle(
fontSize: 19,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 54, 54, 54),
decoration: TextDecoration.none),
LinearProgressIndicator(
value: downloadProgress,
),
const SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.all(8),
child: Text(
title,
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.bold,
color: Colors.black54,
decoration: TextDecoration.none),
overflow: TextOverflow.ellipsis,
maxLines: 2,
textAlign: TextAlign.start,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.all(8),
child: Text(
Text(
'$downloadedFileSize/$fileSize',
style: TextStyle(
fontSize: 9,
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.secondary,
decoration: TextDecoration.none,
letterSpacing: 1),
overflow: TextOverflow.ellipsis,
maxLines: 1,
textAlign: TextAlign.start,
),
),
)
],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(50)),
child: LinearProgressIndicator(
color: Theme.of(context).colorScheme.secondary,
backgroundColor: Colors.black26,
value: downloadProgress,
minHeight: 4,
),
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.secondary,
textStyle: const TextStyle(
fontSize: 11,
fontWeight: FontWeight.w900,
color: Colors.white,
)),
onPressed: () {
ref.read(cancelCurrentDownload).cancel();
Navigator.of(context).pop();
Navigator.pop(context, 'Cancel');
},
child: const Padding(
padding: EdgeInsets.all(3.0),
child: Text('Cancel'),
),
)
],
),
)
],
),
),
),
child: const Text('Cancel'),
),
],
);

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:openlib/ui/extensions.dart';
import 'package:cached_network_image/cached_network_image.dart';
// TODO: Redesign this widget
class BookInfoCard extends StatelessWidget {
const BookInfoCard(
{Key? key,
@ -22,26 +23,29 @@ class BookInfoCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onClick,
child: Container(
width: double.infinity,
height: 120,
decoration: BoxDecoration(
return Card(
shadowColor: Colors.black.withOpacity(0),
margin: const EdgeInsets.only(bottom: 20),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
color: Theme.of(context).colorScheme.tertiaryContainer,
side: BorderSide(
color: Theme.of(context).colorScheme.surfaceVariant,
width: 1,
),
margin: const EdgeInsets.only(bottom: 10),
),
child: InkWell(
onTap: onClick,
borderRadius: BorderRadius.circular(5),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
CachedNetworkImage(
height: 120,
width: 90,
height: 140,
width: 105,
imageUrl: thumbnail ?? "",
imageBuilder: (context, imageProvider) => Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(5)),
borderRadius: BorderRadius.circular(5),
image: DecorationImage(
image: imageProvider,
fit: BoxFit.fill,
@ -51,7 +55,7 @@ class BookInfoCard extends StatelessWidget {
placeholder: (context, url) => Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: "#F8C0C8".toColor(),
color: Theme.of(context).colorScheme.surfaceVariant,
),
height: 120,
width: 90,
@ -60,7 +64,7 @@ class BookInfoCard extends StatelessWidget {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: "#F8C0C8".toColor(),
color: Theme.of(context).colorScheme.surfaceVariant,
),
height: 120,
width: 90,
@ -72,7 +76,7 @@ class BookInfoCard extends StatelessWidget {
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(5),
padding: const EdgeInsets.all(18),
child: SizedBox(
width: double.infinity,
child: Column(
@ -82,29 +86,33 @@ class BookInfoCard extends StatelessWidget {
Text(
title,
style: const TextStyle(
fontSize: 15,
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black,
// color: Colors.black,
),
overflow: TextOverflow.ellipsis,
maxLines: 2,
),
Text(
Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Text(
publisher,
style: TextStyle(
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: "#4D4D4D".toColor(),
fontWeight: FontWeight.w500,
// color: "#4D4D4D".toColor(),
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
Text(
author,
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: "#7B7B7B".toColor(),
fontSize: 14,
fontWeight: FontWeight.w500,
// color: "#7B7B7B".toColor(),
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,

View File

@ -12,10 +12,10 @@ class BookInfoWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
physics: const BouncingScrollPhysics(),
// physics: const BouncingScrollPhysics(),
scrollDirection: Axis.vertical,
child: Padding(
padding: const EdgeInsets.only(left: 15, right: 15, top: 10),
padding: const EdgeInsets.only(left: 20, right: 20, top: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
@ -26,8 +26,8 @@ class BookInfoWidget extends StatelessWidget {
),
Center(
child: CachedNetworkImage(
height: 230,
width: 170,
height: 240,
width: 180,
imageUrl: data.thumbnail,
imageBuilder: (context, imageProvider) => Container(
decoration: BoxDecoration(
@ -43,8 +43,8 @@ class BookInfoWidget extends StatelessWidget {
borderRadius: BorderRadius.circular(10),
color: Colors.grey,
),
height: 230,
width: 170,
height: 240,
width: 180,
),
errorWidget: (context, url, error) {
return Container(
@ -63,21 +63,22 @@ class BookInfoWidget extends StatelessWidget {
),
_TopPaddedText(
text: data.title,
fontSize: 19,
fontSize: 22,
topPadding: 15,
color: Colors.black,
fontWeight: FontWeight.w600,
// color: Colors.black,
maxLines: 7,
),
_TopPaddedText(
text: data.publisher ?? "unknown",
fontSize: 15,
fontSize: 17,
topPadding: 7,
color: "#595E60".toColor(),
color: Theme.of(context).colorScheme.onSecondaryContainer,
maxLines: 4,
),
_TopPaddedText(
text: data.author ?? "unknown",
fontSize: 13,
fontSize: 20,
topPadding: 7,
color: "#7F7F7F".toColor(),
maxLines: 3,
@ -91,33 +92,41 @@ class BookInfoWidget extends StatelessWidget {
),
// child slot of page
child,
Column(
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
child: SizedBox(
width: double.infinity,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Description",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w900,
color: Theme.of(context).colorScheme.tertiary,
fontSize: 20,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.onSurface,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
Padding(
padding: const EdgeInsets.only(top: 7, bottom: 10),
padding: const EdgeInsets.only(top: 15, bottom: 10),
child: Text(
data.description ?? "",
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: "#6B6B6B".toColor(),
letterSpacing: 1.5,
style: const TextStyle(
fontSize: 16,
),
),
)
],
),
),
),
)
],
),
@ -130,14 +139,16 @@ class _TopPaddedText extends StatelessWidget {
final String text;
final double fontSize;
final double topPadding;
final Color color;
final Color? color;
final int maxLines;
final FontWeight fontWeight;
const _TopPaddedText(
{required this.text,
required this.fontSize,
required this.topPadding,
required this.color,
this.color,
this.fontWeight = FontWeight.w400,
required this.maxLines,
Key? key})
: super(key: key);
@ -150,9 +161,9 @@ class _TopPaddedText extends StatelessWidget {
text,
style: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.w900,
fontWeight: fontWeight,
color: color,
letterSpacing: 0.5,
// letterSpacing: 0.5,
),
overflow: TextOverflow.ellipsis,
maxLines: maxLines,

View File

@ -16,117 +16,28 @@ class ShowDeleteDialog extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
return Stack(
alignment: Alignment.center,
children: [
Padding(
padding: const EdgeInsets.all(15.0),
child: Container(
width: double.infinity,
height: 219,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
),
padding: const EdgeInsets.fromLTRB(20, 50, 20, 20),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.all(8),
child: Text(
"Delete Book",
style: TextStyle(
fontSize: 19,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 54, 54, 54),
decoration: TextDecoration.none),
),
),
const Padding(
padding: EdgeInsets.all(8),
child: Text(
"This is permanent and cannot be undone",
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.bold,
color: Colors.black54,
decoration: TextDecoration.none),
overflow: TextOverflow.ellipsis,
maxLines: 2,
textAlign: TextAlign.start,
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
// if (false) {
// return
// }
return AlertDialog(
title: const Text("Delete Book?"),
content: const Text("This is permanent and cannot be undone"),
actions: <Widget>[
TextButton(
style: ButtonStyle(
shape: MaterialStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
side: BorderSide(
width: 3,
color: Theme.of(context)
.colorScheme
.secondary),
),
),
),
onPressed: () {
ref.read(deleteFileFromMyLib(
FileName(md5: id, format: format)));
ref.read(deleteFileFromMyLib(FileName(md5: id, format: format)));
Navigator.of(context).pop();
showSnackBar(
context: context,
message: 'Book has been Deleted!');
showSnackBar(context: context, message: 'Book has been Deleted!');
onDelete();
},
child: const Padding(
padding: EdgeInsets.all(5.0),
child: Text(
'Delete',
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
),
),
const SizedBox(
width: 10,
child: const Text('Delete'),
),
TextButton(
style: TextButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.secondary,
textStyle: const TextStyle(
fontSize: 11,
fontWeight: FontWeight.w900,
color: Colors.white,
)),
onPressed: () {
Navigator.of(context).pop();
},
child: const Padding(
padding: EdgeInsets.all(5.0),
child: Text('Cancel'),
),
)
],
),
)
],
),
),
),
onPressed: () => Navigator.pop(context, 'Cancel'),
child: const Text('Cancel'),
),
],
);

View File

@ -24,7 +24,7 @@ class FileOpenAndDeleteButtons extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextButton(
FilledButton(
style: TextButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.secondary,
textStyle: const TextStyle(
@ -60,7 +60,7 @@ class FileOpenAndDeleteButtons extends StatelessWidget {
const SizedBox(
width: 10,
),
TextButton(
OutlinedButton(
style: ButtonStyle(
shape: MaterialStateProperty.all(
RoundedRectangleBorder(
@ -82,14 +82,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.onSurface,
),
),
),

View File

@ -7,13 +7,13 @@ class TitleText extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 10, bottom: 7),
padding: const EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 10),
child: Text(
text,
style: TextStyle(
fontSize: 19,
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.secondary,
style: const TextStyle(
fontSize: 25,
fontWeight: FontWeight.w500,
// color: Theme.of(context).colorScheme.onInverseSurface,
),
),
);

View File

@ -5,14 +5,14 @@ void showSnackBar({required BuildContext context, required String message}) {
content: Text(
message,
style: const TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 12,
// fontWeight: FontWeight.bold,
// color: Colors.white,
),
textAlign: TextAlign.center,
),
// ignore: use_build_context_synchronously
backgroundColor: Theme.of(context).colorScheme.secondary,
// backgroundColor: Theme.of(context).colorScheme.secondary,
width: 300,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(50))),

View File

@ -3,7 +3,8 @@ import 'package:flutter/material.dart';
import 'package:epub_view/epub_view.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:openlib/state/state.dart' show filePathProvider;
import 'package:openlib/state/state.dart'
show filePathProvider, saveEpubState, getBookPosition;
class EpubViewerWidget extends ConsumerStatefulWidget {
const EpubViewerWidget({super.key, required this.fileName});
@ -19,22 +20,22 @@ 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(
backgroundColor: Theme.of(context).colorScheme.primary,
// backgroundColor: Theme.of(context).colorScheme.primary,
title: const Text("Openlib"),
titleTextStyle: Theme.of(context).textTheme.displayLarge,
// titleTextStyle: Theme.of(context).textTheme.displayLarge,
),
body: Center(child: Text(error.toString())),
);
}, loading: () {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.primary,
// backgroundColor: Theme.of(context).colorScheme.primary,
title: const Text("Openlib"),
titleTextStyle: Theme.of(context).textTheme.displayLarge,
// titleTextStyle: Theme.of(context).textTheme.displayLarge,
),
body: Center(
child: SizedBox(
@ -43,24 +44,28 @@ class _EpubViewState extends ConsumerState<EpubViewerWidget> {
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 +75,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,23 +91,59 @@ 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,
// backgroundColor: Theme.of(context).colorScheme.primary,
title: const Text("Openlib"),
titleTextStyle: Theme.of(context).textTheme.displayLarge,
titleSpacing: 0,
// titleTextStyle: Theme.of(context).textTheme.displayLarge,
),
endDrawer: Drawer(
child: EpubViewTableOfContents(controller: _epubReaderController),
),
body: EpubView(
onDocumentLoaded: (doc) {},
onChapterChanged: (value) {},
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

@ -7,17 +7,18 @@ 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({Key? key, required this.id, required this.title})
: super(key: key);
final String id;
final String title;
@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,
title: Text(title),
titleSpacing: 0,
),
body: Consumer(
builder: (BuildContext context, WidgetRef ref, _) {
@ -42,12 +43,8 @@ class BookPage extends StatelessWidget {
);
} else {
return Center(
child: SizedBox(
width: 25,
height: 25,
child: CircularProgressIndicator(
color: Theme.of(context).colorScheme.secondary,
),
));
}
});

View File

@ -38,7 +38,7 @@ class MyLibraryPage extends ConsumerWidget {
onClick: () {
Navigator.push(context, MaterialPageRoute(
builder: (BuildContext context) {
return BookPage(id: i.id);
return BookPage(id: i.id, title: i.title);
}));
}))
.toList()),
@ -81,12 +81,8 @@ class MyLibraryPage extends ConsumerWidget {
},
loading: () {
return Center(
child: SizedBox(
width: 25,
height: 25,
child: CircularProgressIndicator(
color: Theme.of(context).colorScheme.secondary,
),
));
},
);

View File

@ -2,7 +2,14 @@ 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,
getBookPosition;
import 'package:url_launcher/url_launcher.dart';
import 'dart:io' show Platform;
class PdfView extends ConsumerStatefulWidget {
const PdfView({super.key, required this.fileName});
@ -18,7 +25,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(
@ -31,9 +38,9 @@ class _PdfViewState extends ConsumerState<PdfView> {
}, loading: () {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.primary,
// backgroundColor: Theme.of(context).colorScheme.primary,
title: const Text("Openlib"),
titleTextStyle: Theme.of(context).textTheme.displayLarge,
// titleTextStyle: Theme.of(context).textTheme.displayLarge,
),
body: Center(
child: SizedBox(
@ -49,9 +56,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,20 +69,59 @@ 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(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.primary,
// backgroundColor: Theme.of(context).colorScheme.primary,
title: const Text("Openlib"),
titleTextStyle: Theme.of(context).textTheme.displayLarge,
actions: [
titleSpacing: 0,
// titleTextStyle: Theme.of(context).textTheme.displayLarge,
actions: isMobile
? [
IconButton(
onPressed: () {
if (currentPage != 0) {
ref.read(pdfCurrentPage.notifier).state = currentPage - 1;
ref.read(pdfCurrentPage.notifier).state =
currentPage - 1;
controller.setPage(currentPage - 1);
} else {
ref.read(pdfCurrentPage.notifier).state = totalPages;
@ -84,11 +132,13 @@ class _PdfViewerState extends ConsumerState<PdfViewer> {
Icons.arrow_left,
size: 25,
)),
Text('${(currentPage + 1).toString()} / ${totalPages.toString()}'),
Text(
'${(currentPage + 1).toString()} / ${totalPages.toString()}'),
IconButton(
onPressed: () {
if (currentPage + 1 < totalPages) {
ref.read(pdfCurrentPage.notifier).state = currentPage + 1;
ref.read(pdfCurrentPage.notifier).state =
currentPage + 1;
controller.setPage(currentPage + 1);
} else {
ref.read(pdfCurrentPage.notifier).state = 0;
@ -99,9 +149,29 @@ class _PdfViewerState extends ConsumerState<PdfViewer> {
Icons.arrow_right,
size: 25,
)),
],
]
: [],
),
body: PDFView(
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,
@ -113,6 +183,36 @@ class _PdfViewerState extends ConsumerState<PdfViewer> {
ref.read(pdfCurrentPage.notifier).state = page ?? 0;
ref.read(totalPdfPage.notifier).state = total ?? 0;
},
);
},
loading: () {
return Center(
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

@ -23,22 +23,30 @@ class ResultPage extends ConsumerWidget {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.primary,
title: const Text("Openlib"),
titleTextStyle: Theme.of(context).textTheme.displayLarge,
// backgroundColor: Theme.of(context).colorScheme.primary,
title: const Text(
"Results",
style: TextStyle(fontWeight: FontWeight.w500),
),
titleSpacing: 0,
// titleTextStyle: Theme.of(context).textTheme.displayLarge,
),
body: searchBooks.when(
data: (data) {
if (data.isNotEmpty) {
return Padding(
padding: const EdgeInsets.only(left: 5, right: 5, top: 10),
padding: const EdgeInsets.only(
left: 5,
right: 5,
),
child: CustomScrollView(
slivers: <Widget>[
const SliverToBoxAdapter(
child: TitleText("Results"),
),
// const SliverToBoxAdapter(
// child: TitleText("Results"),
// ),
SliverPadding(
padding: const EdgeInsets.only(left: 5, right: 5, top: 10),
padding: const EdgeInsets.only(left: 5, right: 5, top: 15),
sliver: SliverList(
delegate: SliverChildListDelegate(data
.map((i) => BookInfoCard(
@ -50,7 +58,8 @@ class ResultPage extends ConsumerWidget {
onClick: () {
Navigator.push(context, MaterialPageRoute(
builder: (BuildContext context) {
return BookInfoPage(url: i.link);
return BookInfoPage(
url: i.link, title: i.title);
}));
},
))
@ -103,22 +112,14 @@ class ResultPage extends ConsumerWidget {
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.only(left: 5, right: 5, top: 10),
child: TitleText("Results"),
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Center(
child: SizedBox(
width: 25,
height: 25,
child: CircularProgressIndicator(
color: Theme.of(context).colorScheme.secondary,
),
))
],
),

View File

@ -39,19 +39,23 @@ class SearchPage extends ConsumerWidget {
padding: const EdgeInsets.only(left: 7, right: 7, top: 10),
child: TextField(
showCursor: true,
cursorColor: Theme.of(context).colorScheme.secondary,
// cursorColor: Theme.of(context).colorScheme.secondary,
decoration: InputDecoration(
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black45, width: 2),
borderRadius: BorderRadius.all(Radius.circular(50)),
label: const Text("Search"),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.outline, width: 2),
borderRadius: const 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.outline, width: 2),
borderRadius: const BorderRadius.all(Radius.circular(50)),
),
suffixIcon: IconButton(
padding: const EdgeInsets.only(right: 5),
color: Theme.of(context).colorScheme.secondary,
padding: const EdgeInsets.only(right: 10),
// color: Theme.of(context).colorScheme.secondary,
icon: const Icon(
Icons.search,
size: 23,
@ -59,16 +63,16 @@ class SearchPage extends ConsumerWidget {
onPressed: () => onSubmit(context, ref),
),
filled: true,
hintStyle: const TextStyle(
color: Colors.grey, fontWeight: FontWeight.bold),
hintText: "Search",
fillColor: Theme.of(context).colorScheme.primary,
// hintStyle: const TextStyle(
// color: Colors.grey, fontWeight: FontWeight.bold),
hintText: "Search books ,author or ISBN",
// fillColor: Theme.of(context).colorScheme.primary,
),
onSubmitted: (String value) => onSubmit(context, ref),
style: TextStyle(
color: Theme.of(context).colorScheme.tertiary,
fontWeight: FontWeight.bold,
fontSize: 12,
style: const TextStyle(
// color: Theme.of(context).colorScheme.tertiary,
// fontWeight: FontWeight.bold,
fontSize: 14,
),
onChanged: (String value) {
ref.read(searchQueryProvider.notifier).state = value;
@ -83,17 +87,21 @@ class SearchPage extends ConsumerWidget {
decoration: InputDecoration(
labelText: 'Type',
labelStyle: TextStyle(
fontSize: 11,
fontSize: 12,
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.secondary,
),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black54, width: 2),
borderRadius: BorderRadius.all(Radius.circular(50)),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.outline,
width: 2),
borderRadius: const 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.outline,
width: 2),
borderRadius: const BorderRadius.all(Radius.circular(50)),
),
),
icon: const Icon(Icons.arrow_drop_down),
@ -105,7 +113,7 @@ class SearchPage extends ConsumerWidget {
value: value,
child: Text(
value,
style: const TextStyle(fontSize: 12),
style: const TextStyle(fontSize: 14),
),
);
}).toList(),
@ -123,17 +131,21 @@ class SearchPage extends ConsumerWidget {
decoration: InputDecoration(
labelText: 'Sort by',
labelStyle: TextStyle(
fontSize: 11,
fontSize: 12,
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.secondary,
),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black45, width: 2),
borderRadius: BorderRadius.all(Radius.circular(50)),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.outline,
width: 2),
borderRadius: const 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.outline,
width: 2),
borderRadius: const BorderRadius.all(Radius.circular(50)),
),
),
value: dropdownSortValue,
@ -144,7 +156,7 @@ class SearchPage extends ConsumerWidget {
value: value,
child: Text(
value,
style: const TextStyle(fontSize: 12),
style: const TextStyle(fontSize: 14),
),
);
}).toList(),
@ -153,7 +165,7 @@ class SearchPage extends ConsumerWidget {
},
),
),
)
),
],
),
),

View File

@ -19,7 +19,7 @@ class TrendingPage extends ConsumerWidget {
final trendingBooks = ref.watch(getTrendingBooks);
return trendingBooks.when(data: (data) {
return Padding(
padding: const EdgeInsets.only(left: 5, right: 5, top: 10),
padding: const EdgeInsets.only(left: 5, right: 5, top: 0),
child: CustomScrollView(
slivers: [
const SliverToBoxAdapter(
@ -37,6 +37,7 @@ class TrendingPage extends ConsumerWidget {
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return InkWell(
borderRadius: BorderRadius.circular(10),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
@ -45,10 +46,6 @@ class TrendingPage extends ConsumerWidget {
);
}));
},
child: Container(
width: double.infinity,
height: double.infinity,
color: const Color.fromARGB(255, 255, 255, 255),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
@ -60,12 +57,6 @@ class TrendingPage extends ConsumerWidget {
imageBuilder: (context, imageProvider) =>
Container(
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
color: Colors.grey,
spreadRadius: 0.1,
blurRadius: 1)
],
borderRadius: const BorderRadius.all(
Radius.circular(5)),
image: DecorationImage(
@ -77,7 +68,10 @@ class TrendingPage extends ConsumerWidget {
placeholder: (context, url) => Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: "#E3E8E9".toColor(),
// color: "#E3E8E9".toColor(),
color: Theme.of(context)
.colorScheme
.surfaceVariant,
),
height: imageHeight,
width: imageWidth,
@ -86,7 +80,9 @@ class TrendingPage extends ConsumerWidget {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.grey,
color: Theme.of(context)
.colorScheme
.surfaceVariant,
),
height: imageHeight,
width: imageWidth,
@ -97,20 +93,19 @@ class TrendingPage extends ConsumerWidget {
},
),
Padding(
padding: const EdgeInsets.only(top: 4),
padding: const EdgeInsets.only(top: 8),
child: SizedBox(
width: imageWidth,
child: Text(
data[index].title!,
style: Theme.of(context)
.textTheme
.displayMedium,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w400),
maxLines: 2,
),
),
),
]),
),
);
},
childCount: data.length,
@ -130,12 +125,12 @@ class TrendingPage extends ConsumerWidget {
},
);
}, loading: () {
return Center(
return const Center(
child: SizedBox(
width: 25,
height: 25,
child: CircularProgressIndicator(
color: Theme.of(context).colorScheme.secondary,
// color: Theme.of(context).colorScheme.secondary,
),
));
});

View File

@ -6,6 +6,14 @@
#include "generated_plugin_registrant.h"
#include <dynamic_color/dynamic_color_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) dynamic_color_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin");
dynamic_color_plugin_register_with_registrar(dynamic_color_registrar);
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,8 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
dynamic_color
url_launcher_linux
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST

View File

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

View File

@ -145,6 +145,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.3.0"
dynamic_color:
dependency: "direct main"
description:
name: dynamic_color
sha256: de4798a7069121aee12d5895315680258415de9b00e717723a1bd73d58f0126d
url: "https://pub.dev"
source: hosted
version: "1.6.6"
epub_view:
dependency: "direct main"
description:
@ -267,6 +275,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:
@ -544,6 +557,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:
@ -616,6 +645,70 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.0"
url_launcher:
dependency: "direct main"
description:
name: url_launcher
sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e"
url: "https://pub.dev"
source: hosted
version: "6.1.12"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
sha256: "3dd2388cc0c42912eee04434531a26a82512b9cb1827e0214430c9bcbddfe025"
url: "https://pub.dev"
source: hosted
version: "6.0.38"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2"
url: "https://pub.dev"
source: hosted
version: "6.1.4"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1"
url: "https://pub.dev"
source: hosted
version: "3.0.6"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea
url: "https://pub.dev"
source: hosted
version: "2.1.3"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4
url: "https://pub.dev"
source: hosted
version: "2.0.18"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422"
url: "https://pub.dev"
source: hosted
version: "3.0.7"
uuid:
dependency: transitive
description:
@ -690,4 +783,4 @@ packages:
version: "3.1.2"
sdks:
dart: ">=3.0.5 <4.0.0"
flutter: ">=3.7.0-0"
flutter: ">=3.10.0"

View File

@ -49,10 +49,14 @@ dependencies:
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
dev: ^1.0.0
dynamic_color: ^1.6.6
dev_dependencies:
flutter_test:

View File

@ -6,6 +6,12 @@
#include "generated_plugin_registrant.h"
#include <dynamic_color/dynamic_color_plugin_c_api.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
DynamicColorPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
}

View File

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