fix local comic display

This commit is contained in:
nyne
2024-10-27 18:39:33 +08:00
parent 27d25db407
commit f17af25e2c
16 changed files with 123 additions and 24 deletions

View File

@@ -149,6 +149,11 @@ class ComicTile extends StatelessWidget {
ImageProvider image;
if (comic is LocalComic) {
image = FileImage((comic as LocalComic).coverFile);
} else if (comic.cover.startsWith('file://')) {
image = FileImage(File(comic.cover.substring(7)));
} else if (comic.sourceKey == 'local') {
var localComic = LocalManager().find(comic.id, ComicType.local);
image = FileImage(localComic!.coverFile);
} else {
image = CachedImageProvider(comic.cover, sourceKey: comic.sourceKey);
}

View File

@@ -26,6 +26,7 @@ import 'package:venera/network/cloudflare.dart';
import 'package:venera/pages/comic_page.dart';
import 'package:venera/pages/favorites/favorites_page.dart';
import 'package:venera/utils/ext.dart';
import 'package:venera/utils/io.dart';
import 'package:venera/utils/tags_translation.dart';
import 'package:venera/utils/translations.dart';

View File

@@ -113,6 +113,7 @@ abstract class LoadingState<T extends StatefulWidget, S extends Object>
if (res.success) {
return res;
} else {
if(!mounted) return res;
if (retry >= 3) {
return res;
}
@@ -170,6 +171,7 @@ abstract class LoadingState<T extends StatefulWidget, S extends Object>
isLoading = true;
Future.microtask(() {
loadDataWithRetry().then((value) async {
if(!mounted) return;
if (value.success) {
data = value.data;
await onDataLoaded();

View File

@@ -11,6 +11,14 @@ class ComicType {
@override
int get hashCode => value.hashCode;
String get sourceKey {
if(this == local) {
return "local";
} else {
return comicSource!.key;
}
}
ComicSource? get comicSource {
if(this == local) {
return null;

View File

@@ -19,6 +19,11 @@ extension Navigation on BuildContext {
.push<T>(AppPageRoute(builder: (context) => builder()));
}
Future<void> toReplacement<T>(Widget Function() builder) {
return Navigator.of(this)
.pushReplacement(AppPageRoute(builder: (context) => builder()));
}
double get width => MediaQuery.of(this).size.width;
double get height => MediaQuery.of(this).size.height;

View File

@@ -55,7 +55,7 @@ class FavoriteItem implements Comic {
@override
String toString() {
var s = "FavoriteItem: $name $author $coverPath $hashCode $tags";
if(s.length > 100) {
if (s.length > 100) {
return s.substring(0, 100);
}
return s;
@@ -65,7 +65,9 @@ class FavoriteItem implements Comic {
String get cover => coverPath;
@override
String get description => "$time | ${type.comicSource?.name ?? "Unknown"}";
String get description {
return "$time | ${type == ComicType.local ? 'local' : type.comicSource?.name ?? "Unknown"}";
}
@override
String? get favoriteId => null;
@@ -77,7 +79,7 @@ class FavoriteItem implements Comic {
int? get maxPage => null;
@override
String get sourceKey => type.comicSource?.key ?? "Unknown:${type.value}";
String get sourceKey => type == ComicType.local ? 'local' : type.comicSource?.key ?? "Unknown:${type.value}";
@override
double? get stars => null;
@@ -514,6 +516,13 @@ class LocalFavoritesManager {
update "$folder"
set name = ?, author = ?, cover_path = ?, tags = ?
where id == ? and type == ?;
""", [comic.name, comic.author, comic.coverPath, comic.tags.join(","), comic.id, comic.type.value]);
""", [
comic.name,
comic.author,
comic.coverPath,
comic.tags.join(","),
comic.id,
comic.type.value
]);
}
}

View File

@@ -79,7 +79,7 @@ class LocalComic with HistoryMixin implements Comic {
String get description => "";
@override
String get sourceKey => comicType.comicSource?.key ?? '_local_';
String get sourceKey => comicType == ComicType.local ? "local" : "";
@override
Map<String, dynamic> toJson() {
@@ -214,7 +214,7 @@ class LocalManager with ChangeNotifier {
SELECT id FROM comics WHERE comic_type = ?
ORDER BY CAST(id AS INTEGER) DESC
LIMIT 1;
'''[type.value],
''', [type.value],
);
if (res.isEmpty) {
return '1';
@@ -341,7 +341,7 @@ class LocalManager with ChangeNotifier {
if (comic == null) return false;
if (comic.chapters == null) return true;
return comic.downloadedChapters
.contains(comic.chapters!.keys.elementAt(ep));
.contains(comic.chapters!.keys.elementAt(ep-1));
}
List<DownloadTask> downloadingTasks = [];

View File

@@ -161,7 +161,7 @@ class NetworkCacheManager implements Interceptor {
return handler.next(response);
}
var size = _calculateSize(response.data);
if(size != null && size < 1024 * 1024) {
if(size != null && size < 1024 * 1024 && size > 1024) {
var cache = NetworkCache(
uri: response.requestOptions.uri,
requestHeaders: response.requestOptions.headers,

View File

@@ -203,6 +203,8 @@ class ImagesDownloadTask extends DownloadTask with _TransferSpeedMixin {
@override
void resume() async {
if (_isRunning) return;
_isError = false;
_message = "Resuming...";
_isRunning = true;
notifyListeners();
runRecorder();

View File

@@ -72,6 +72,8 @@ class _ComicPageState extends LoadingState<ComicPage, ComicDetails>
}
}
var isFirst = true;
@override
Widget buildContent(BuildContext context, ComicDetails data) {
return SmoothCustomScrollView(
@@ -91,8 +93,37 @@ class _ComicPageState extends LoadingState<ComicPage, ComicDetails>
@override
Future<Res<ComicDetails>> loadData() async {
if (widget.sourceKey == 'local') {
var localComic = LocalManager().find(widget.id, ComicType.local);
if (localComic == null) {
return const Res.error('Local comic not found');
}
var history = await HistoryManager().find(widget.id, ComicType.local);
if(isFirst) {
Future.microtask(() {
App.rootContext.to(() {
return Reader(
type: ComicType.local,
cid: widget.id,
name: localComic.title,
chapters: localComic.chapters,
history: history ??
History.fromModel(
model: localComic,
ep: 0,
page: 0,
),
);
});
App.mainNavigatorKey!.currentContext!.pop();
});
isFirst = false;
}
await Future.delayed(const Duration(milliseconds: 200));
return const Res.error('Local comic');
}
var comicSource = ComicSource.find(widget.sourceKey);
if(comicSource == null) {
if (comicSource == null) {
return const Res.error('Comic source not found');
}
isAddToLocalFav = LocalFavoritesManager().isExist(
@@ -101,7 +132,7 @@ class _ComicPageState extends LoadingState<ComicPage, ComicDetails>
);
history = await HistoryManager()
.find(widget.id, ComicType(widget.sourceKey.hashCode));
return comicSource!.loadComicInfo!(widget.id);
return comicSource.loadComicInfo!(widget.id);
}
@override
@@ -500,7 +531,11 @@ abstract mixin class _ComicPageActions {
}
void share() {
Share.shareText(comic.title);
var text = comic.title;
if (comic.url != null) {
text += '\n${comic.url}';
}
Share.shareText(text);
}
/// read the comic
@@ -694,8 +729,7 @@ abstract mixin class _ComicPageActions {
setState(() {
isLoading = true;
});
comicSource.starRatingFunc!
(comic.id, rating.round())
comicSource.starRatingFunc!(comic.id, rating.round())
.then((value) {
if (value.success) {
App.rootContext

View File

@@ -66,7 +66,16 @@ class _ExplorePageState extends State<ExplorePage>
return NetworkError(
message: "No Explore Pages".tl,
retry: () {
setState(() {});
setState(() {
pages = ComicSource.all()
.map((e) => e.explorePages)
.expand((e) => e.map((e) => e.title))
.toList();
controller = TabController(
length: pages.length,
vsync: this,
);
});
},
withAppbar: false,
);

View File

@@ -98,7 +98,7 @@ void addFavorite(Comic comic) {
name: comic.title,
coverPath: comic.cover,
author: comic.subtitle ?? '',
type: ComicType(comic.sourceKey.hashCode),
type: ComicType((comic.sourceKey == 'local' ? 0 : comic.sourceKey.hashCode)),
tags: comic.tags ?? [],
),
);

View File

@@ -4,6 +4,8 @@ import 'package:venera/foundation/app.dart';
import 'package:venera/foundation/comic_source/comic_source.dart';
import 'package:venera/foundation/comic_type.dart';
import 'package:venera/foundation/history.dart';
import 'package:venera/foundation/local.dart';
import 'package:venera/utils/ext.dart';
import 'package:venera/utils/translations.dart';
class HistoryPage extends StatefulWidget {
@@ -78,9 +80,19 @@ 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,
e.cover,
cover,
e.id,
e.subtitle,
null,
@@ -100,7 +112,7 @@ class _HistoryPageState extends State<HistoryPage> {
icon: Icons.remove,
text: 'Remove'.tl,
onClick: () {
if(c.sourceKey.startsWith("Invalid")) {
if (c.sourceKey.startsWith("Invalid")) {
HistoryManager().remove(
c.id,
ComicType(int.parse(c.sourceKey.split(':')[1])),

View File

@@ -15,6 +15,7 @@ import 'package:venera/pages/comic_source_page.dart';
import 'package:venera/pages/downloading_page.dart';
import 'package:venera/pages/history_page.dart';
import 'package:venera/pages/search_page.dart';
import 'package:venera/utils/ext.dart';
import 'package:venera/utils/io.dart';
import 'package:venera/utils/translations.dart';
@@ -155,12 +156,26 @@ 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,
);
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(
() => ComicPage(
id: history[index].id,
sourceKey: history[index].type.comicSource!.key,
sourceKey: history[index].type.sourceKey,
),
);
},
@@ -177,10 +192,7 @@ class _HistoryState extends State<_History> {
),
clipBehavior: Clip.antiAlias,
child: AnimatedImage(
image: CachedImageProvider(
history[index].cover,
sourceKey: history[index].type.comicSource?.key,
),
image: imageProvider,
width: 96,
height: 128,
fit: BoxFit.cover,

View File

@@ -196,7 +196,7 @@ class _SearchPageState extends State<SearchPage> {
runSpacing: 8,
children: sources.map((e) {
return OptionChip(
text: e.name.tl,
text: e.name,
isSelected: searchTarget == e.key,
onTap: () {
setState(() {

View File

@@ -75,7 +75,7 @@ extension StringExt on String{
bool _isURL(){
final regex = RegExp(
r'^((http|https|ftp)://)?[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-|]*[\w@?^=%&/~+#-])?$',
r'^((http|https|ftp)://)[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-|]*[\w@?^=%&/~+#-])?$',
caseSensitive: false);
return regex.hasMatch(this);
}