show downloaded list and view downloaded illusts

This commit is contained in:
wgh19
2024-05-14 20:24:35 +08:00
parent 5066ed761b
commit f49e847851
3 changed files with 360 additions and 1 deletions

View File

@@ -25,6 +25,45 @@ class SliverGridViewWithFixedItemHeight extends StatelessWidget {
))); )));
} }
double calcChildAspectRatio(double width) {
var crossItems = width ~/ maxCrossAxisExtent;
if (width % maxCrossAxisExtent != 0) {
crossItems += 1;
}
final itemWidth = width / crossItems;
return itemWidth / itemHeight;
}
}
class GridViewWithFixedItemHeight extends StatelessWidget {
const GridViewWithFixedItemHeight(
{ required this.builder,
required this.itemCount,
required this.maxCrossAxisExtent,
required this.itemHeight,
super.key});
final Widget Function(BuildContext, int) builder;
final int itemCount;
final double maxCrossAxisExtent;
final double itemHeight;
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: ((context, constraints) => GridView.builder(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: maxCrossAxisExtent,
childAspectRatio:
calcChildAspectRatio(constraints.maxWidth)),
itemBuilder: builder,
itemCount: itemCount,
)));
}
double calcChildAspectRatio(double width) { double calcChildAspectRatio(double width) {
var crossItems = width ~/ maxCrossAxisExtent; var crossItems = width ~/ maxCrossAxisExtent;
if (width % maxCrossAxisExtent != 0) { if (width % maxCrossAxisExtent != 0) {

View File

@@ -266,4 +266,30 @@ class DownloadManager {
} }
}); });
} }
void delete(DownloadedIllust illust) {
_db.execute('''
delete from download
where illust_id = ?;
''', [illust.illustId]);
var images = _db.select('''
select * from images
where illust_id = ?;
''', [illust.illustId]);
for(var image in images) {
File(image["path"] as String).deleteIfExists();
}
_db.execute('''
delete from images
where illust_id = ?;
''', [illust.illustId]);
}
List<String> getImagePaths(int illustId) {
var res = _db.select('''
select * from images
where illust_id = ?;
''', [illustId]);
return res.map((e) => e["path"] as String).toList();
}
} }

View File

