mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
improve ui
This commit is contained in:
@@ -156,7 +156,7 @@ class _ButtonState extends State<Button> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var padding = widget.padding ??
|
var padding = widget.padding ??
|
||||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 4);
|
const EdgeInsets.symmetric(horizontal: 16);
|
||||||
var width = widget.width;
|
var width = widget.width;
|
||||||
if (width != null) {
|
if (width != null) {
|
||||||
width = width - padding.horizontal;
|
width = width - padding.horizontal;
|
||||||
@@ -206,6 +206,7 @@ class _ButtonState extends State<Button> {
|
|||||||
padding: padding,
|
padding: padding,
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
minWidth: 76,
|
minWidth: 76,
|
||||||
|
minHeight: 32,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: buttonColor,
|
color: buttonColor,
|
||||||
|
@@ -158,12 +158,16 @@ class ComicTile extends StatelessWidget {
|
|||||||
image = FileImage(File(comic.cover.substring(7)));
|
image = FileImage(File(comic.cover.substring(7)));
|
||||||
} else if (comic.sourceKey == 'local') {
|
} else if (comic.sourceKey == 'local') {
|
||||||
var localComic = LocalManager().find(comic.id, ComicType.local);
|
var localComic = LocalManager().find(comic.id, ComicType.local);
|
||||||
if(localComic == null) {
|
if (localComic == null) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
image = FileImage(localComic.coverFile);
|
image = FileImage(localComic.coverFile);
|
||||||
} else {
|
} else {
|
||||||
image = CachedImageProvider(comic.cover, sourceKey: comic.sourceKey);
|
image = CachedImageProvider(
|
||||||
|
comic.cover,
|
||||||
|
sourceKey: comic.sourceKey,
|
||||||
|
cid: comic.id,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return AnimatedImage(
|
return AnimatedImage(
|
||||||
image: image,
|
image: image,
|
||||||
@@ -485,12 +489,11 @@ class _ComicDescription extends StatelessWidget {
|
|||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
child:Text(
|
child: Text(
|
||||||
"${badge![0].toUpperCase()}${badge!.substring(1).toLowerCase()}",
|
"${badge![0].toUpperCase()}${badge!.substring(1).toLowerCase()}",
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
),
|
),
|
||||||
)
|
)),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -574,15 +577,14 @@ class _ReadingHistoryPainter extends CustomPainter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SliverGridComics extends StatefulWidget {
|
class SliverGridComics extends StatefulWidget {
|
||||||
const SliverGridComics({
|
const SliverGridComics(
|
||||||
super.key,
|
{super.key,
|
||||||
required this.comics,
|
required this.comics,
|
||||||
this.onLastItemBuild,
|
this.onLastItemBuild,
|
||||||
this.badgeBuilder,
|
this.badgeBuilder,
|
||||||
this.menuBuilder,
|
this.menuBuilder,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
this.selections
|
this.selections});
|
||||||
});
|
|
||||||
|
|
||||||
final List<Comic> comics;
|
final List<Comic> comics;
|
||||||
|
|
||||||
@@ -681,37 +683,23 @@ class _SliverGridComics extends StatelessWidget {
|
|||||||
onLastItemBuild?.call();
|
onLastItemBuild?.call();
|
||||||
}
|
}
|
||||||
var badge = badgeBuilder?.call(comics[index]);
|
var badge = badgeBuilder?.call(comics[index]);
|
||||||
return Stack(
|
var isSelected =
|
||||||
children: [
|
selection == null ? false : selection![comics[index]] ?? false;
|
||||||
ComicTile(
|
var comic = ComicTile(
|
||||||
comic: comics[index],
|
comic: comics[index],
|
||||||
badge: badge,
|
badge: badge,
|
||||||
menuOptions: menuBuilder?.call(comics[index]),
|
menuOptions: menuBuilder?.call(comics[index]),
|
||||||
onTap: onTap != null ? () => onTap!(comics[index]) : null,
|
onTap: onTap != null ? () => onTap!(comics[index]) : null,
|
||||||
|
);
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: isSelected
|
||||||
|
? Theme.of(context).colorScheme.surfaceContainer
|
||||||
|
: null,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
Positioned(
|
margin: const EdgeInsets.all(4),
|
||||||
bottom: 10,
|
child: comic,
|
||||||
right: 8,
|
|
||||||
child: Visibility(
|
|
||||||
visible: selection == null ? false : selection![comics[index]] ?? false,
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
Transform.scale(
|
|
||||||
scale: 0.9,
|
|
||||||
child: const Icon(
|
|
||||||
Icons.circle_rounded,
|
|
||||||
color: Colors.white,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
const Icon(
|
|
||||||
Icons.check_circle_rounded,
|
|
||||||
color: Colors.green,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: comics.length,
|
childCount: comics.length,
|
||||||
@@ -910,7 +898,7 @@ class ComicListState extends State<ComicList> {
|
|||||||
try {
|
try {
|
||||||
if (widget.loadPage != null) {
|
if (widget.loadPage != null) {
|
||||||
var res = await widget.loadPage!(page);
|
var res = await widget.loadPage!(page);
|
||||||
if(!mounted) return;
|
if (!mounted) return;
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
if (res.data.isEmpty) {
|
if (res.data.isEmpty) {
|
||||||
_data[page] = const [];
|
_data[page] = const [];
|
||||||
|
@@ -8,7 +8,7 @@ import 'cached_image.dart' as image_provider;
|
|||||||
class CachedImageProvider
|
class CachedImageProvider
|
||||||
extends BaseImageProvider<image_provider.CachedImageProvider> {
|
extends BaseImageProvider<image_provider.CachedImageProvider> {
|
||||||
/// Image provider for normal image.
|
/// Image provider for normal image.
|
||||||
const CachedImageProvider(this.url, {this.headers, this.sourceKey});
|
const CachedImageProvider(this.url, {this.headers, this.sourceKey, this.cid});
|
||||||
|
|
||||||
final String url;
|
final String url;
|
||||||
|
|
||||||
@@ -16,9 +16,11 @@ class CachedImageProvider
|
|||||||
|
|
||||||
final String? sourceKey;
|
final String? sourceKey;
|
||||||
|
|
||||||
|
final String? cid;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Uint8List> load(StreamController<ImageChunkEvent> chunkEvents) async {
|
Future<Uint8List> load(StreamController<ImageChunkEvent> chunkEvents) async {
|
||||||
await for (var progress in ImageDownloader.loadThumbnail(url, sourceKey)) {
|
await for (var progress in ImageDownloader.loadThumbnail(url, sourceKey, cid)) {
|
||||||
chunkEvents.add(ImageChunkEvent(
|
chunkEvents.add(ImageChunkEvent(
|
||||||
cumulativeBytesLoaded: progress.currentBytes,
|
cumulativeBytesLoaded: progress.currentBytes,
|
||||||
expectedTotalBytes: progress.totalBytes,
|
expectedTotalBytes: progress.totalBytes,
|
||||||
@@ -36,5 +38,5 @@ class CachedImageProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get key => url;
|
String get key => url + (sourceKey ?? "") + (cid ?? "");
|
||||||
}
|
}
|
||||||
|
@@ -357,6 +357,7 @@ class ImagesDownloadTask extends DownloadTask with _TransferSpeedMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LocalManager().completeTask(this);
|
LocalManager().completeTask(this);
|
||||||
|
stopRecorder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -534,6 +535,9 @@ class _ImageDownloadWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
|
if (isCancelled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Log.error("Download", e.toString(), s);
|
Log.error("Download", e.toString(), s);
|
||||||
retry--;
|
retry--;
|
||||||
if (retry > 0) {
|
if (retry > 0) {
|
||||||
|
@@ -10,8 +10,9 @@ import 'app_dio.dart';
|
|||||||
|
|
||||||
class ImageDownloader {
|
class ImageDownloader {
|
||||||
static Stream<ImageDownloadProgress> loadThumbnail(
|
static Stream<ImageDownloadProgress> loadThumbnail(
|
||||||
String url, String? sourceKey) async* {
|
String url, String? sourceKey,
|
||||||
final cacheKey = "$url@$sourceKey";
|
[String? cid]) async* {
|
||||||
|
final cacheKey = "$url@$sourceKey${cid != null ? '@$cid' : ''}";
|
||||||
final cache = await CacheManager().findCache(cacheKey);
|
final cache = await CacheManager().findCache(cacheKey);
|
||||||
|
|
||||||
if (cache != null) {
|
if (cache != null) {
|
||||||
@@ -34,6 +35,16 @@ class ImageDownloader {
|
|||||||
configs['headers']['user-agent'] = webUA;
|
configs['headers']['user-agent'] = webUA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (((configs['url'] as String?) ?? url).startsWith('cover.') &&
|
||||||
|
sourceKey != null) {
|
||||||
|
var comicSource = ComicSource.find(sourceKey);
|
||||||
|
if(comicSource != null) {
|
||||||
|
var comicInfo = await comicSource.loadComicInfo!(cid!);
|
||||||
|
yield* loadThumbnail(comicInfo.data.cover, sourceKey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var dio = AppDio(BaseOptions(
|
var dio = AppDio(BaseOptions(
|
||||||
headers: Map<String, dynamic>.from(configs['headers']),
|
headers: Map<String, dynamic>.from(configs['headers']),
|
||||||
method: configs['method'] ?? 'GET',
|
method: configs['method'] ?? 'GET',
|
||||||
@@ -171,9 +182,8 @@ class ImageDownloader {
|
|||||||
}
|
}
|
||||||
configs = newConfig;
|
configs = newConfig;
|
||||||
retryLimit--;
|
retryLimit--;
|
||||||
}
|
} finally {
|
||||||
finally {
|
if (onLoadFailed != null) {
|
||||||
if(onLoadFailed != null) {
|
|
||||||
(configs['onLoadFailed'] as JSInvokable).free();
|
(configs['onLoadFailed'] as JSInvokable).free();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,8 +27,10 @@ class _DownloadingPageState extends State<DownloadingPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void update() {
|
void update() {
|
||||||
|
if(mounted) {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@@ -258,6 +258,7 @@ class _HistoryState extends State<_History> {
|
|||||||
ImageProvider imageProvider = CachedImageProvider(
|
ImageProvider imageProvider = CachedImageProvider(
|
||||||
cover,
|
cover,
|
||||||
sourceKey: history[index].type.comicSource?.key,
|
sourceKey: history[index].type.comicSource?.key,
|
||||||
|
cid: history[index].id,
|
||||||
);
|
);
|
||||||
if (!cover.isURL) {
|
if (!cover.isURL) {
|
||||||
var localComic = LocalManager().find(
|
var localComic = LocalManager().find(
|
||||||
@@ -567,7 +568,7 @@ class _ImportComicsWidgetState extends State<_ImportComicsWidget> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
barrierColor: Colors.transparent,
|
barrierColor: Colors.black.withOpacity(0.2),
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
var help = '';
|
var help = '';
|
||||||
help +=
|
help +=
|
||||||
|
@@ -100,7 +100,7 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
|
|||||||
actions: [
|
actions: [
|
||||||
FilledButton(
|
FilledButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
appdata.implicitData["local_sort"] =sortType.value;
|
appdata.implicitData["local_sort"] = sortType.value;
|
||||||
appdata.writeImplicitData();
|
appdata.writeImplicitData();
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
update();
|
update();
|
||||||
@@ -116,19 +116,18 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final double screenWidth = MediaQuery.of(context).size.width;
|
void selectAll() {
|
||||||
final bool isScreenSmall = screenWidth < 500.0;
|
|
||||||
|
|
||||||
void selectAll(){
|
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedComics = comics.asMap().map((k, v) => MapEntry(v, true));
|
selectedComics = comics.asMap().map((k, v) => MapEntry(v, true));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void deSelect() {
|
void deSelect() {
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedComics.clear();
|
selectedComics.clear();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void invertSelection() {
|
void invertSelection() {
|
||||||
setState(() {
|
setState(() {
|
||||||
comics.asMap().forEach((k, v) {
|
comics.asMap().forEach((k, v) {
|
||||||
@@ -137,86 +136,46 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
|
|||||||
selectedComics.removeWhere((k, v) => !v);
|
selectedComics.removeWhere((k, v) => !v);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void selectRange() {
|
void selectRange() {
|
||||||
setState(() {
|
setState(() {
|
||||||
List<int> l = [];
|
List<int> l = [];
|
||||||
selectedComics.forEach((k, v) {
|
selectedComics.forEach((k, v) {
|
||||||
l.add(comics.indexOf(k as LocalComic));
|
l.add(comics.indexOf(k as LocalComic));
|
||||||
});
|
});
|
||||||
if(l.isEmpty) {
|
if (l.isEmpty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
l.sort();
|
l.sort();
|
||||||
int start = l.first;
|
int start = l.first;
|
||||||
int end = l.last;
|
int end = l.last;
|
||||||
selectedComics.clear();
|
selectedComics.clear();
|
||||||
selectedComics.addEntries(
|
selectedComics.addEntries(List.generate(end - start + 1, (i) {
|
||||||
List.generate(end - start + 1, (i) {
|
|
||||||
return MapEntry(comics[start + i], true);
|
return MapEntry(comics[start + i], true);
|
||||||
})
|
}));
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> selectActions = [];
|
List<Widget> selectActions = [
|
||||||
if(isScreenSmall) {
|
|
||||||
selectActions.add(
|
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
icon: const Icon(Icons.select_all),
|
||||||
showMenu(
|
|
||||||
context: context,
|
|
||||||
position: RelativeRect.fromLTRB(screenWidth, App.isMobile ? 64 : 96, 0, 0),
|
|
||||||
items: <PopupMenuEntry>[
|
|
||||||
PopupMenuItem(
|
|
||||||
onTap: selectAll,
|
|
||||||
child: Text("Select All".tl),
|
|
||||||
),
|
|
||||||
PopupMenuItem(
|
|
||||||
onTap: deSelect,
|
|
||||||
child: Text("Deselect".tl),
|
|
||||||
),
|
|
||||||
PopupMenuItem(
|
|
||||||
onTap: invertSelection,
|
|
||||||
child: Text("Invert Selection".tl),
|
|
||||||
),
|
|
||||||
PopupMenuItem(
|
|
||||||
onTap: selectRange,
|
|
||||||
child: Text("Select in range".tl),
|
|
||||||
)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
},
|
|
||||||
icon: const Icon(
|
|
||||||
Icons.list
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}else {
|
|
||||||
selectActions = [
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.check_box_rounded),
|
|
||||||
tooltip: "Select All".tl,
|
tooltip: "Select All".tl,
|
||||||
onPressed: selectAll
|
onPressed: selectAll),
|
||||||
),
|
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.check_box_outline_blank_outlined),
|
icon: const Icon(Icons.deselect),
|
||||||
tooltip: "Deselect".tl,
|
tooltip: "Deselect".tl,
|
||||||
onPressed: deSelect
|
onPressed: deSelect),
|
||||||
),
|
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.check_box_outlined),
|
icon: const Icon(Icons.flip),
|
||||||
tooltip: "Invert Selection".tl,
|
tooltip: "Invert Selection".tl,
|
||||||
onPressed: invertSelection
|
onPressed: invertSelection),
|
||||||
),
|
|
||||||
|
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.indeterminate_check_box_rounded),
|
icon: const Icon(Icons.border_horizontal_outlined),
|
||||||
tooltip: "Select in range".tl,
|
tooltip: "Select in range".tl,
|
||||||
onPressed: selectRange
|
onPressed: selectRange),
|
||||||
),
|
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
return Scaffold(
|
var body = Scaffold(
|
||||||
body: SmoothCustomScrollView(
|
body: SmoothCustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
if (!searchMode && !multiSelectMode)
|
if (!searchMode && !multiSelectMode)
|
||||||
@@ -267,12 +226,10 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
|
|||||||
)
|
)
|
||||||
else if (multiSelectMode)
|
else if (multiSelectMode)
|
||||||
SliverAppbar(
|
SliverAppbar(
|
||||||
title: Text("Selected @c comics".tlParams({"c": selectedComics.length})),
|
leading: Tooltip(
|
||||||
actions: [
|
message: "Cancel".tl,
|
||||||
...selectActions,
|
child: IconButton(
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.close),
|
icon: const Icon(Icons.close),
|
||||||
tooltip: "Exit Multi-Select".tl,
|
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
multiSelectMode = false;
|
multiSelectMode = false;
|
||||||
@@ -280,11 +237,26 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
title: Text(
|
||||||
|
"Selected @c comics".tlParams({"c": selectedComics.length})),
|
||||||
|
actions: selectActions,
|
||||||
)
|
)
|
||||||
else if (searchMode)
|
else if (searchMode)
|
||||||
SliverAppbar(
|
SliverAppbar(
|
||||||
|
leading: Tooltip(
|
||||||
|
message: "Cancel".tl,
|
||||||
|
child: IconButton(
|
||||||
|
icon: const Icon(Icons.close),
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
searchMode = false;
|
||||||
|
keyword = "";
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
title: TextField(
|
title: TextField(
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@@ -296,18 +268,6 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
|
|||||||
update();
|
update();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
actions: [
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.close),
|
|
||||||
onPressed: () {
|
|
||||||
setState(() {
|
|
||||||
searchMode = false;
|
|
||||||
keyword = "";
|
|
||||||
update();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
SliverGridComics(
|
SliverGridComics(
|
||||||
comics: comics,
|
comics: comics,
|
||||||
@@ -335,50 +295,51 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
|
|||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
bool removeComicFile = true;
|
bool removeComicFile = true;
|
||||||
return StatefulBuilder(
|
return StatefulBuilder(builder: (context, state) {
|
||||||
builder: (context, state) {
|
|
||||||
return ContentDialog(
|
return ContentDialog(
|
||||||
title: "Delete".tl,
|
title: "Delete".tl,
|
||||||
content: Column(
|
content: Column(
|
||||||
children: [
|
children: [
|
||||||
Text("Delete selected comics?".tl).paddingVertical(8),
|
Text("Delete selected comics?".tl)
|
||||||
|
.paddingVertical(8),
|
||||||
Transform.scale(
|
Transform.scale(
|
||||||
scale: 0.9,
|
scale: 0.9,
|
||||||
child: CheckboxListTile(
|
child: CheckboxListTile(
|
||||||
title: Text("Also remove files on disk".tl),
|
title: Text(
|
||||||
|
"Also remove files on disk".tl),
|
||||||
value: removeComicFile,
|
value: removeComicFile,
|
||||||
onChanged: (v) {
|
onChanged: (v) {
|
||||||
state(() {
|
state(() {
|
||||||
removeComicFile = !removeComicFile;
|
removeComicFile =
|
||||||
|
!removeComicFile;
|
||||||
});
|
});
|
||||||
}
|
})),
|
||||||
)
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
).paddingHorizontal(16).paddingVertical(8),
|
).paddingHorizontal(16).paddingVertical(8),
|
||||||
actions: [
|
actions: [
|
||||||
FilledButton(
|
FilledButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pop();
|
context.pop();
|
||||||
if(multiSelectMode) {
|
if (multiSelectMode) {
|
||||||
for (var comic in selectedComics.keys) {
|
for (var comic in selectedComics.keys) {
|
||||||
LocalManager().deleteComic(comic as LocalComic, removeComicFile);
|
LocalManager().deleteComic(
|
||||||
|
comic as LocalComic,
|
||||||
|
removeComicFile);
|
||||||
}
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedComics.clear();
|
selectedComics.clear();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
LocalManager().deleteComic(c as LocalComic, removeComicFile);
|
LocalManager().deleteComic(
|
||||||
|
c as LocalComic, removeComicFile);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Text("Confirm".tl),
|
child: Text("Confirm".tl),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
);
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
}),
|
}),
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon: Icons.outbox_outlined,
|
icon: Icons.outbox_outlined,
|
||||||
@@ -414,5 +375,24 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return PopScope(
|
||||||
|
canPop: !multiSelectMode && !searchMode,
|
||||||
|
onPopInvokedWithResult: (didPop, result) {
|
||||||
|
if(multiSelectMode) {
|
||||||
|
setState(() {
|
||||||
|
multiSelectMode = false;
|
||||||
|
selectedComics.clear();
|
||||||
|
});
|
||||||
|
} else if(searchMode) {
|
||||||
|
setState(() {
|
||||||
|
searchMode = false;
|
||||||
|
keyword = "";
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: body,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,12 +16,12 @@ class _AboutSettingsState extends State<AboutSettings> {
|
|||||||
slivers: [
|
slivers: [
|
||||||
SliverAppbar(title: Text("About".tl)),
|
SliverAppbar(title: Text("About".tl)),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 136,
|
height: 112,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 136,
|
width: 112,
|
||||||
height: 136,
|
height: 112,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(136),
|
borderRadius: BorderRadius.circular(136),
|
||||||
),
|
),
|
||||||
|
@@ -10,7 +10,6 @@ import 'package:venera/foundation/app.dart';
|
|||||||
import 'package:venera/foundation/appdata.dart';
|
import 'package:venera/foundation/appdata.dart';
|
||||||
import 'package:venera/foundation/cache_manager.dart';
|
import 'package:venera/foundation/cache_manager.dart';
|
||||||
import 'package:venera/foundation/comic_source/comic_source.dart';
|
import 'package:venera/foundation/comic_source/comic_source.dart';
|
||||||
import 'package:venera/foundation/consts.dart';
|
|
||||||
import 'package:venera/foundation/favorites.dart';
|
import 'package:venera/foundation/favorites.dart';
|
||||||
import 'package:venera/foundation/local.dart';
|
import 'package:venera/foundation/local.dart';
|
||||||
import 'package:venera/foundation/log.dart';
|
import 'package:venera/foundation/log.dart';
|
||||||
@@ -44,7 +43,7 @@ class _SettingsPageState extends State<SettingsPage> implements PopEntry {
|
|||||||
|
|
||||||
ColorScheme get colors => Theme.of(context).colorScheme;
|
ColorScheme get colors => Theme.of(context).colorScheme;
|
||||||
|
|
||||||
bool get enableTwoViews => context.width > changePoint;
|
bool get enableTwoViews => context.width > 720;
|
||||||
|
|
||||||
final categories = <String>[
|
final categories = <String>[
|
||||||
"Explore",
|
"Explore",
|
||||||
|
@@ -18,11 +18,11 @@ export 'package:flutter_inappwebview/flutter_inappwebview.dart'
|
|||||||
|
|
||||||
extension WebviewExtension on InAppWebViewController {
|
extension WebviewExtension on InAppWebViewController {
|
||||||
Future<List<io.Cookie>?> getCookies(String url) async {
|
Future<List<io.Cookie>?> getCookies(String url) async {
|
||||||
if(url.contains("https://")){
|
if (url.contains("https://")) {
|
||||||
url.replaceAll("https://", "");
|
url.replaceAll("https://", "");
|
||||||
}
|
}
|
||||||
if(url[url.length-1] == '/'){
|
if (url[url.length - 1] == '/') {
|
||||||
url = url.substring(0, url.length-1);
|
url = url.substring(0, url.length - 1);
|
||||||
}
|
}
|
||||||
CookieManager cookieManager = CookieManager.instance();
|
CookieManager cookieManager = CookieManager.instance();
|
||||||
final cookies = await cookieManager.getCookies(url: WebUri(url));
|
final cookies = await cookieManager.getCookies(url: WebUri(url));
|
||||||
@@ -89,29 +89,29 @@ class _AppWebviewState extends State<AppWebview> {
|
|||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: const Icon(Icons.more_horiz),
|
icon: const Icon(Icons.more_horiz),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showMenu(
|
showMenuX(
|
||||||
context: context,
|
context,
|
||||||
position: RelativeRect.fromLTRB(
|
Offset(context.width, context.padding.top),
|
||||||
MediaQuery.of(context).size.width,
|
[
|
||||||
0,
|
MenuEntry(
|
||||||
MediaQuery.of(context).size.width,
|
icon: Icons.open_in_browser,
|
||||||
0),
|
text: "Open in browser".tl,
|
||||||
items: [
|
onClick: () async =>
|
||||||
PopupMenuItem(
|
|
||||||
child: Text("Open in browser".tl),
|
|
||||||
onTap: () async =>
|
|
||||||
launchUrlString((await controller?.getUrl())!.toString()),
|
launchUrlString((await controller?.getUrl())!.toString()),
|
||||||
),
|
),
|
||||||
PopupMenuItem(
|
MenuEntry(
|
||||||
child: Text("Copy link".tl),
|
icon: Icons.copy,
|
||||||
onTap: () async => Clipboard.setData(ClipboardData(
|
text: "Copy link".tl,
|
||||||
|
onClick: () async => Clipboard.setData(ClipboardData(
|
||||||
text: (await controller?.getUrl())!.toString())),
|
text: (await controller?.getUrl())!.toString())),
|
||||||
),
|
),
|
||||||
PopupMenuItem(
|
MenuEntry(
|
||||||
child: Text("Reload".tl),
|
icon: Icons.refresh,
|
||||||
onTap: () => controller?.reload(),
|
text: "Reload".tl,
|
||||||
|
onClick: () => controller?.reload(),
|
||||||
),
|
),
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user