mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
fix local comic display
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
@@ -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';
|
||||
|
||||
|
@@ -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();
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@@ -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 = [];
|
||||
|
@@ -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,
|
||||
|
@@ -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();
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
);
|
||||
|
@@ -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 ?? [],
|
||||
),
|
||||
);
|
||||
|
@@ -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])),
|
||||
|
@@ -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,
|
||||
|
@@ -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(() {
|
||||
|
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user