Improve local comics page

This commit is contained in:
2024-12-22 18:07:13 +08:00
parent 6023e462d7
commit 0b96d01afb
2 changed files with 193 additions and 153 deletions

View File

@@ -342,21 +342,39 @@ class ComicTile extends StatelessWidget {
} }
List<String> _splitText(String text) { List<String> _splitText(String text) {
// split text by space, comma. text in brackets will be kept together. // split text by comma, brackets
var words = <String>[]; var words = <String>[];
var buffer = StringBuffer(); var buffer = StringBuffer();
var inBracket = false; var inBracket = false;
String? prevBracket;
for (var i = 0; i < text.length; i++) { for (var i = 0; i < text.length; i++) {
var c = text[i]; var c = text[i];
if (c == '[' || c == '(') { if (c == '[' || c == '(') {
inBracket = true;
} else if (c == ']' || c == ')') {
inBracket = false;
} else if (c == ' ' || c == ',') {
if (inBracket) { if (inBracket) {
buffer.write(c); buffer.write(c);
} else { } 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(); buffer.clear();
} }
} else { } else {
@@ -364,8 +382,10 @@ class ComicTile extends StatelessWidget {
} }
} }
if (buffer.isNotEmpty) { if (buffer.isNotEmpty) {
words.add(buffer.toString()); words.add(buffer.toString().trim());
} }
words.removeWhere((element) => element == "");
words = words.toSet().toList();
return words; return words;
} }
@@ -383,26 +403,33 @@ class ComicTile extends StatelessWidget {
return StatefulBuilder(builder: (context, setState) { return StatefulBuilder(builder: (context, setState) {
return ContentDialog( return ContentDialog(
title: 'Block'.tl, title: 'Block'.tl,
content: Wrap( content: ConstrainedBox(
runSpacing: 8, constraints: BoxConstraints(
spacing: 8, maxHeight: math.min(400, context.height - 136),
children: [ ),
for (var word in all) child: SingleChildScrollView(
OptionChip( child: Wrap(
text: word, runSpacing: 8,
isSelected: words.contains(word), spacing: 8,
onTap: () { children: [
setState(() { for (var word in all)
if (!words.contains(word)) { OptionChip(
words.add(word); text: word,
} else { isSelected: words.contains(word),
words.remove(word); onTap: () {
} setState(() {
}); if (!words.contains(word)) {
}, words.add(word);
), } else {
], words.remove(word);
).paddingHorizontal(16), }
});
},
),
],
),
).paddingHorizontal(16),
),
actions: [ actions: [
Button.filled( Button.filled(
onPressed: () { onPressed: () {

View File

@@ -140,6 +140,8 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
addFavorite(selectedComics.keys.toList()); addFavorite(selectedComics.keys.toList());
}, },
), ),
if (selectedComics.length == 1)
...exportActions(selectedComics.keys.first),
]); ]);
} }
@@ -182,59 +184,63 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
buildMultiSelectMenu(), buildMultiSelectMenu(),
]; ];
List<Widget> 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( var body = Scaffold(
body: SmoothCustomScrollView( body: SmoothCustomScrollView(
slivers: [ slivers: [
if (!searchMode && !multiSelectMode) if (!searchMode)
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)
SliverAppbar( SliverAppbar(
leading: Tooltip( leading: Tooltip(
message: "Cancel".tl, message: multiSelectMode ? "Cancel".tl : "Back".tl,
child: IconButton( child: IconButton(
icon: const Icon(Icons.close),
onPressed: () { onPressed: () {
setState(() { if (multiSelectMode) {
multiSelectMode = false; setState(() {
selectedComics.clear(); multiSelectMode = false;
}); selectedComics.clear();
});
} else {
context.pop();
}
}, },
icon: multiSelectMode
? const Icon(Icons.close)
: const Icon(Icons.arrow_back),
), ),
), ),
title: Text( title: multiSelectMode
"Selected @c comics".tlParams({"c": selectedComics.length})), ? Text(selectedComics.length.toString())
actions: selectActions, : Text("Local".tl),
actions: multiSelectMode ? selectActions : normalActions,
) )
else if (searchMode) else if (searchMode)
SliverAppbar( SliverAppbar(
@@ -273,14 +279,14 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
}); });
}, },
onTap: (c) { onTap: (c) {
if(multiSelectMode) { if (multiSelectMode) {
setState(() { setState(() {
if (selectedComics.containsKey(c as LocalComic)) { if (selectedComics.containsKey(c as LocalComic)) {
selectedComics.remove(c); selectedComics.remove(c);
} else { } else {
selectedComics[c] = true; selectedComics[c] = true;
} }
if(selectedComics.isEmpty) { if (selectedComics.isEmpty) {
multiSelectMode = false; multiSelectMode = false;
} }
}); });
@@ -291,88 +297,20 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
menuBuilder: (c) { menuBuilder: (c) {
return [ return [
MenuEntry( MenuEntry(
icon: Icons.delete, icon: Icons.delete,
text: "Delete".tl, text: "Delete".tl,
onClick: () { onClick: () {
deleteComics([c as LocalComic]).then((value) { deleteComics([c as LocalComic]).then((value) {
if (value && multiSelectMode) { if (value && multiSelectMode) {
setState(() { setState(() {
multiSelectMode = false; multiSelectMode = false;
selectedComics.clear(); 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());
} }
controller.close(); });
}), },
MenuEntry( ),
icon: Icons.picture_as_pdf_outlined, ...exportActions(c as LocalComic),
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();
}
},
)
]; ];
}, },
), ),
@@ -439,4 +377,79 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
); );
return isDeleted; return isDeleted;
} }
List<MenuEntry> 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();
}
},
)
];
}
} }