From 21bf9d72c0e3a6196e8b5e248f513cc1946e931f Mon Sep 17 00:00:00 2001 From: nyne Date: Mon, 2 Dec 2024 11:19:06 +0800 Subject: [PATCH] Add HistoryImageProvider --- lib/components/comic.dart | 2 + lib/components/components.dart | 1 + lib/foundation/history.dart | 49 +++++++++++++++- .../history_image_provider.dart | 57 +++++++++++++++++++ lib/pages/history_page.dart | 28 +-------- lib/pages/home_page.dart | 18 +----- 6 files changed, 111 insertions(+), 44 deletions(-) create mode 100644 lib/foundation/image_provider/history_image_provider.dart diff --git a/lib/components/comic.dart b/lib/components/comic.dart index d01f63a..d175649 100644 --- a/lib/components/comic.dart +++ b/lib/components/comic.dart @@ -164,6 +164,8 @@ class ComicTile extends StatelessWidget { ImageProvider image; if (comic is LocalComic) { image = LocalComicImageProvider(comic as LocalComic); + } else if (comic is History) { + image = HistoryImageProvider(comic as History); } else if (comic.sourceKey == 'local') { var localComic = LocalManager().find(comic.id, ComicType.local); if (localComic == null) { diff --git a/lib/components/components.dart b/lib/components/components.dart index ea377c1..719bc79 100644 --- a/lib/components/components.dart +++ b/lib/components/components.dart @@ -19,6 +19,7 @@ import 'package:venera/foundation/consts.dart'; import 'package:venera/foundation/favorites.dart'; import 'package:venera/foundation/history.dart'; import 'package:venera/foundation/image_provider/cached_image.dart'; +import 'package:venera/foundation/image_provider/history_image_provider.dart'; import 'package:venera/foundation/image_provider/local_comic_image.dart'; import 'package:venera/foundation/local.dart'; import 'package:venera/foundation/res.dart'; diff --git a/lib/foundation/history.dart b/lib/foundation/history.dart index 71ef40d..d5def70 100644 --- a/lib/foundation/history.dart +++ b/lib/foundation/history.dart @@ -2,7 +2,9 @@ import 'dart:async'; import 'package:flutter/widgets.dart' show ChangeNotifier; import 'package:sqlite3/sqlite3.dart'; +import 'package:venera/foundation/comic_source/comic_source.dart'; import 'package:venera/foundation/comic_type.dart'; +import 'package:venera/utils/translations.dart'; import 'app.dart'; @@ -22,15 +24,18 @@ abstract mixin class HistoryMixin { HistoryType get historyType; } -class History { +class History implements Comic { HistoryType type; DateTime time; + @override String title; + @override String subtitle; + @override String cover; int ep; @@ -44,6 +49,7 @@ class History { /// The number of episodes is 1-based. Set readEpisode; + @override int? maxPage; History.fromModel( @@ -137,6 +143,47 @@ class History { @override int get hashCode => Object.hash(id, type); + + @override + String get description { + var res = ""; + if (ep >= 1) { + res += "Chapter @ep".tlParams({ + "ep": ep, + }); + } + if (page >= 1) { + if (ep >= 1) { + res += " - "; + } + res += "Page @page".tlParams({ + "page": page, + }); + } + return res; + } + + @override + String? get favoriteId => null; + + @override + String? get language => null; + + @override + String get sourceKey => type == ComicType.local + ? 'local' + : type.comicSource?.key ?? "Unknown:${type.value}"; + + @override + double? get stars => null; + + @override + List? get tags => null; + + @override + Map toJson() { + throw UnimplementedError(); + } } class HistoryManager with ChangeNotifier { diff --git a/lib/foundation/image_provider/history_image_provider.dart b/lib/foundation/image_provider/history_image_provider.dart new file mode 100644 index 0000000..4e2475a --- /dev/null +++ b/lib/foundation/image_provider/history_image_provider.dart @@ -0,0 +1,57 @@ +import 'dart:async' show Future, StreamController; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:venera/foundation/local.dart'; +import 'package:venera/network/images.dart'; +import '../history.dart'; +import 'base_image_provider.dart'; +import 'history_image_provider.dart' as image_provider; + +class HistoryImageProvider + extends BaseImageProvider { + /// Image provider for normal image. + /// + /// [url] is the url of the image. Local file path is also supported. + const HistoryImageProvider(this.history); + + final History history; + + @override + Future load(StreamController chunkEvents) async { + var url = history.cover; + if (!url.contains('/')) { + var localComic = LocalManager().find(history.id, history.type); + if (localComic != null) { + return localComic.coverFile.readAsBytes(); + } + var comicSource = + history.type.comicSource ?? (throw "Comic source not found."); + var comic = await comicSource.loadComicInfo!(history.id); + url = comic.data.cover; + history.cover = url; + HistoryManager().addHistory(history); + } + await for (var progress in ImageDownloader.loadThumbnail( + url, + history.type.sourceKey, + history.id, + )) { + chunkEvents.add(ImageChunkEvent( + cumulativeBytesLoaded: progress.currentBytes, + expectedTotalBytes: progress.totalBytes, + )); + if (progress.imageBytes != null) { + return progress.imageBytes!; + } + } + throw "Error: Empty response body."; + } + + @override + Future obtainKey(ImageConfiguration configuration) { + return SynchronousFuture(this); + } + + @override + String get key => "history${history.id}${history.type.value}"; +} diff --git a/lib/pages/history_page.dart b/lib/pages/history_page.dart index 37e8c4e..36a7165 100644 --- a/lib/pages/history_page.dart +++ b/lib/pages/history_page.dart @@ -78,33 +78,7 @@ class _HistoryPageState extends State { ], ), SliverGridComics( - comics: comics.map( - (e) { - var cover = e.cover; - if (!cover.isURL) { - var localComic = LocalManager().find( - e.id, - e.type, - ); - if(localComic != null) { - cover = "file://${localComic.coverFile.path}"; - } - } - return Comic( - e.title, - cover, - e.id, - e.subtitle, - null, - getDescription(e), - e.type == ComicType.local - ? 'local' - : e.type.comicSource?.key ?? "Unknown:${e.type.value}", - null, - null, - ); - }, - ).toList(), + comics: comics, badgeBuilder: (c) { return ComicSource.find(c.sourceKey)?.name; }, diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 32ca613..d4e0ee8 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -7,6 +7,7 @@ import 'package:venera/foundation/consts.dart'; import 'package:venera/foundation/favorites.dart'; import 'package:venera/foundation/history.dart'; import 'package:venera/foundation/image_provider/cached_image.dart'; +import 'package:venera/foundation/image_provider/history_image_provider.dart'; import 'package:venera/foundation/image_provider/local_comic_image.dart'; import 'package:venera/foundation/local.dart'; import 'package:venera/pages/accounts_page.dart'; @@ -265,21 +266,6 @@ class _HistoryState extends State<_History> { scrollDirection: Axis.horizontal, itemCount: history.length, itemBuilder: (context, index) { - var cover = history[index].cover; - ImageProvider imageProvider = CachedImageProvider( - cover, - sourceKey: history[index].type.comicSource?.key, - cid: history[index].id, - ); - if (!cover.isURL) { - var localComic = LocalManager().find( - history[index].id, - history[index].type, - ); - if (localComic != null) { - imageProvider = FileImage(localComic.coverFile); - } - } return InkWell( onTap: () { context.to( @@ -302,7 +288,7 @@ class _HistoryState extends State<_History> { ), clipBehavior: Clip.antiAlias, child: AnimatedImage( - image: imageProvider, + image: HistoryImageProvider(history[index]), width: 96, height: 128, fit: BoxFit.cover,