mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
local comic reading
This commit is contained in:
@@ -6,10 +6,11 @@ import 'package:path_provider/path_provider.dart';
|
|||||||
import 'package:sqlite3/sqlite3.dart';
|
import 'package:sqlite3/sqlite3.dart';
|
||||||
import 'package:venera/foundation/comic_source/comic_source.dart';
|
import 'package:venera/foundation/comic_source/comic_source.dart';
|
||||||
import 'package:venera/foundation/comic_type.dart';
|
import 'package:venera/foundation/comic_type.dart';
|
||||||
|
import 'package:venera/utils/io.dart';
|
||||||
|
|
||||||
import 'app.dart';
|
import 'app.dart';
|
||||||
|
|
||||||
class LocalComic implements Comic{
|
class LocalComic implements Comic {
|
||||||
@override
|
@override
|
||||||
final String id;
|
final String id;
|
||||||
|
|
||||||
@@ -117,12 +118,12 @@ class LocalManager with ChangeNotifier {
|
|||||||
PRIMARY KEY (id, comic_type)
|
PRIMARY KEY (id, comic_type)
|
||||||
);
|
);
|
||||||
''');
|
''');
|
||||||
if(File('${App.dataPath}/local_path').existsSync()){
|
if (File('${App.dataPath}/local_path').existsSync()) {
|
||||||
path = File('${App.dataPath}/local_path').readAsStringSync();
|
path = File('${App.dataPath}/local_path').readAsStringSync();
|
||||||
} else {
|
} else {
|
||||||
if(App.isAndroid) {
|
if (App.isAndroid) {
|
||||||
var external = await getExternalStorageDirectories();
|
var external = await getExternalStorageDirectories();
|
||||||
if(external != null && external.isNotEmpty){
|
if (external != null && external.isNotEmpty) {
|
||||||
path = '${external.first.path}/local';
|
path = '${external.first.path}/local';
|
||||||
} else {
|
} else {
|
||||||
path = '${App.dataPath}/local';
|
path = '${App.dataPath}/local';
|
||||||
@@ -131,18 +132,18 @@ class LocalManager with ChangeNotifier {
|
|||||||
path = '${App.dataPath}/local';
|
path = '${App.dataPath}/local';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!Directory(path).existsSync()) {
|
if (!Directory(path).existsSync()) {
|
||||||
await Directory(path).create();
|
await Directory(path).create();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String findValidId(ComicType type) {
|
String findValidId(ComicType type) {
|
||||||
final res = _db.select('''
|
final res = _db.select(
|
||||||
|
'''
|
||||||
SELECT id FROM comics WHERE comic_type = ?
|
SELECT id FROM comics WHERE comic_type = ?
|
||||||
ORDER BY CAST(id AS INTEGER) DESC
|
ORDER BY CAST(id AS INTEGER) DESC
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
'''
|
'''[type.value],
|
||||||
[type.value],
|
|
||||||
);
|
);
|
||||||
if (res.isEmpty) {
|
if (res.isEmpty) {
|
||||||
return '1';
|
return '1';
|
||||||
@@ -229,4 +230,40 @@ class LocalManager with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
return LocalComic.fromRow(res.first);
|
return LocalComic.fromRow(res.first);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
Future<List<String>> getImages(String id, ComicType type, int ep) async {
|
||||||
|
var comic = find(id, type) ?? (throw "Comic Not Found");
|
||||||
|
var directory = Directory(FilePath.join(path, comic.directory));
|
||||||
|
if (comic.chapters != null) {
|
||||||
|
var cid = comic.chapters!.keys.elementAt(ep - 1);
|
||||||
|
directory = Directory(FilePath.join(directory.path, cid));
|
||||||
|
}
|
||||||
|
var files = <File>[];
|
||||||
|
await for (var entity in directory.list()) {
|
||||||
|
if (entity is File) {
|
||||||
|
if (entity.absolute.path.replaceFirst(path, '').substring(1) ==
|
||||||
|
comic.cover) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
files.add(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
files.sort((a, b) {
|
||||||
|
var ai = int.tryParse(a.name.split('.').first);
|
||||||
|
var bi = int.tryParse(b.name.split('.').first);
|
||||||
|
if(ai != null && bi != null) {
|
||||||
|
return ai.compareTo(bi);
|
||||||
|
}
|
||||||
|
return a.name.compareTo(b.name);
|
||||||
|
});
|
||||||
|
return files.map((e) => "file://${e.path}").toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> isDownloaded(String id, ComicType type, int ep) async {
|
||||||
|
var comic = find(id, type);
|
||||||
|
if(comic == null) return false;
|
||||||
|
if(comic.chapters == null) return true;
|
||||||
|
var eid = comic.chapters!.keys.elementAt(ep);
|
||||||
|
return Directory(FilePath.join(path, comic.directory, eid)).exists();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -462,7 +462,7 @@ abstract mixin class _ComicPageActions {
|
|||||||
void read([int? ep, int? page]) {
|
void read([int? ep, int? page]) {
|
||||||
App.rootContext.to(
|
App.rootContext.to(
|
||||||
() => Reader(
|
() => Reader(
|
||||||
source: comicSource,
|
type: comic.comicType,
|
||||||
cid: comic.id,
|
cid: comic.id,
|
||||||
name: comic.title,
|
name: comic.title,
|
||||||
chapters: comic.chapters,
|
chapters: comic.chapters,
|
||||||
|
@@ -21,23 +21,43 @@ class _ReaderImagesState extends State<_ReaderImages> {
|
|||||||
void load() async {
|
void load() async {
|
||||||
if (inProgress) return;
|
if (inProgress) return;
|
||||||
inProgress = true;
|
inProgress = true;
|
||||||
var res = await context.reader.widget.source.loadComicPages!(
|
if (context.reader.type == ComicType.local ||
|
||||||
context.reader.widget.cid,
|
(await LocalManager().isDownloaded(
|
||||||
context.reader.widget.chapters?.keys
|
context.reader.cid, context.reader.type, context.reader.chapter))) {
|
||||||
.elementAt(context.reader.chapter - 1),
|
try {
|
||||||
);
|
var images = await LocalManager().getImages(
|
||||||
if (res.error) {
|
context.reader.cid, context.reader.type, context.reader.chapter);
|
||||||
setState(() {
|
setState(() {
|
||||||
error = res.errorMessage;
|
context.reader.images = images;
|
||||||
context.reader.isLoading = false;
|
context.reader.isLoading = false;
|
||||||
inProgress = false;
|
inProgress = false;
|
||||||
});
|
});
|
||||||
|
} catch (e) {
|
||||||
|
setState(() {
|
||||||
|
error = e.toString();
|
||||||
|
context.reader.isLoading = false;
|
||||||
|
inProgress = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setState(() {
|
var res = await context.reader.type.comicSource!.loadComicPages!(
|
||||||
context.reader.images = res.data;
|
context.reader.widget.cid,
|
||||||
context.reader.isLoading = false;
|
context.reader.widget.chapters?.keys
|
||||||
inProgress = false;
|
.elementAt(context.reader.chapter - 1),
|
||||||
});
|
);
|
||||||
|
if (res.error) {
|
||||||
|
setState(() {
|
||||||
|
error = res.errorMessage;
|
||||||
|
context.reader.isLoading = false;
|
||||||
|
inProgress = false;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
context.reader.images = res.data;
|
||||||
|
context.reader.isLoading = false;
|
||||||
|
inProgress = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
context.readerScaffold.update();
|
context.readerScaffold.update();
|
||||||
}
|
}
|
||||||
@@ -196,12 +216,17 @@ class _GalleryModeState extends State<_GalleryMode>
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImageProvider _createImageProvider(int page, BuildContext context) {
|
ImageProvider _createImageProvider(int page, BuildContext context) {
|
||||||
return ReaderImageProvider(
|
var imageKey = context.reader.images![page-1];
|
||||||
context.reader.images![page - 1],
|
if(imageKey.startsWith('file://')) {
|
||||||
context.reader.widget.source.key,
|
return FileImage(File(imageKey.replaceFirst("file://", '')));
|
||||||
context.reader.cid,
|
} else {
|
||||||
context.reader.eid,
|
return ReaderImageProvider(
|
||||||
);
|
imageKey,
|
||||||
|
context.reader.type.comicSource!.key,
|
||||||
|
context.reader.cid,
|
||||||
|
context.reader.eid,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _precacheImage(int page, BuildContext context) {
|
void _precacheImage(int page, BuildContext context) {
|
||||||
|
@@ -10,9 +10,11 @@ import 'package:photo_view/photo_view_gallery.dart';
|
|||||||
import 'package:venera/components/components.dart';
|
import 'package:venera/components/components.dart';
|
||||||
import 'package:venera/foundation/app.dart';
|
import 'package:venera/foundation/app.dart';
|
||||||
import 'package:venera/foundation/appdata.dart';
|
import 'package:venera/foundation/appdata.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/history.dart';
|
||||||
import 'package:venera/foundation/image_provider/reader_image.dart';
|
import 'package:venera/foundation/image_provider/reader_image.dart';
|
||||||
|
import 'package:venera/foundation/local.dart';
|
||||||
|
import 'package:venera/utils/io.dart';
|
||||||
import 'package:venera/utils/translations.dart';
|
import 'package:venera/utils/translations.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
@@ -32,7 +34,7 @@ extension _ReaderContext on BuildContext {
|
|||||||
class Reader extends StatefulWidget {
|
class Reader extends StatefulWidget {
|
||||||
const Reader({
|
const Reader({
|
||||||
super.key,
|
super.key,
|
||||||
required this.source,
|
required this.type,
|
||||||
required this.cid,
|
required this.cid,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.chapters,
|
required this.chapters,
|
||||||
@@ -41,7 +43,7 @@ class Reader extends StatefulWidget {
|
|||||||
this.initialChapter,
|
this.initialChapter,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ComicSource source;
|
final ComicType type;
|
||||||
|
|
||||||
final String cid;
|
final String cid;
|
||||||
|
|
||||||
@@ -72,6 +74,8 @@ class _ReaderState extends State<Reader> with _ReaderLocation, _ReaderWindow {
|
|||||||
@override
|
@override
|
||||||
int get maxPage => images?.length ?? 1;
|
int get maxPage => images?.length ?? 1;
|
||||||
|
|
||||||
|
ComicType get type => widget.type;
|
||||||
|
|
||||||
String get cid => widget.cid;
|
String get cid => widget.cid;
|
||||||
|
|
||||||
String get eid => widget.chapters?.keys.elementAt(chapter - 1) ?? '0';
|
String get eid => widget.chapters?.keys.elementAt(chapter - 1) ?? '0';
|
||||||
|
Reference in New Issue
Block a user