diff --git a/lib/anime/anime.dart b/lib/anime/anime.dart index 5d91f5a..1b38c2d 100644 --- a/lib/anime/anime.dart +++ b/lib/anime/anime.dart @@ -148,6 +148,7 @@ class AniPageState extends State with AutomaticKeepAliveClientMixin { page = 1; animeData = []; if (textController.text.isNotEmpty) { + print(textController.text); selectedGenres = []; search = textController.text; } else { diff --git a/lib/manga/manga_reader.dart b/lib/manga/manga_reader.dart index 19a4c3d..05df471 100644 --- a/lib/manga/manga_reader.dart +++ b/lib/manga/manga_reader.dart @@ -98,6 +98,8 @@ class MangaControlsState extends State { @override Widget build(context) { + final width = MediaQuery.of(context).size.width; + final height = MediaQuery.of(context).size.height; return SafeArea( child: Stack( children: [ @@ -132,8 +134,8 @@ class MangaControlsState extends State { Positioned( top: 0, left: 0, - width: MediaQuery.of(context).size.width / 2, - height: MediaQuery.of(context).size.height, + width: width / 2, + height: height, child: GestureDetector( onTap: () { widget.controller.jumpToPage( @@ -145,8 +147,8 @@ class MangaControlsState extends State { Positioned( top: 0, right: 0, - width: MediaQuery.of(context).size.width / 2, - height: MediaQuery.of(context).size.height, + width: width / 2, + height: height, child: GestureDetector( onTap: () { widget.controller.jumpToPage( @@ -156,7 +158,7 @@ class MangaControlsState extends State { ), ), Positioned( - height: MediaQuery.of(context).size.height / 5, + height: height / 5, left: 0, right: 0, bottom: 0, diff --git a/lib/novel/novel.dart b/lib/novel/novel.dart index 6f03d93..c09df8c 100755 --- a/lib/novel/novel.dart +++ b/lib/novel/novel.dart @@ -1,10 +1,10 @@ import 'dart:io'; -import 'dart:ui'; import 'package:anicross/novel/novel_parser.dart'; import 'package:anicross/widgets/grid.dart'; import 'package:anicross/models/info_models.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:isar/isar.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:file_picker/file_picker.dart'; @@ -32,39 +32,49 @@ class NovelPageState extends State { importNovel() async { bool permission = true; - if (Platform.isIOS || Platform.isAndroid) { + if (Platform.isAndroid) { if (await Permission.storage.isDenied) { - permission = (await Permission.storage.request()).isGranted; + permission = + (await Permission.manageExternalStorage.request()).isGranted; print("uwu"); } } if (permission) { final String? path = await FilePicker.platform.getDirectoryPath(); if (path != null) { - novels = await compute((directory) async { - DartPluginRegistrant.ensureInitialized(); - final Directory directory = Directory(path); - final List epubs = await directory.list(recursive: true).toList() - ..retainWhere( - (element) => element.path.endsWith(".epub"), + novels = await compute( + (stuff) async { + BackgroundIsolateBinaryMessenger.ensureInitialized( + stuff[1] as RootIsolateToken, ); - List data = []; - for (File i in epubs) { - final Novel novel = Novel(path: i.path); - await novel.parse(); - await novel.writeCover(); - novel.close(); - data.add( - AniData( - type: "novel", - title: novel.title!, - image: novel.cover!, - mediaId: i.path, - ), - ); - } - return data; - }, path); + final Directory directory = Directory(stuff[0] as String); + final List epubs = directory.listSync(recursive: true).toList() + ..retainWhere( + (element) => element.path.endsWith(".epub"), + ); + List data = []; + for (File i in epubs) { + print(i); + final Novel novel = Novel(path: i.path); + await novel.parse(); + await novel.writeCover(); + novel.close(); + data.add( + AniData( + type: "novel", + title: novel.title!, + image: novel.cover!, + mediaId: i.path, + ), + ); + } + return data; + }, + [ + path, + RootIsolateToken.instance, + ], + ); updateIsar(); } } diff --git a/lib/novel/novel_parser.dart b/lib/novel/novel_parser.dart index 9349f22..de687d4 100644 --- a/lib/novel/novel_parser.dart +++ b/lib/novel/novel_parser.dart @@ -2,8 +2,9 @@ import 'dart:convert'; import 'dart:io'; import 'package:archive/archive_io.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; -import 'package:image/image.dart'; +import 'package:flutter_html/flutter_html.dart'; +import 'package:image/image.dart' as img; +import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import 'package:xml2json/xml2json.dart'; @@ -66,21 +67,41 @@ class Novel { title = content?['metadata']?['dc\$title']?['\$t']; } - List parseChapters() { + List parseChapters(final String extract) { + extractArchiveToDisk(archive, extract); + Directory current = Directory( + p.normalize( + p.join(extract, root, '../'), + ), + ); List chapters = []; for (Map s in spine!['itemref']) { for (Map c in content!['manifest']['item']) { if (c.containsValue(s['idref'])) { + print(c); + print('${current.path}/${c['href']}'); chapters.add( - HtmlWidget( - utf8.decode( - archive.findFile("OEBPS/${c['href']}")?.content, - ), - renderMode: const ListViewMode( - primary: false, - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - ), + Html( + data: File('${current.path}/${c['href']}').readAsStringSync(), + customRenders: { + (context) => context.tree.element?.localName == "img": + CustomRender.widget( + widget: (context, p1) { + return Image.file( + File( + p.normalize( + p.join( + current.path, + c['href'], + "../", + context.tree.element!.attributes['src']!, + ), + ), + ), + ); + }, + ), + }, ), ); } @@ -98,7 +119,7 @@ class Novel { imagePath = '${documents.path}/.anicross/$title-${i['href'].split('/').last}'; //print(imagePath); - await (Command() + (img.Command() ..decodeImage( (archive.findFile( '${root?.split("/")[0]}/${i['href']}', diff --git a/lib/novel/novel_reader.dart b/lib/novel/novel_reader.dart index 72001e1..b5dada4 100644 --- a/lib/novel/novel_reader.dart +++ b/lib/novel/novel_reader.dart @@ -1,6 +1,8 @@ +import 'dart:io'; import 'package:anicross/models/info_models.dart'; import 'package:anicross/novel/novel_parser.dart'; import 'package:flutter/material.dart'; +import 'package:path_provider/path_provider.dart'; class NovelReader extends StatefulWidget { final AniData data; @@ -12,6 +14,7 @@ class NovelReader extends StatefulWidget { class NovelReaderState extends State { late final Novel novel = Novel(path: widget.data.mediaId!); + late final String extract; List chapters = []; @override @@ -19,9 +22,11 @@ class NovelReaderState extends State { super.initState(); Future.microtask( () async { + extract = '${(await getTemporaryDirectory()).path}/anicross-epub'; await novel.parse(); - chapters = novel.parseChapters(); - setState(() {}); + setState(() { + chapters = novel.parseChapters(extract); + }); }, ); } @@ -29,6 +34,7 @@ class NovelReaderState extends State { @override void dispose() { novel.close(); + Directory(extract).deleteSync(recursive: true); super.dispose(); } @@ -48,11 +54,119 @@ class NovelReaderState extends State { ) ], ) - : ListView( - primary: true, - semanticChildCount: chapters.length, - children: chapters, + : Stack( + children: [ + ListView( + primary: true, + semanticChildCount: chapters.length, + children: chapters, + ), + NovelControls(), + ], + ), + ); + } +} + +class NovelControls extends StatefulWidget { + //final PageController controller; + const NovelControls({super.key}); + + @override + State createState() => NovelControlsState(); +} + +class NovelControlsState extends State { + bool show = false; + + @override + void dispose() { + //widget.controller.dispose(); + super.dispose(); + } + + @override + Widget build(context) { + final width = MediaQuery.of(context).size.width; + final height = MediaQuery.of(context).size.height; + return SafeArea( + child: Stack( + children: [ + AnimatedOpacity( + duration: const Duration(milliseconds: 300), + opacity: !show ? 0.0 : 1.0, + child: Stack( + children: [ + // Positioned( + // bottom: 0, + // child: Text( + // ((widget.controller.page?.toInt() ?? 0) + 1).toString(), + // ), + // ), + Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Color(0xCC000000), + Color(0x00000000), + Color(0x00000000), + Color(0x00000000), + Color(0x00000000), + Color(0x00000000), + Color(0xCC000000), + ], + ), + ), + ), + Positioned( + top: 0, + left: 0, + width: width / 3, + height: height, + child: GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + print("left"); + // widget.controller.jumpToPage( + // (widget.controller.page! + 1).toInt(), + // ); + }, + ), + ), + Positioned( + top: 0, + right: 0, + width: width / 3, + height: height, + child: GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + // widget.controller.jumpToPage( + // (widget.controller.page! - 1).toInt(), + // ); + }, + ), + ), + Positioned( + height: height / 5, + left: 0, + right: 0, + bottom: 0, + child: GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () => setState( + () => (show) ? show = false : show = true, + ), + ), + ), + const BackButton(), + ], ), + ) + ], + ), ); } } diff --git a/lib/widgets/grid.dart b/lib/widgets/grid.dart index 62d55ba..202e902 100644 --- a/lib/widgets/grid.dart +++ b/lib/widgets/grid.dart @@ -32,9 +32,9 @@ class GridState extends State with AutomaticKeepAliveClientMixin { maxCrossAxisExtent: 280, ), delegate: SliverChildBuilderDelegate( - childCount: widget.length, + childCount: widget.data.length, (context, index) { - if (index >= widget.data.length - 5 && widget.length == null) { + if (index >= widget.data.length - 5 && widget.data.length >= 5) { widget.paginate(); } else { return Padding( diff --git a/pubspec.lock b/pubspec.lock index ae87a02..fc63c41 100755 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: "direct main" description: name: archive - sha256: d6347d54a2d8028e0437e3c099f66fdb8ae02c4720c1e7534c9f24c10351f85d + sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" url: "https://pub.dev" source: hosted - version: "3.3.6" + version: "3.3.7" args: dependency: transitive description: @@ -311,6 +311,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.3.0" + flutter_html: + dependency: "direct main" + description: + name: flutter_html + sha256: "342c7908f0a67bcec62b6e0f7cf23e23bafe7f64693665dd35be98d5e783bdfd" + url: "https://pub.dev" + source: hosted + version: "3.0.0-alpha.6" flutter_lints: dependency: "direct dev" description: @@ -333,7 +341,7 @@ packages: source: sdk version: "0.0.0" flutter_widget_from_html_core: - dependency: "direct main" + dependency: transitive description: name: flutter_widget_from_html_core sha256: e8f4f8b461a140ffb7c71f938bc76efc758893e7468843d9dbf70cb0b9e900cb @@ -659,6 +667,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.2" + numerus: + dependency: transitive + description: + name: numerus + sha256: "436759d84f233b40107d0cc31cfa92d24e0960afeb2e506be70926d4cddffd9e" + url: "https://pub.dev" + source: hosted + version: "2.0.0" octo_image: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 73bd4d9..ee92479 100755 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: flutter: sdk: flutter - flutter_widget_from_html_core: + flutter_html: archive: image: path: