mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 15:57:25 +00:00
Improve local comics page
This commit is contained in:
@@ -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,7 +403,12 @@ 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(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
maxHeight: math.min(400, context.height - 136),
|
||||||
|
),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Wrap(
|
||||||
runSpacing: 8,
|
runSpacing: 8,
|
||||||
spacing: 8,
|
spacing: 8,
|
||||||
children: [
|
children: [
|
||||||
@@ -402,7 +427,9 @@ class ComicTile extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
).paddingHorizontal(16),
|
).paddingHorizontal(16),
|
||||||
|
),
|
||||||
actions: [
|
actions: [
|
||||||
Button.filled(
|
Button.filled(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
@@ -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,13 +184,7 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
|
|||||||
buildMultiSelectMenu(),
|
buildMultiSelectMenu(),
|
||||||
];
|
];
|
||||||
|
|
||||||
var body = Scaffold(
|
List<Widget> normalActions = [
|
||||||
body: SmoothCustomScrollView(
|
|
||||||
slivers: [
|
|
||||||
if (!searchMode && !multiSelectMode)
|
|
||||||
SliverAppbar(
|
|
||||||
title: Text("Local".tl),
|
|
||||||
actions: [
|
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: "Search".tl,
|
message: "Search".tl,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
@@ -216,25 +212,35 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
];
|
||||||
)
|
|
||||||
else if (multiSelectMode)
|
var body = Scaffold(
|
||||||
|
body: SmoothCustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
if (!searchMode)
|
||||||
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: () {
|
||||||
|
if (multiSelectMode) {
|
||||||
setState(() {
|
setState(() {
|
||||||
multiSelectMode = false;
|
multiSelectMode = false;
|
||||||
selectedComics.clear();
|
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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -302,77 +308,9 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}),
|
|
||||||
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,
|
|
||||||
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(
|
...exportActions(c as LocalComic),
|
||||||
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();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user