mirror of
https://github.com/lifegpc/eh_downloader_flutter.git
synced 2026-07-08 01:30:28 +08:00
Update
This commit is contained in:
@@ -2,19 +2,11 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:super_clipboard/super_clipboard.dart';
|
|
||||||
import 'package:super_context_menu/super_context_menu.dart';
|
import 'package:super_context_menu/super_context_menu.dart';
|
||||||
import '../platform/to_png_none.dart'
|
import '../utils/clipboard.dart';
|
||||||
if (dart.library.html) '../platform/to_png.dart';
|
|
||||||
|
|
||||||
final _log = Logger("ImageWithContextMenu");
|
final _log = Logger("ImageWithContextMenu");
|
||||||
|
|
||||||
enum ImageFmt {
|
|
||||||
jpg,
|
|
||||||
png,
|
|
||||||
gif,
|
|
||||||
}
|
|
||||||
|
|
||||||
class ImageWithContextMenu extends StatelessWidget {
|
class ImageWithContextMenu extends StatelessWidget {
|
||||||
const ImageWithContextMenu(this.data,
|
const ImageWithContextMenu(this.data,
|
||||||
{Key? key, this.uri, this.fmt = ImageFmt.jpg})
|
{Key? key, this.uri, this.fmt = ImageFmt.jpg})
|
||||||
@@ -31,16 +23,7 @@ class ImageWithContextMenu extends StatelessWidget {
|
|||||||
title: AppLocalizations.of(context)!.copyImage,
|
title: AppLocalizations.of(context)!.copyImage,
|
||||||
callback: () async {
|
callback: () async {
|
||||||
try {
|
try {
|
||||||
final item = DataWriterItem();
|
await copyImageToClipboard(data, fmt);
|
||||||
if (!kIsWeb) {
|
|
||||||
item.add(fmt == ImageFmt.jpg
|
|
||||||
? Formats.jpeg(data)
|
|
||||||
: Formats.png(data));
|
|
||||||
} else {
|
|
||||||
item.add(Formats.png(
|
|
||||||
fmt == ImageFmt.jpg ? await jpgToPng(data) : data));
|
|
||||||
}
|
|
||||||
await ClipboardWriter.instance.write([item]);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
_log.warning("Failed to copy image to clipboard:", err);
|
_log.warning("Failed to copy image to clipboard:", err);
|
||||||
}
|
}
|
||||||
@@ -50,9 +33,7 @@ class ImageWithContextMenu extends StatelessWidget {
|
|||||||
list.add(MenuAction(
|
list.add(MenuAction(
|
||||||
title: AppLocalizations.of(context)!.copyImgUrl,
|
title: AppLocalizations.of(context)!.copyImgUrl,
|
||||||
callback: () {
|
callback: () {
|
||||||
final item = DataWriterItem();
|
copyTextToClipboard(uri!).catchError((err) {
|
||||||
item.add(Formats.plainText(uri!));
|
|
||||||
ClipboardWriter.instance.write([item]).catchError((err) {
|
|
||||||
_log.warning("Failed to copy image to clipboard:", err);
|
_log.warning("Failed to copy image to clipboard:", err);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:logging/logging.dart';
|
|||||||
import '../api/client.dart';
|
import '../api/client.dart';
|
||||||
import '../api/gallery.dart';
|
import '../api/gallery.dart';
|
||||||
import '../globals.dart';
|
import '../globals.dart';
|
||||||
|
import '../utils/clipboard.dart';
|
||||||
import 'image.dart';
|
import 'image.dart';
|
||||||
|
|
||||||
final _log = Logger("Thumbnail");
|
final _log = Logger("Thumbnail");
|
||||||
@@ -41,6 +42,11 @@ class Thumbnail extends StatefulWidget {
|
|||||||
State<Thumbnail> createState() => _Thumbnail();
|
State<Thumbnail> createState() => _Thumbnail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum _ThumbnailMenu {
|
||||||
|
copyImage,
|
||||||
|
copyImgUrl,
|
||||||
|
}
|
||||||
|
|
||||||
class _Thumbnail extends State<Thumbnail> {
|
class _Thumbnail extends State<Thumbnail> {
|
||||||
Uint8List? _data;
|
Uint8List? _data;
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
@@ -111,11 +117,52 @@ class _Thumbnail extends State<Thumbnail> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> onItemSelected(_ThumbnailMenu v) async {
|
||||||
|
switch (v) {
|
||||||
|
case _ThumbnailMenu.copyImage:
|
||||||
|
try {
|
||||||
|
copyImageToClipboard(_data!, ImageFmt.jpg);
|
||||||
|
} catch (err) {
|
||||||
|
_log.warning("Failed to copy image to clipboard:", err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case _ThumbnailMenu.copyImgUrl:
|
||||||
|
try {
|
||||||
|
copyTextToClipboard(_uri!);
|
||||||
|
} catch (err) {
|
||||||
|
_log.warning("Failed to copy image url to clipboard:", err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isLoading = _data == null && _error == null;
|
final isLoading = _data == null && _error == null;
|
||||||
final isNsfw = widget._pMeta.isNsfw;
|
final isNsfw = widget._pMeta.isNsfw;
|
||||||
if (isLoading && !_isLoading) _fetchData();
|
if (isLoading && !_isLoading) _fetchData();
|
||||||
|
final iconSize = Theme.of(context).iconTheme.size;
|
||||||
|
final moreVertMenu = Positioned(
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
|
width: iconSize,
|
||||||
|
height: iconSize,
|
||||||
|
child: PopupMenuButton(
|
||||||
|
icon: const Icon(Icons.more_vert),
|
||||||
|
onSelected: (v) {
|
||||||
|
onItemSelected(v);
|
||||||
|
},
|
||||||
|
itemBuilder: (context) {
|
||||||
|
var list = <PopupMenuEntry<_ThumbnailMenu>>[
|
||||||
|
PopupMenuItem(
|
||||||
|
value: _ThumbnailMenu.copyImage,
|
||||||
|
child: Text(AppLocalizations.of(context)!.copyImage)),
|
||||||
|
PopupMenuItem(
|
||||||
|
value: _ThumbnailMenu.copyImgUrl,
|
||||||
|
child: Text(AppLocalizations.of(context)!.copyImgUrl)),
|
||||||
|
];
|
||||||
|
return list;
|
||||||
|
}));
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: widget.width.toDouble(),
|
width: widget.width.toDouble(),
|
||||||
height: widget.height.toDouble(),
|
height: widget.height.toDouble(),
|
||||||
@@ -147,10 +194,17 @@ class _Thumbnail extends State<Thumbnail> {
|
|||||||
},
|
},
|
||||||
icon: const Icon(Icons.visibility),
|
icon: const Icon(Icons.visibility),
|
||||||
),
|
),
|
||||||
))
|
)),
|
||||||
|
moreVertMenu
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: ImageWithContextMenu(_data!, uri: _uri)
|
: Stack(children: [
|
||||||
|
SizedBox(
|
||||||
|
width: widget.width.toDouble(),
|
||||||
|
height: widget.height.toDouble(),
|
||||||
|
child: ImageWithContextMenu(_data!, uri: _uri)),
|
||||||
|
moreVertMenu
|
||||||
|
])
|
||||||
: Center(
|
: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
|||||||
32
lib/utils/clipboard.dart
Normal file
32
lib/utils/clipboard.dart
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:super_clipboard/super_clipboard.dart';
|
||||||
|
import '../platform/to_png_none.dart'
|
||||||
|
if (dart.library.html) '../platform/to_png.dart';
|
||||||
|
|
||||||
|
enum ImageFmt {
|
||||||
|
jpg,
|
||||||
|
png,
|
||||||
|
gif,
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> copyImageToClipboard(Uint8List data, ImageFmt fmt) async {
|
||||||
|
final item = DataWriterItem();
|
||||||
|
if (!kIsWeb) {
|
||||||
|
item.add(fmt == ImageFmt.jpg
|
||||||
|
? Formats.jpeg(data)
|
||||||
|
: fmt == ImageFmt.gif
|
||||||
|
? Formats.gif(data)
|
||||||
|
: Formats.png(data));
|
||||||
|
} else {
|
||||||
|
item.add(fmt == ImageFmt.gif
|
||||||
|
? Formats.gif(data)
|
||||||
|
: Formats.png(fmt == ImageFmt.jpg ? await jpgToPng(data) : data));
|
||||||
|
}
|
||||||
|
await ClipboardWriter.instance.write([item]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> copyTextToClipboard(String text) async {
|
||||||
|
final item = DataWriterItem();
|
||||||
|
item.add(Formats.plainText(text));
|
||||||
|
await ClipboardWriter.instance.write([item]);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user