@@ -1,4 +1,18 @@
import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/gestures.dart';
import 'package:photo_view/photo_view_gallery.dart';
import 'package:pixes/components/grid.dart';
import 'package:pixes/components/md.dart';
import 'package:pixes/components/page_route.dart';
import 'package:pixes/components/title_bar.dart';
import 'package:pixes/foundation/app.dart';
import 'package:pixes/network/download.dart';
import 'package:pixes/utils/translation.dart';
import 'package:window_manager/window_manager.dart';
import 'main_page.dart';
class DownloadedPage extends StatefulWidget { class DownloadedPage extends StatefulWidget {
const DownloadedPage({super.key}); const DownloadedPage({super.key});
@@ -8,8 +22,288 @@ class DownloadedPage extends StatefulWidget {
} }
class _DownloadedPageState extends State<DownloadedPage> { class _DownloadedPageState extends State<DownloadedPage> {
var illusts = <DownloadedIllust>[];
var flyoutControllers = <FlyoutController>[];
void loadData() {
illusts = DownloadManager().listAll();
flyoutControllers = List.generate(illusts.length, (index) => FlyoutController());
}
@override
void initState() {
loadData();
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const Placeholder(); return Column(
children: [
TitleBar(title: "Downloaded".tl),
Expanded(
child: buildBody(),
),
],
);
}
Widget buildBody() {
return GridViewWithFixedItemHeight(
itemCount: illusts.length,
itemHeight: 152,
maxCrossAxisExtent: 560,
builder: (context, index) {
return Card(
margin: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: Row(
children: [
Container(
width: 96,
height: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: ColorScheme.of(context).secondaryContainer
),
clipBehavior: Clip.antiAlias,
child: Image(
image: FileImage(DownloadManager().getImage(
illusts[index].illustId, 0)!),
fit: BoxFit.cover,
filterQuality: FilterQuality.medium,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
illusts[index].title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Text(
illusts[index].author,
style: const TextStyle(
fontSize: 12,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
Text(
"${illusts[index].imageCount}P",
style: const TextStyle(
fontSize: 12,
),
),
const Spacer(),
Row(
children: [
const Spacer(),
Button(
child: Text("View".tl).fixWidth(42),
onPressed: () {
App.rootNavigatorKey.currentState?.push(
AppPageRoute(builder: (context) {
return _DownloadedIllustViewPage(
DownloadManager().getImagePaths(
illusts[index].illustId));
}));
},
),
const SizedBox(width: 8),
FlyoutTarget(
controller: flyoutControllers[index],
child: Button(
child: Text("Delete".tl).fixWidth(42),
onPressed: () {
flyoutControllers[index].showFlyout(
navigatorKey: App.rootNavigatorKey.currentState,
builder: (context) {
return FlyoutContent(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Are you sure you want to delete?'.tl,
style: const TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 12.0),
Button(
onPressed: () {
Flyout.of(context).close();
DownloadManager().delete(illusts[index]);
setState(() {
illusts.removeAt(index);
flyoutControllers.removeAt(index);
});
},
child: Text('Yes'.tl),
),
],
),
);
});
},
),
),
],
),
],
),
),
],
),
);
}
).paddingHorizontal(8);
} }
} }
class _DownloadedIllustViewPage extends StatefulWidget {
const _DownloadedIllustViewPage(this.imagePaths);
final List<String> imagePaths;
@override
State<_DownloadedIllustViewPage> createState() => _DownloadedIllustViewPageState();
}
class _DownloadedIllustViewPageState extends State<_DownloadedIllustViewPage> with WindowListener{
int windowButtonKey = 0;
@override
void initState() {
windowManager.addListener(this);
super.initState();
}
@override
void dispose() {
windowManager.removeListener(this);
super.dispose();
}
@override
void onWindowMaximize() {
setState(() {
windowButtonKey++;
});
}
@override
void onWindowUnmaximize() {
setState(() {
windowButtonKey++;
});
}
var controller = PageController();
@override
Widget build(BuildContext context) {
return ScaffoldPage(
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
content: Listener(
onPointerSignal: (event) {
if(event is PointerScrollEvent) {
if(event.scrollDelta.dy > 0
&& controller.page!.toInt() < widget.imagePaths.length - 1) {
controller.jumpToPage(controller.page!.toInt() + 1);
} else if(event.scrollDelta.dy < 0 && controller.page!.toInt() > 0){
controller.jumpToPage(controller.page!.toInt() - 1);
}
}
},
child: LayoutBuilder(
builder: (context, constrains) {
var height = constrains.maxHeight;
return Stack(
children: [
Positioned.fill(child: PhotoViewGallery.builder(
pageController: controller,
backgroundDecoration: BoxDecoration(
color: FluentTheme.of(context).micaBackgroundColor
),
itemCount: widget.imagePaths.length,
builder: (context, index) {
return PhotoViewGalleryPageOptions(
imageProvider: FileImage(File(widget.imagePaths[index])),
);
},
onPageChanged: (index) {
setState(() {});
},
)),
Positioned(
top: 0,
left: 0,
right: 0,
child: SizedBox(
height: 36,
child: Row(
children: [
const SizedBox(width: 6,),
IconButton(
icon: const Icon(FluentIcons.back).paddingAll(2),
onPressed: () => context.pop()
),
const Expanded(
child: DragToMoveArea(child: SizedBox.expand(),),
),
if(App.isDesktop)
WindowButtons(key: ValueKey(windowButtonKey),),
],
),
),
),
Positioned(
left: 0,
top: height / 2 - 9,
child: IconButton(
icon: const Icon(FluentIcons.chevron_left, size: 18,),
onPressed: () {
controller.previousPage(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
},
).paddingAll(8),
),
Positioned(
right: 0,
top: height / 2 - 9,
child: IconButton(
icon: const Icon(FluentIcons.chevron_right, size: 18),
onPressed: () {
controller.nextPage(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
},
).paddingAll(8),
),
Positioned(
left: 12,
bottom: 8,
child: Text(
"${controller.page!.toInt() + 1}/${widget.imagePaths.length}",
),
)
],
);
},
),
),
);
}
}