From 76e9ef87d4c9c075534a6e01f74b45cfb492caf7 Mon Sep 17 00:00:00 2001 From: nyne Date: Sun, 25 May 2025 20:26:35 +0800 Subject: [PATCH] Add functionality to delete specific comic chapters. Close #368 --- assets/translation.json | 6 ++- lib/foundation/local.dart | 36 ++++++++++++++++++ lib/pages/local_comics_page.dart | 64 ++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/assets/translation.json b/assets/translation.json index 9de20d2..45079e2 100644 --- a/assets/translation.json +++ b/assets/translation.json @@ -393,7 +393,8 @@ "The URL should point to a 'index.json' file": "该URL应指向一个'index.json'文件", "Double tap to zoom": "双击缩放", "Clear Unfavorited": "清除未收藏", - "Reverse": "反转" + "Reverse": "反转", + "Delete Chapters": "删除章节" }, "zh_TW": { "Home": "首頁", @@ -789,6 +790,7 @@ "The URL should point to a 'index.json' file": "該URL應指向一個'index.json'文件", "Double tap to zoom": "雙擊縮放", "Clear Unfavorited": "清除未收藏", - "Reverse": "反轉" + "Reverse": "反轉", + "Delete Chapters": "刪除章節" } } \ No newline at end of file diff --git a/lib/foundation/local.dart b/lib/foundation/local.dart index 206e8fb..ef7cf15 100644 --- a/lib/foundation/local.dart +++ b/lib/foundation/local.dart @@ -548,6 +548,41 @@ class LocalManager with ChangeNotifier { notifyListeners(); } + void deleteComicChapters(LocalComic c, List chapters) { + if (chapters.isEmpty) { + return; + } + var newDownloadedChapters = c.downloadedChapters + .where((e) => !chapters.contains(e)) + .toList(); + if (newDownloadedChapters.isNotEmpty) { + _db.execute( + 'UPDATE comics SET downloadedChapters = ? WHERE id = ? AND comic_type = ?;', + [ + jsonEncode(newDownloadedChapters), + c.id, + c.comicType.value, + ], + ); + } else { + _db.execute( + 'DELETE FROM comics WHERE id = ? AND comic_type = ?;', + [c.id, c.comicType.value], + ); + } + var shouldRemovedDirs = []; + for (var chapter in chapters) { + var dir = Directory(FilePath.join(c.baseDir, chapter)); + if (dir.existsSync()) { + shouldRemovedDirs.add(dir); + } + } + if (shouldRemovedDirs.isNotEmpty) { + _deleteDirectories(shouldRemovedDirs); + } + notifyListeners(); + } + void batchDeleteComics(List comics, [bool removeFileOnDisk = true]) { if (comics.isEmpty) { return; @@ -587,6 +622,7 @@ class LocalManager with ChangeNotifier { } } + /// Deletes the directories in a separate isolate to avoid blocking the UI thread. static void _deleteDirectories(List directories) { Isolate.run(() async { for (var dir in directories) { diff --git a/lib/pages/local_comics_page.dart b/lib/pages/local_comics_page.dart index c958fee..6904054 100644 --- a/lib/pages/local_comics_page.dart +++ b/lib/pages/local_comics_page.dart @@ -374,6 +374,14 @@ class _LocalComicsPageState extends State { }, ), actions: [ + if (comics.length == 1 && comics.first.hasChapters) + TextButton( + child: Text("Delete Chapters".tl), + onPressed: () { + context.pop(); + showDeleteChaptersPopWindow(context, comics.first); + }, + ), FilledButton( onPressed: () { context.pop(); @@ -495,3 +503,59 @@ class _LocalComicsPageState extends State { typedef ExportComicFunc = Future Function( LocalComic comic, String outFilePath); + +void showDeleteChaptersPopWindow(BuildContext context, LocalComic comic) { + var chapters = []; + + showPopUpWidget( + context, + PopUpWidgetScaffold( + title: "Delete Chapters".tl, + body: StatefulBuilder(builder: (context, setState) { + return Column( + children: [ + Expanded( + child: ListView.builder( + itemCount: comic.downloadedChapters.length, + itemBuilder: (context, index) { + var id = comic.downloadedChapters[index]; + var chapter = comic.chapters![id] ?? "Unknown Chapter"; + return CheckboxListTile( + title: Text(chapter), + value: chapters.contains(id), + onChanged: (v) { + setState(() { + if (v == true) { + chapters.add(id); + } else { + chapters.remove(id); + } + }); + }, + ); + }, + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + FilledButton( + onPressed: () { + Future.delayed(const Duration(milliseconds: 200), () { + LocalManager().deleteComicChapters(comic, chapters); + }); + App.rootContext.pop(); + }, + child: Text("Submit".tl), + ) + ], + ), + ) + ], + ); + }), + ), + ); +}