mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
comic reading
This commit is contained in:
@@ -47,7 +47,7 @@ class _App {
|
||||
void pop() {
|
||||
if(rootNavigatorKey.currentState?.canPop() ?? false) {
|
||||
rootNavigatorKey.currentState?.pop();
|
||||
} else {
|
||||
} else if (mainNavigatorKey?.currentState?.canPop() ?? false) {
|
||||
mainNavigatorKey?.currentState?.pop();
|
||||
}
|
||||
}
|
||||
|
@@ -75,6 +75,10 @@ class _Settings {
|
||||
'showHistoryStatusOnTile': false,
|
||||
'blockedWords': [],
|
||||
'defaultSearchTarget': null,
|
||||
'autoPageTurningInterval': 5, // in seconds
|
||||
'readerMode': 'galleryLeftToRight', // values of [ReaderMode]
|
||||
'enableTapToTurnPages': true,
|
||||
'enablePageAnimation': true,
|
||||
};
|
||||
|
||||
operator[](String key) {
|
||||
|
@@ -39,25 +39,25 @@ class History {
|
||||
|
||||
String id;
|
||||
|
||||
/// readEpisode is a set of episode numbers that have been read.
|
||||
///
|
||||
/// The number of episodes is 1-based.
|
||||
Set<int> readEpisode;
|
||||
|
||||
int? maxPage;
|
||||
|
||||
History(this.type, this.time, this.title, this.subtitle, this.cover, this.ep,
|
||||
this.page, this.id,
|
||||
[this.readEpisode = const <int>{}, this.maxPage]);
|
||||
|
||||
History.fromModel(
|
||||
{required HistoryMixin model,
|
||||
required this.ep,
|
||||
required this.page,
|
||||
this.readEpisode = const <int>{},
|
||||
Set<int>? readChapters,
|
||||
DateTime? time})
|
||||
: type = model.historyType,
|
||||
title = model.title,
|
||||
subtitle = model.subTitle ?? '',
|
||||
cover = model.cover,
|
||||
id = model.id,
|
||||
readEpisode = readChapters ?? <int>{},
|
||||
time = time ?? DateTime.now();
|
||||
|
||||
Map<String, dynamic> toMap() => {
|
||||
@@ -168,50 +168,22 @@ class HistoryManager with ChangeNotifier {
|
||||
///
|
||||
/// This function would be called when user start reading.
|
||||
Future<void> addHistory(History newItem) async {
|
||||
var res = _db.select("""
|
||||
select * from history
|
||||
where id == ? and type == ?;
|
||||
""", [newItem.id, newItem.type.value]);
|
||||
if (res.isEmpty) {
|
||||
_db.execute("""
|
||||
insert into history (id, title, subtitle, cover, time, type, ep, page, readEpisode, max_page)
|
||||
_db.execute("""
|
||||
insert or replace into history (id, title, subtitle, cover, time, type, ep, page, readEpisode, max_page)
|
||||
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
""", [
|
||||
newItem.id,
|
||||
newItem.title,
|
||||
newItem.subtitle,
|
||||
newItem.cover,
|
||||
newItem.time.millisecondsSinceEpoch,
|
||||
newItem.type.value,
|
||||
newItem.ep,
|
||||
newItem.page,
|
||||
newItem.readEpisode.join(','),
|
||||
newItem.maxPage
|
||||
]);
|
||||
} else {
|
||||
_db.execute("""
|
||||
update history
|
||||
set time = ${DateTime.now().millisecondsSinceEpoch}
|
||||
where id == ? and type == ?;
|
||||
""", [newItem.id, newItem.type.value]);
|
||||
}
|
||||
updateCache();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> saveReadHistory(History history) async {
|
||||
_db.execute("""
|
||||
update history
|
||||
set time = ${DateTime.now().millisecondsSinceEpoch}, ep = ?, page = ?, readEpisode = ?, max_page = ?
|
||||
where id == ? and type == ?;
|
||||
""", [
|
||||
history.ep,
|
||||
history.page,
|
||||
history.readEpisode.join(','),
|
||||
history.maxPage,
|
||||
history.id,
|
||||
history.type.value
|
||||
newItem.id,
|
||||
newItem.title,
|
||||
newItem.subtitle,
|
||||
newItem.cover,
|
||||
newItem.time.millisecondsSinceEpoch,
|
||||
newItem.type.value,
|
||||
newItem.ep,
|
||||
newItem.page,
|
||||
newItem.readEpisode.join(','),
|
||||
newItem.maxPage
|
||||
]);
|
||||
updateCache();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import 'dart:async' show Future, StreamController;
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:venera/foundation/cache_manager.dart';
|
||||
|
81
lib/foundation/image_provider/reader_image.dart
Normal file
81
lib/foundation/image_provider/reader_image.dart
Normal file
@@ -0,0 +1,81 @@
|
||||
import 'dart:async' show Future, StreamController;
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:venera/foundation/cache_manager.dart';
|
||||
import 'package:venera/foundation/comic_source/comic_source.dart';
|
||||
import 'package:venera/foundation/consts.dart';
|
||||
import 'package:venera/network/app_dio.dart';
|
||||
import 'base_image_provider.dart';
|
||||
import 'reader_image.dart' as image_provider;
|
||||
|
||||
class ReaderImageProvider
|
||||
extends BaseImageProvider<image_provider.ReaderImageProvider> {
|
||||
/// Image provider for normal image.
|
||||
const ReaderImageProvider(this.imageKey, this.sourceKey, this.cid, this.eid);
|
||||
|
||||
final String imageKey;
|
||||
|
||||
final String? sourceKey;
|
||||
|
||||
final String cid;
|
||||
|
||||
final String eid;
|
||||
|
||||
@override
|
||||
Future<Uint8List> load(StreamController<ImageChunkEvent> chunkEvents) async {
|
||||
final cacheKey = "$imageKey@$sourceKey@$cid@$eid";
|
||||
final cache = await CacheManager().findCache(cacheKey);
|
||||
|
||||
if (cache != null) {
|
||||
return await cache.readAsBytes();
|
||||
}
|
||||
|
||||
var configs = <String, dynamic>{};
|
||||
if (sourceKey != null) {
|
||||
var comicSource = ComicSource.find(sourceKey!);
|
||||
configs = comicSource!.getImageLoadingConfig?.call(imageKey, cid, eid) ?? {};
|
||||
}
|
||||
configs['headers'] ??= {
|
||||
'user-agent': webUA,
|
||||
};
|
||||
|
||||
var dio = AppDio(BaseOptions(
|
||||
headers: configs['headers'],
|
||||
method: configs['method'] ?? 'GET',
|
||||
responseType: ResponseType.stream,
|
||||
));
|
||||
|
||||
var req = await dio.request<ResponseBody>(configs['url'] ?? imageKey,
|
||||
data: configs['data']);
|
||||
var stream = req.data?.stream ?? (throw "Error: Empty response body.");
|
||||
int? expectedBytes = req.data!.contentLength;
|
||||
if (expectedBytes == -1) {
|
||||
expectedBytes = null;
|
||||
}
|
||||
var buffer = <int>[];
|
||||
await for (var data in stream) {
|
||||
buffer.addAll(data);
|
||||
if (expectedBytes != null) {
|
||||
chunkEvents.add(ImageChunkEvent(
|
||||
cumulativeBytesLoaded: buffer.length,
|
||||
expectedTotalBytes: expectedBytes,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if(configs['onResponse'] != null) {
|
||||
buffer = configs['onResponse'](buffer);
|
||||
}
|
||||
|
||||
await CacheManager().writeCache(cacheKey, buffer);
|
||||
return Uint8List.fromList(buffer);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ReaderImageProvider> obtainKey(ImageConfiguration configuration) {
|
||||
return SynchronousFuture(this);
|
||||
}
|
||||
|
||||
@override
|
||||
String get key => "$imageKey@$sourceKey@$cid@$eid";
|
||||
}
|
Reference in New Issue
Block a user