diff --git a/lib/components/comic.dart b/lib/components/comic.dart index b0b455d..344cab7 100644 --- a/lib/components/comic.dart +++ b/lib/components/comic.dart @@ -342,21 +342,39 @@ class ComicTile extends StatelessWidget { } List _splitText(String text) { - // split text by space, comma. text in brackets will be kept together. + // split text by comma, brackets var words = []; var buffer = StringBuffer(); var inBracket = false; + String? prevBracket; for (var i = 0; i < text.length; i++) { var c = text[i]; if (c == '[' || c == '(') { - inBracket = true; - } else if (c == ']' || c == ')') { - inBracket = false; - } else if (c == ' ' || c == ',') { if (inBracket) { buffer.write(c); } else { - words.add(buffer.toString()); + if (buffer.isNotEmpty) { + words.add(buffer.toString().trim()); + buffer.clear(); + } + inBracket = true; + prevBracket = c; + } + } else if (c == ']' || c == ')') { + if (prevBracket == '[' && c == ']' || prevBracket == '(' && c == ')') { + if (buffer.isNotEmpty) { + words.add(buffer.toString().trim()); + buffer.clear(); + } + inBracket = false; + } else { + buffer.write(c); + } + } else if (c == ',') { + if (inBracket) { + buffer.write(c); + } else { + words.add(buffer.toString().trim()); buffer.clear(); } } else { @@ -364,8 +382,10 @@ class ComicTile extends StatelessWidget { } } if (buffer.isNotEmpty) { - words.add(buffer.toString()); + words.add(buffer.toString().trim()); } + words.removeWhere((element) => element == ""); + words = words.toSet().toList(); return words; } @@ -383,26 +403,33 @@ class ComicTile extends StatelessWidget { return StatefulBuilder(builder: (context, setState) { return ContentDialog( title: 'Block'.tl, - content: Wrap( - runSpacing: 8, - spacing: 8, - children: [ - for (var word in all) - OptionChip( - text: word, - isSelected: words.contains(word), - onTap: () { - setState(() { - if (!words.contains(word)) { - words.add(word); - } else { - words.remove(word); - } - }); - }, - ), - ], - ).paddingHorizontal(16), + content: ConstrainedBox( + constraints: BoxConstraints( + maxHeight: math.min(400, context.height - 136), + ), + child: SingleChildScrollView( + child: Wrap( + runSpacing: 8, + spacing: 8, + children: [ + for (var word in all) + OptionChip( + text: word, + isSelected: words.contains(word), + onTap: () { + setState(() { + if (!words.contains(word)) { + words.add(word); + } else { + words.remove(word); + } + }); + }, + ), + ], + ), + ).paddingHorizontal(16), + ), actions: [ Button.filled( onPressed: () { diff --git a/lib/pages/local_comics_page.dart b/lib/pages/local_comics_page.dart index 05c6dd8..7dc51e6 100644 --- a/lib/pages/local_comics_page.dart +++ b/lib/pages/local_comics_page.dart @@ -140,6 +140,8 @@ class _LocalComicsPageState extends State { addFavorite(selectedComics.keys.toList()); }, ), + if (selectedComics.length == 1) + ...exportActions(selectedComics.keys.first), ]); } @@ -182,59 +184,63 @@ class _LocalComicsPageState extends State { buildMultiSelectMenu(), ]; + List normalActions = [ + Tooltip( + message: "Search".tl, + child: IconButton( + icon: const Icon(Icons.search), + onPressed: () { + setState(() { + searchMode = true; + }); + }, + ), + ), + Tooltip( + message: "Sort".tl, + child: IconButton( + icon: const Icon(Icons.sort), + onPressed: sort, + ), + ), + Tooltip( + message: "Downloading".tl, + child: IconButton( + icon: const Icon(Icons.download), + onPressed: () { + showPopUpWidget(context, const DownloadingPage()); + }, + ), + ), + ]; + var body = Scaffold( body: SmoothCustomScrollView( slivers: [ - if (!searchMode && !multiSelectMode) - SliverAppbar( - title: Text("Local".tl), - actions: [ - Tooltip( - message: "Search".tl, - child: IconButton( - icon: const Icon(Icons.search), - onPressed: () { - setState(() { - searchMode = true; - }); - }, - ), - ), - Tooltip( - message: "Sort".tl, - child: IconButton( - icon: const Icon(Icons.sort), - onPressed: sort, - ), - ), - Tooltip( - message: "Downloading".tl, - child: IconButton( - icon: const Icon(Icons.download), - onPressed: () { - showPopUpWidget(context, const DownloadingPage()); - }, - ), - ), - ], - ) - else if (multiSelectMode) + if (!searchMode) SliverAppbar( leading: Tooltip( - message: "Cancel".tl, + message: multiSelectMode ? "Cancel".tl : "Back".tl, child: IconButton( - icon: const Icon(Icons.close), onPressed: () { - setState(() { - multiSelectMode = false; - selectedComics.clear(); - }); + if (multiSelectMode) { + setState(() { + multiSelectMode = false; + selectedComics.clear(); + }); + } else { + context.pop(); + } }, + icon: multiSelectMode + ? const Icon(Icons.close) + : const Icon(Icons.arrow_back), ), ), - title: Text( - "Selected @c comics".tlParams({"c": selectedComics.length})), - actions: selectActions, + title: multiSelectMode + ? Text(selectedComics.length.toString()) + : Text("Local".tl), + actions: multiSelectMode ? selectActions : normalActions, ) else if (searchMode) SliverAppbar( @@ -273,14 +279,14 @@ class _LocalComicsPageState extends State { }); }, onTap: (c) { - if(multiSelectMode) { + if (multiSelectMode) { setState(() { if (selectedComics.containsKey(c as LocalComic)) { selectedComics.remove(c); } else { selectedComics[c] = true; } - if(selectedComics.isEmpty) { + if (selectedComics.isEmpty) { multiSelectMode = false; } }); @@ -291,88 +297,20 @@ class _LocalComicsPageState extends State { menuBuilder: (c) { return [ MenuEntry( - icon: Icons.delete, - text: "Delete".tl, - onClick: () { - deleteComics([c as LocalComic]).then((value) { - if (value && multiSelectMode) { - setState(() { - multiSelectMode = false; - selectedComics.clear(); - }); - } - }); - }), - MenuEntry( - icon: Icons.outbox_outlined, - text: "Export as cbz".tl, - onClick: () async { - var controller = showLoadingDialog( - context, - allowCancel: false, - ); - try { - var file = await CBZ.export(c as LocalComic); - await saveFile(filename: file.name, file: file); - await file.delete(); - } catch (e) { - context.showMessage(message: e.toString()); + icon: Icons.delete, + text: "Delete".tl, + onClick: () { + deleteComics([c as LocalComic]).then((value) { + if (value && multiSelectMode) { + setState(() { + multiSelectMode = false; + selectedComics.clear(); + }); } - controller.close(); - }), - MenuEntry( - icon: Icons.picture_as_pdf_outlined, - text: "Export as pdf".tl, - onClick: () async { - var cache = FilePath.join(App.cachePath, 'temp.pdf'); - var controller = showLoadingDialog( - context, - allowCancel: false, - ); - try { - await createPdfFromComicIsolate( - comic: c as LocalComic, - savePath: cache, - ); - await saveFile( - file: File(cache), - filename: "${c.title}.pdf", - ); - } catch (e, s) { - Log.error("PDF Export", e, s); - context.showMessage(message: e.toString()); - } finally { - controller.close(); - File(cache).deleteIgnoreError(); - } - }, - ), - MenuEntry( - icon: Icons.import_contacts_outlined, - text: "Export as epub".tl, - onClick: () async { - var controller = showLoadingDialog( - context, - allowCancel: false, - ); - File? file; - try { - file = await createEpubWithLocalComic( - c as LocalComic, - ); - await saveFile( - file: file, - filename: "${c.title}.epub", - ); - } catch (e, s) { - Log.error("EPUB Export", e, s); - context.showMessage(message: e.toString()); - } finally { - controller.close(); - file?.deleteIgnoreError(); - } - }, - ) + }); + }, + ), + ...exportActions(c as LocalComic), ]; }, ), @@ -439,4 +377,79 @@ class _LocalComicsPageState extends State { ); return isDeleted; } + + List exportActions(LocalComic c) { + return [ + MenuEntry( + icon: Icons.outbox_outlined, + text: "Export as cbz".tl, + onClick: () async { + var controller = showLoadingDialog( + context, + allowCancel: false, + ); + try { + var file = await CBZ.export(c); + await saveFile(filename: file.name, file: file); + await file.delete(); + } catch (e) { + context.showMessage(message: e.toString()); + } + controller.close(); + }), + MenuEntry( + icon: Icons.picture_as_pdf_outlined, + text: "Export as pdf".tl, + onClick: () async { + var cache = FilePath.join(App.cachePath, 'temp.pdf'); + var controller = showLoadingDialog( + context, + allowCancel: false, + ); + try { + await createPdfFromComicIsolate( + comic: c, + savePath: cache, + ); + await saveFile( + file: File(cache), + filename: "${c.title}.pdf", + ); + } catch (e, s) { + Log.error("PDF Export", e, s); + context.showMessage(message: e.toString()); + } finally { + controller.close(); + File(cache).deleteIgnoreError(); + } + }, + ), + MenuEntry( + icon: Icons.import_contacts_outlined, + text: "Export as epub".tl, + onClick: () async { + var controller = showLoadingDialog( + context, + allowCancel: false, + ); + File? file; + try { + file = await createEpubWithLocalComic( + c, + ); + await saveFile( + file: file, + filename: "${c.title}.epub", + ); + } catch (e, s) { + Log.error("EPUB Export", e, s); + context.showMessage(message: e.toString()); + } finally { + controller.close(); + file?.deleteIgnoreError(); + } + }, + ) + ]; + } }