mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
fix deleting local comic, favorites
This commit is contained in:
@@ -50,7 +50,10 @@ class ComicTile extends StatelessWidget {
|
|||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon: Icons.chrome_reader_mode_outlined,
|
icon: Icons.chrome_reader_mode_outlined,
|
||||||
text: 'Details'.tl,
|
text: 'Details'.tl,
|
||||||
onClick: _onTap,
|
onClick: () {
|
||||||
|
App.mainNavigatorKey?.currentContext
|
||||||
|
?.to(() => ComicPage(id: comic.id, sourceKey: comic.sourceKey));
|
||||||
|
},
|
||||||
),
|
),
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon: Icons.copy,
|
icon: Icons.copy,
|
||||||
|
@@ -180,7 +180,7 @@ class _SidebarBodyState extends State<SidebarBody> {
|
|||||||
width: 8,
|
width: 8,
|
||||||
),
|
),
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: "返回",
|
message: "Back".tl,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
iconSize: 25,
|
iconSize: 25,
|
||||||
icon: const Icon(Icons.arrow_back),
|
icon: const Icon(Icons.arrow_back),
|
||||||
|
@@ -3,6 +3,7 @@ import 'package:venera/foundation/appdata.dart';
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'app.dart';
|
import 'app.dart';
|
||||||
|
import 'comic_source/comic_source.dart';
|
||||||
import 'comic_type.dart';
|
import 'comic_type.dart';
|
||||||
|
|
||||||
String _getCurTime() {
|
String _getCurTime() {
|
||||||
@@ -12,11 +13,13 @@ String _getCurTime() {
|
|||||||
.substring(0, 19);
|
.substring(0, 19);
|
||||||
}
|
}
|
||||||
|
|
||||||
class FavoriteItem {
|
class FavoriteItem implements Comic {
|
||||||
String name;
|
String name;
|
||||||
String author;
|
String author;
|
||||||
ComicType type;
|
ComicType type;
|
||||||
|
@override
|
||||||
List<String> tags;
|
List<String> tags;
|
||||||
|
@override
|
||||||
String id;
|
String id;
|
||||||
String coverPath;
|
String coverPath;
|
||||||
String time = _getCurTime();
|
String time = _getCurTime();
|
||||||
@@ -57,6 +60,38 @@ class FavoriteItem {
|
|||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get cover => coverPath;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get description => "$time | ${type.comicSource?.name ?? "Unknown"}";
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get favoriteId => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get language => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int? get maxPage => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sourceKey => type.comicSource?.key ?? "Unknown:${type.value}";
|
||||||
|
|
||||||
|
@override
|
||||||
|
double? get stars => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get subtitle => author;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => name;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FavoriteItemWithFolderInfo {
|
class FavoriteItemWithFolderInfo {
|
||||||
|
53
lib/foundation/image_provider/local_favorite_image.dart
Normal file
53
lib/foundation/image_provider/local_favorite_image.dart
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import 'dart:async' show Future, StreamController;
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:venera/foundation/app.dart';
|
||||||
|
import 'package:venera/foundation/comic_source/comic_source.dart';
|
||||||
|
import 'package:venera/network/images.dart';
|
||||||
|
import 'package:venera/utils/io.dart';
|
||||||
|
import 'base_image_provider.dart';
|
||||||
|
import 'local_favorite_image.dart' as image_provider;
|
||||||
|
|
||||||
|
class LocalFavoriteImageProvider
|
||||||
|
extends BaseImageProvider<image_provider.LocalFavoriteImageProvider> {
|
||||||
|
/// Image provider for normal image.
|
||||||
|
const LocalFavoriteImageProvider(this.url, this.id, this.intKey);
|
||||||
|
|
||||||
|
final String url;
|
||||||
|
|
||||||
|
final String id;
|
||||||
|
|
||||||
|
final int intKey;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> load(StreamController<ImageChunkEvent> chunkEvents) async {
|
||||||
|
var sourceKey = ComicSource.fromIntKey(intKey)?.key;
|
||||||
|
var fileName = key.hashCode.toString();
|
||||||
|
var file = File(FilePath.join(App.dataPath, 'favorite_cover', fileName));
|
||||||
|
if (await file.exists()) {
|
||||||
|
return await file.readAsBytes();
|
||||||
|
} else {
|
||||||
|
await file.create(recursive: true);
|
||||||
|
}
|
||||||
|
await for (var progress in ImageDownloader.loadThumbnail(url, sourceKey)) {
|
||||||
|
chunkEvents.add(ImageChunkEvent(
|
||||||
|
cumulativeBytesLoaded: progress.currentBytes,
|
||||||
|
expectedTotalBytes: progress.totalBytes,
|
||||||
|
));
|
||||||
|
if(progress.imageBytes != null) {
|
||||||
|
var data = progress.imageBytes!;
|
||||||
|
await file.writeAsBytes(data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw "Error: Empty response body.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LocalFavoriteImageProvider> obtainKey(ImageConfiguration configuration) {
|
||||||
|
return SynchronousFuture(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get key => id + intKey.toString();
|
||||||
|
}
|
@@ -26,7 +26,7 @@ class LocalComic with HistoryMixin implements Comic {
|
|||||||
@override
|
@override
|
||||||
final List<String> tags;
|
final List<String> tags;
|
||||||
|
|
||||||
/// name of the directory, which is in `LocalManager.path`
|
/// The name of the directory where the comic is stored
|
||||||
final String directory;
|
final String directory;
|
||||||
|
|
||||||
/// key: chapter id, value: chapter title
|
/// key: chapter id, value: chapter title
|
||||||
@@ -143,6 +143,7 @@ class LocalManager with ChangeNotifier {
|
|||||||
|
|
||||||
late Database _db;
|
late Database _db;
|
||||||
|
|
||||||
|
/// path to the directory where all the comics are stored
|
||||||
late String path;
|
late String path;
|
||||||
|
|
||||||
// return error message if failed
|
// return error message if failed
|
||||||
@@ -413,4 +414,11 @@ class LocalManager with ChangeNotifier {
|
|||||||
saveCurrentDownloadingTasks();
|
saveCurrentDownloadingTasks();
|
||||||
downloadingTasks.first.resume();
|
downloadingTasks.first.resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void deleteComic(LocalComic c) {
|
||||||
|
var dir = Directory(FilePath.join(path, c.directory));
|
||||||
|
dir.deleteSync(recursive: true);
|
||||||
|
remove(c.id, c.comicType);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -64,6 +64,7 @@ class _CommentsPageState extends State<CommentsPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
resizeToAvoidBottomInset: false,
|
||||||
appBar: Appbar(
|
appBar: Appbar(
|
||||||
title: Text("Comments".tl),
|
title: Text("Comments".tl),
|
||||||
),
|
),
|
||||||
|
@@ -42,7 +42,12 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
|
|||||||
)
|
)
|
||||||
: const SizedBox(),
|
: const SizedBox(),
|
||||||
),
|
),
|
||||||
title: Text(favPage.folder ?? "Unselected".tl),
|
title: GestureDetector(
|
||||||
|
onTap: context.width < _kTwoPanelChangeWidth
|
||||||
|
? favPage.showFolderSelector
|
||||||
|
: null,
|
||||||
|
child: Text(favPage.folder ?? "Unselected".tl),
|
||||||
|
),
|
||||||
actions: [
|
actions: [
|
||||||
MenuButton(
|
MenuButton(
|
||||||
entries: [
|
entries: [
|
||||||
@@ -110,20 +115,7 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
SliverGridComics(
|
SliverGridComics(
|
||||||
comics: comics.map((e) {
|
comics: comics,
|
||||||
var comicSource = e.type.comicSource;
|
|
||||||
return Comic(
|
|
||||||
e.name,
|
|
||||||
e.coverPath,
|
|
||||||
e.id,
|
|
||||||
e.author,
|
|
||||||
e.tags,
|
|
||||||
"${e.time} | ${comicSource?.name ?? "Unknown"}",
|
|
||||||
comicSource?.key ?? "Unknown",
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
menuBuilder: (c) {
|
menuBuilder: (c) {
|
||||||
return [
|
return [
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
@@ -138,7 +130,7 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
|
|||||||
LocalFavoritesManager().deleteComicWithId(
|
LocalFavoritesManager().deleteComicWithId(
|
||||||
widget.folder,
|
widget.folder,
|
||||||
c.id,
|
c.id,
|
||||||
ComicType(c.sourceKey.hashCode),
|
(c as FavoriteItem).type,
|
||||||
);
|
);
|
||||||
updateComics();
|
updateComics();
|
||||||
},
|
},
|
||||||
|
@@ -83,6 +83,12 @@ class _NormalFavoritePage extends StatefulWidget {
|
|||||||
class _NormalFavoritePageState extends State<_NormalFavoritePage> {
|
class _NormalFavoritePageState extends State<_NormalFavoritePage> {
|
||||||
final comicListKey = GlobalKey<ComicListState>();
|
final comicListKey = GlobalKey<ComicListState>();
|
||||||
|
|
||||||
|
void showFolders() {
|
||||||
|
context
|
||||||
|
.findAncestorStateOfType<_FavoritesPageState>()!
|
||||||
|
.showFolderSelector();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ComicList(
|
return ComicList(
|
||||||
@@ -94,13 +100,14 @@ class _NormalFavoritePageState extends State<_NormalFavoritePage> {
|
|||||||
? IconButton(
|
? IconButton(
|
||||||
icon: const Icon(Icons.menu),
|
icon: const Icon(Icons.menu),
|
||||||
color: context.colorScheme.primary,
|
color: context.colorScheme.primary,
|
||||||
onPressed: context
|
onPressed: showFolders,
|
||||||
.findAncestorStateOfType<_FavoritesPageState>()!
|
|
||||||
.showFolderSelector,
|
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
title: Text(widget.data.title),
|
title: GestureDetector(
|
||||||
|
onTap: context.width < _kTwoPanelChangeWidth ? showFolders : null,
|
||||||
|
child: Text(widget.data.title),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
errorLeading: Appbar(
|
errorLeading: Appbar(
|
||||||
leading: Tooltip(
|
leading: Tooltip(
|
||||||
@@ -115,10 +122,17 @@ class _NormalFavoritePageState extends State<_NormalFavoritePage> {
|
|||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
title: Text(widget.data.title),
|
title: GestureDetector(
|
||||||
|
onTap: context.width < _kTwoPanelChangeWidth ? showFolders : null,
|
||||||
|
child: Text(widget.data.title),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
loadPage: widget.data.loadComic == null ? null : (i) => widget.data.loadComic!(i),
|
loadPage: widget.data.loadComic == null
|
||||||
loadNext: widget.data.loadNext == null ? null : (next) => widget.data.loadNext!(next),
|
? null
|
||||||
|
: (i) => widget.data.loadComic!(i),
|
||||||
|
loadNext: widget.data.loadNext == null
|
||||||
|
? null
|
||||||
|
: (next) => widget.data.loadNext!(next),
|
||||||
menuBuilder: (comic) {
|
menuBuilder: (comic) {
|
||||||
return [
|
return [
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
@@ -159,6 +173,12 @@ class _MultiFolderFavoritesPageState extends State<_MultiFolderFavoritesPage> {
|
|||||||
|
|
||||||
Map<String, String>? folders;
|
Map<String, String>? folders;
|
||||||
|
|
||||||
|
void showFolders() {
|
||||||
|
context
|
||||||
|
.findAncestorStateOfType<_FavoritesPageState>()!
|
||||||
|
.showFolderSelector();
|
||||||
|
}
|
||||||
|
|
||||||
void loadPage() async {
|
void loadPage() async {
|
||||||
var res = await widget.data.loadFolders!();
|
var res = await widget.data.loadFolders!();
|
||||||
_loading = false;
|
_loading = false;
|
||||||
@@ -186,13 +206,14 @@ class _MultiFolderFavoritesPageState extends State<_MultiFolderFavoritesPage> {
|
|||||||
? IconButton(
|
? IconButton(
|
||||||
icon: const Icon(Icons.menu),
|
icon: const Icon(Icons.menu),
|
||||||
color: context.colorScheme.primary,
|
color: context.colorScheme.primary,
|
||||||
onPressed: context
|
onPressed: showFolders,
|
||||||
.findAncestorStateOfType<_FavoritesPageState>()!
|
|
||||||
.showFolderSelector,
|
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
title: Text(widget.data.title),
|
title: GestureDetector(
|
||||||
|
onTap: context.width < _kTwoPanelChangeWidth ? showFolders : null,
|
||||||
|
child: Text(widget.data.title),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
var appBar = Appbar(
|
var appBar = Appbar(
|
||||||
@@ -202,13 +223,14 @@ class _MultiFolderFavoritesPageState extends State<_MultiFolderFavoritesPage> {
|
|||||||
? IconButton(
|
? IconButton(
|
||||||
icon: const Icon(Icons.menu),
|
icon: const Icon(Icons.menu),
|
||||||
color: context.colorScheme.primary,
|
color: context.colorScheme.primary,
|
||||||
onPressed: context
|
onPressed: showFolders,
|
||||||
.findAncestorStateOfType<_FavoritesPageState>()!
|
|
||||||
.showFolderSelector,
|
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
title: Text(widget.data.title),
|
title: GestureDetector(
|
||||||
|
onTap: context.width < _kTwoPanelChangeWidth ? showFolders : null,
|
||||||
|
child: Text(widget.data.title),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (_loading) {
|
if (_loading) {
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:venera/components/components.dart';
|
import 'package:venera/components/components.dart';
|
||||||
import 'package:venera/foundation/app.dart';
|
|
||||||
import 'package:venera/foundation/local.dart';
|
import 'package:venera/foundation/local.dart';
|
||||||
import 'package:venera/pages/downloading_page.dart';
|
import 'package:venera/pages/downloading_page.dart';
|
||||||
import 'package:venera/utils/translations.dart';
|
import 'package:venera/utils/translations.dart';
|
||||||
@@ -58,6 +57,17 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
|
|||||||
onTap: (c) {
|
onTap: (c) {
|
||||||
(c as LocalComic).read();
|
(c as LocalComic).read();
|
||||||
},
|
},
|
||||||
|
menuBuilder: (c) {
|
||||||
|
return [
|
||||||
|
MenuEntry(
|
||||||
|
icon: Icons.delete,
|
||||||
|
text: "Delete".tl,
|
||||||
|
onClick: () {
|
||||||
|
LocalManager().deleteComic(c as LocalComic);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
];
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
Reference in New Issue
Block a user