Add HistoryImageProvider

This commit is contained in:
2024-12-02 11:19:06 +08:00
committed by nyne
parent 035a84380c
commit 21bf9d72c0
6 changed files with 111 additions and 44 deletions

View File

@@ -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) {

View File

@@ -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';

View File

@@ -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<int> 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<String>? get tags => null;
@override
Map<String, dynamic> toJson() {
throw UnimplementedError();
}
}
class HistoryManager with ChangeNotifier {

View File

@@ -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.HistoryImageProvider> {
/// 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<Uint8List> load(StreamController<ImageChunkEvent> 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<HistoryImageProvider> obtainKey(ImageConfiguration configuration) {
return SynchronousFuture(this);
}
@override
String get key => "history${history.id}${history.type.value}";
}

View File

@@ -78,33 +78,7 @@ class _HistoryPageState extends State<HistoryPage> {
],
),
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;
},

View File

@@ -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,