mirror of
https://github.com/wgh136/pixes.git
synced 2025-09-27 04:57:23 +00:00
show downloaded list and view downloaded illusts
This commit is contained in:
@@ -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) {
|
||||||
|
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
@@ -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}",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user