mirror of
https://github.com/wgh136/pixes.git
synced 2025-09-27 12:57:24 +00:00
page view
This commit is contained in:
@@ -76,6 +76,19 @@ class _IllustPageState extends State<IllustPage> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void openImage(int index) {
|
||||||
|
var images = <String>[];
|
||||||
|
for(var i = 0; i < widget.illust.images.length; i++) {
|
||||||
|
var downloadFile = DownloadManager().getImage(widget.illust.id, i);
|
||||||
|
if(downloadFile != null) {
|
||||||
|
images.add("file://${downloadFile.path}");
|
||||||
|
} else {
|
||||||
|
images.add(widget.illust.images[i].original);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImagePage.show(images, initialPage: index);
|
||||||
|
}
|
||||||
|
|
||||||
Widget buildImage(double width, double height, int index) {
|
Widget buildImage(double width, double height, int index) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return Text(
|
return Text(
|
||||||
@@ -108,9 +121,7 @@ class _IllustPageState extends State<IllustPage> {
|
|||||||
width: imageWidth,
|
width: imageWidth,
|
||||||
height: imageHeight,
|
height: imageHeight,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => ImagePage.show(downloadFile == null
|
onTap: () => openImage(index),
|
||||||
? widget.illust.images[index].original
|
|
||||||
: "file://${downloadFile.path}"),
|
|
||||||
child: Image(
|
child: Image(
|
||||||
key: ValueKey(index),
|
key: ValueKey(index),
|
||||||
image: downloadFile == null
|
image: downloadFile == null
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:fluent_ui/fluent_ui.dart';
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
import 'package:photo_view/photo_view.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:photo_view/photo_view_gallery.dart';
|
||||||
import 'package:pixes/components/md.dart';
|
import 'package:pixes/components/md.dart';
|
||||||
import 'package:pixes/components/page_route.dart';
|
import 'package:pixes/components/page_route.dart';
|
||||||
import 'package:pixes/foundation/app.dart';
|
import 'package:pixes/foundation/app.dart';
|
||||||
@@ -14,13 +16,16 @@ import 'package:share_plus/share_plus.dart';
|
|||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
class ImagePage extends StatefulWidget {
|
class ImagePage extends StatefulWidget {
|
||||||
const ImagePage(this.url, {super.key});
|
const ImagePage(this.urls, {this.initialPage = 1, super.key});
|
||||||
|
|
||||||
final String url;
|
final List<String> urls;
|
||||||
|
|
||||||
static show(String url) {
|
final int initialPage;
|
||||||
|
|
||||||
|
static show(List<String> urls, {int initialPage = 1}) {
|
||||||
App.rootNavigatorKey.currentState
|
App.rootNavigatorKey.currentState
|
||||||
?.push(AppPageRoute(builder: (context) => ImagePage(url)));
|
?.push(AppPageRoute(
|
||||||
|
builder: (context) => ImagePage(urls, initialPage: initialPage)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -56,70 +61,25 @@ class _ImagePageState extends State<ImagePage> with WindowListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
late var controller = PageController(initialPage: widget.initialPage);
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
late int currentPage = widget.initialPage;
|
||||||
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
|
|
||||||
color: FluentTheme.of(context).micaBackgroundColor,
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
Positioned.fill(
|
|
||||||
child: PhotoView(
|
|
||||||
backgroundDecoration: BoxDecoration(
|
|
||||||
color: FluentTheme.of(context).micaBackgroundColor),
|
|
||||||
filterQuality: FilterQuality.medium,
|
|
||||||
imageProvider: widget.url.startsWith("file://")
|
|
||||||
? FileImage(File(widget.url.replaceFirst("file://", "")))
|
|
||||||
: CachedImageProvider(widget.url) as ImageProvider,
|
|
||||||
)),
|
|
||||||
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(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
buildActions(),
|
|
||||||
if (App.isDesktop)
|
|
||||||
WindowButtons(
|
|
||||||
key: ValueKey(windowButtonKey),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
var menuController = FlyoutController();
|
var menuController = FlyoutController();
|
||||||
|
|
||||||
Future<File?> getFile() async {
|
Future<File?> getFile() async {
|
||||||
if (widget.url.startsWith("file://")) {
|
var image = widget.urls[currentPage];
|
||||||
return File(widget.url.replaceFirst("file://", ""));
|
if(image.startsWith("file://")){
|
||||||
|
return File(image.replaceFirst("file://", ""));
|
||||||
}
|
}
|
||||||
var res = await CacheManager().findCache(widget.url);
|
var file = await CacheManager().findCache(image);
|
||||||
if(res == null){
|
return file == null
|
||||||
return null;
|
? null
|
||||||
}
|
: File(file);
|
||||||
return File(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String getExtensionName() {
|
String getExtensionName() {
|
||||||
var fileName = widget.url.split('/').last;
|
var fileName = widget.urls[currentPage].split('/').last;
|
||||||
if(fileName.contains('.')){
|
if(fileName.contains('.')){
|
||||||
return '.${fileName.split('.').last}';
|
return '.${fileName.split('.').last}';
|
||||||
}
|
}
|
||||||
@@ -142,15 +102,12 @@ class _ImagePageState extends State<ImagePage> with WindowListener {
|
|||||||
MenuFlyoutItem(text: Text("Share".tl), onPressed: () async{
|
MenuFlyoutItem(text: Text("Share".tl), onPressed: () async{
|
||||||
var file = await getFile();
|
var file = await getFile();
|
||||||
if(file != null){
|
if(file != null){
|
||||||
|
var ext = getExtensionName();
|
||||||
var fileName = file.path.split('/').last;
|
var fileName = file.path.split('/').last;
|
||||||
String ext;
|
|
||||||
if(!fileName.contains('.')){
|
if(!fileName.contains('.')){
|
||||||
ext = getExtensionName();
|
fileName += ext;
|
||||||
fileName += getExtensionName();
|
|
||||||
} else {
|
|
||||||
ext = file.path.split('.').last;
|
|
||||||
}
|
}
|
||||||
var mediaType = switch(ext.replaceFirst('.', "")){
|
var mediaType = switch(ext){
|
||||||
'jpg' => 'image/jpeg',
|
'jpg' => 'image/jpeg',
|
||||||
'jpeg' => 'image/jpeg',
|
'jpeg' => 'image/jpeg',
|
||||||
'png' => 'image/png',
|
'png' => 'image/png',
|
||||||
@@ -158,17 +115,120 @@ class _ImagePageState extends State<ImagePage> with WindowListener {
|
|||||||
'webp' => 'image/webp',
|
'webp' => 'image/webp',
|
||||||
_ => 'application/octet-stream'
|
_ => 'application/octet-stream'
|
||||||
};
|
};
|
||||||
Share.shareXFiles([XFile.fromData(
|
Share.shareXFiles([XFile(file.path, mimeType: mediaType, name: fileName)]);
|
||||||
await file.readAsBytes(),
|
|
||||||
mimeType: mediaType,
|
|
||||||
name: fileName)]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
|
||||||
|
color: FluentTheme.of(context).micaBackgroundColor,
|
||||||
|
child: Listener(
|
||||||
|
onPointerSignal: (event) {
|
||||||
|
if(event is PointerScrollEvent &&
|
||||||
|
!HardwareKeyboard.instance.isControlPressed) {
|
||||||
|
if(event.scrollDelta.dy > 0
|
||||||
|
&& controller.page!.toInt() < widget.urls.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: const BoxDecoration(
|
||||||
|
color: Colors.transparent
|
||||||
|
),
|
||||||
|
itemCount: widget.urls.length,
|
||||||
|
builder: (context, index) {
|
||||||
|
var image = widget.urls[index];
|
||||||
|
|
||||||
|
return PhotoViewGalleryPageOptions(
|
||||||
|
imageProvider: image.startsWith("file://")
|
||||||
|
? FileImage(File(image.replaceFirst("file://", "")))
|
||||||
|
: CachedImageProvider(image) as ImageProvider,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onPageChanged: (index) {
|
||||||
|
setState(() {
|
||||||
|
currentPage = index;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
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(),),
|
||||||
|
),
|
||||||
|
buildActions(),
|
||||||
|
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(
|
||||||
|
"${currentPage + 1}/${widget.urls.length}",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget buildActions() {
|
Widget buildActions() {
|
||||||
var width = MediaQuery.of(context).size.width;
|
var width = MediaQuery.of(context).size.width;
|
||||||
return FlyoutTarget(
|
return FlyoutTarget(
|
||||||
|
Reference in New Issue
Block a user