mirror of
https://github.com/lifegpc/eh_downloader_flutter.git
synced 2026-07-08 01:30:28 +08:00
Update localization and add ad and SFW marking
This commit is contained in:
@@ -126,7 +126,7 @@ class Tag {
|
|||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class ExtendedPMeta {
|
class ExtendedPMeta {
|
||||||
const ExtendedPMeta({
|
ExtendedPMeta({
|
||||||
required this.gid,
|
required this.gid,
|
||||||
required this.index,
|
required this.index,
|
||||||
required this.token,
|
required this.token,
|
||||||
@@ -143,9 +143,9 @@ class ExtendedPMeta {
|
|||||||
final int width;
|
final int width;
|
||||||
final int height;
|
final int height;
|
||||||
@JsonKey(name: 'is_nsfw')
|
@JsonKey(name: 'is_nsfw')
|
||||||
final bool isNsfw;
|
bool isNsfw;
|
||||||
@JsonKey(name: 'is_ad')
|
@JsonKey(name: 'is_ad')
|
||||||
final bool isAd;
|
bool isAd;
|
||||||
|
|
||||||
factory ExtendedPMeta.fromJson(Map<String, dynamic> json) =>
|
factory ExtendedPMeta.fromJson(Map<String, dynamic> json) =>
|
||||||
_$ExtendedPMetaFromJson(json);
|
_$ExtendedPMetaFromJson(json);
|
||||||
|
|||||||
@@ -24,10 +24,29 @@ class _GalleryInfo extends State<GalleryInfo> with ThemeModeWidget {
|
|||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onAdChanged(dynamic args) {
|
||||||
|
final arguments = args as (String, bool)?;
|
||||||
|
if (arguments == null) return;
|
||||||
|
final token = arguments.$1;
|
||||||
|
final isAd = arguments.$2;
|
||||||
|
var changed = false;
|
||||||
|
for (var e in widget.gData.pages) {
|
||||||
|
if (e.token == token) {
|
||||||
|
e.isAd = isAd;
|
||||||
|
changed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
listener.on("showNsfwChanged", stateChanged);
|
listener.on("showNsfwChanged", stateChanged);
|
||||||
listener.on("displayAdChanged", stateChanged);
|
listener.on("displayAdChanged", stateChanged);
|
||||||
|
listener.on("adChanged", _onAdChanged);
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +119,7 @@ class _GalleryInfo extends State<GalleryInfo> with ThemeModeWidget {
|
|||||||
controller.dispose();
|
controller.dispose();
|
||||||
listener.removeEventListener("showNsfwChanged", stateChanged);
|
listener.removeEventListener("showNsfwChanged", stateChanged);
|
||||||
listener.removeEventListener("displayAdChanged", stateChanged);
|
listener.removeEventListener("displayAdChanged", stateChanged);
|
||||||
|
listener.removeEventListener("adChanged", _onAdChanged);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,25 @@ final _log = Logger("ImageWithContextMenu");
|
|||||||
|
|
||||||
class ImageWithContextMenu extends StatelessWidget {
|
class ImageWithContextMenu extends StatelessWidget {
|
||||||
const ImageWithContextMenu(this.data,
|
const ImageWithContextMenu(this.data,
|
||||||
{Key? key, this.uri, this.dir, this.fileName, this.fmt = ImageFmt.jpg})
|
{Key? key,
|
||||||
|
this.uri,
|
||||||
|
this.dir,
|
||||||
|
this.fileName,
|
||||||
|
this.fmt = ImageFmt.jpg,
|
||||||
|
this.isNsfw,
|
||||||
|
this.changeNsfw,
|
||||||
|
this.isAd,
|
||||||
|
this.changeAd})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
final Uint8List data;
|
final Uint8List data;
|
||||||
final String? uri;
|
final String? uri;
|
||||||
final ImageFmt fmt;
|
final ImageFmt fmt;
|
||||||
final String? fileName;
|
final String? fileName;
|
||||||
final String? dir;
|
final String? dir;
|
||||||
|
final bool Function()? isNsfw;
|
||||||
|
final Function(bool isNsfw)? changeNsfw;
|
||||||
|
final bool Function()? isAd;
|
||||||
|
final Function(bool isAd)? changeAd;
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ContextMenuWidget(
|
return ContextMenuWidget(
|
||||||
@@ -53,6 +65,26 @@ class ImageWithContextMenu extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
if (isNsfw != null && changeNsfw != null) {
|
||||||
|
final nsfw = isNsfw!();
|
||||||
|
list.add(MenuAction(
|
||||||
|
title: nsfw
|
||||||
|
? AppLocalizations.of(context)!.markAsSfw
|
||||||
|
: AppLocalizations.of(context)!.markAsNsfw,
|
||||||
|
callback: () {
|
||||||
|
changeNsfw!(!isNsfw!());
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (isAd != null && changeAd != null) {
|
||||||
|
final ad = isAd!();
|
||||||
|
list.add(MenuAction(
|
||||||
|
title: ad
|
||||||
|
? AppLocalizations.of(context)!.markAsNonAd
|
||||||
|
: AppLocalizations.of(context)!.markAsAd,
|
||||||
|
callback: () {
|
||||||
|
changeAd!(!isAd!());
|
||||||
|
}));
|
||||||
|
}
|
||||||
return Menu(children: list);
|
return Menu(children: list);
|
||||||
},
|
},
|
||||||
child: Image.memory(data));
|
child: Image.memory(data));
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ enum _ThumbnailMenu {
|
|||||||
copyImage,
|
copyImage,
|
||||||
copyImgUrl,
|
copyImgUrl,
|
||||||
saveAs,
|
saveAs,
|
||||||
|
markAsNsfw,
|
||||||
|
markAsSfw,
|
||||||
|
markAsAd,
|
||||||
|
markAsNonAd,
|
||||||
}
|
}
|
||||||
|
|
||||||
class _Thumbnail extends State<Thumbnail> {
|
class _Thumbnail extends State<Thumbnail> {
|
||||||
@@ -74,11 +78,52 @@ class _Thumbnail extends State<Thumbnail> {
|
|||||||
bool _showNsfw = false;
|
bool _showNsfw = false;
|
||||||
String? _uri;
|
String? _uri;
|
||||||
CancelToken? _cancel;
|
CancelToken? _cancel;
|
||||||
|
CancelToken? _markAsNsfwCancel;
|
||||||
|
CancelToken? _markAsAdCancel;
|
||||||
String? _fileName;
|
String? _fileName;
|
||||||
String _dir = "";
|
String _dir = "";
|
||||||
Color? _iconColor;
|
Color? _iconColor;
|
||||||
double? _iconSize;
|
double? _iconSize;
|
||||||
bool _disposed = false;
|
bool _disposed = false;
|
||||||
|
void _onNsfwChanged(dynamic args) {
|
||||||
|
final arguments = args as (String, bool)?;
|
||||||
|
if (arguments == null) return;
|
||||||
|
final token = arguments.$1;
|
||||||
|
final isNsfw = arguments.$2;
|
||||||
|
if (token != widget._pMeta.token) return;
|
||||||
|
widget._pMeta.isNsfw = isNsfw;
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _markAsNsfw(bool isNsfw) async {
|
||||||
|
try {
|
||||||
|
_markAsNsfwCancel = CancelToken();
|
||||||
|
final token = widget._pMeta.token;
|
||||||
|
(await api.updateFileMeta(token,
|
||||||
|
isNsfw: isNsfw, cancel: _markAsNsfwCancel))
|
||||||
|
.unwrap();
|
||||||
|
listener.tryEmit("nsfwChanged", (token, isNsfw));
|
||||||
|
} catch (e) {
|
||||||
|
if (!_markAsNsfwCancel!.isCancelled) {
|
||||||
|
_log.warning("Failed to mark as nsfw:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _markAsAd(bool isAd) async {
|
||||||
|
try {
|
||||||
|
_markAsAdCancel = CancelToken();
|
||||||
|
final token = widget._pMeta.token;
|
||||||
|
(await api.updateFileMeta(token, isAd: isAd, cancel: _markAsAdCancel))
|
||||||
|
.unwrap();
|
||||||
|
listener.tryEmit("adChanged", (token, isAd));
|
||||||
|
} catch (e) {
|
||||||
|
if (!_markAsAdCancel!.isCancelled) {
|
||||||
|
_log.warning("Failed to mark as ad:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _fetchData() async {
|
Future<void> _fetchData() async {
|
||||||
try {
|
try {
|
||||||
_cancel = CancelToken();
|
_cancel = CancelToken();
|
||||||
@@ -133,6 +178,7 @@ class _Thumbnail extends State<Thumbnail> {
|
|||||||
_uri = null;
|
_uri = null;
|
||||||
_fileName = "${basenameWithoutExtension(widget._pMeta.name)}_thumb";
|
_fileName = "${basenameWithoutExtension(widget._pMeta.name)}_thumb";
|
||||||
_dir = isAndroid && widget.gid != null ? widget.gid!.toString() : "";
|
_dir = isAndroid && widget.gid != null ? widget.gid!.toString() : "";
|
||||||
|
listener.on("nsfwChanged", _onNsfwChanged);
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,6 +220,9 @@ class _Thumbnail extends State<Thumbnail> {
|
|||||||
void dispose() {
|
void dispose() {
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
_cancel?.cancel();
|
_cancel?.cancel();
|
||||||
|
_markAsNsfwCancel?.cancel();
|
||||||
|
_markAsAdCancel?.cancel();
|
||||||
|
listener.removeEventListener("nsfwChanged", _onNsfwChanged);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,6 +250,18 @@ class _Thumbnail extends State<Thumbnail> {
|
|||||||
_log.warning("Failed to save image:", err);
|
_log.warning("Failed to save image:", err);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case _ThumbnailMenu.markAsNsfw:
|
||||||
|
await _markAsNsfw(true);
|
||||||
|
break;
|
||||||
|
case _ThumbnailMenu.markAsSfw:
|
||||||
|
await _markAsNsfw(false);
|
||||||
|
break;
|
||||||
|
case _ThumbnailMenu.markAsAd:
|
||||||
|
await _markAsAd(true);
|
||||||
|
break;
|
||||||
|
case _ThumbnailMenu.markAsNonAd:
|
||||||
|
await _markAsAd(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +269,7 @@ class _Thumbnail extends State<Thumbnail> {
|
|||||||
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;
|
||||||
|
final isAd = widget._pMeta.isAd;
|
||||||
if (isLoading && !_isLoading) _fetchData();
|
if (isLoading && !_isLoading) _fetchData();
|
||||||
_iconSize ??= Theme.of(context).iconTheme.size;
|
_iconSize ??= Theme.of(context).iconTheme.size;
|
||||||
final iconSize = MediaQuery.of(context).size.width < 400
|
final iconSize = MediaQuery.of(context).size.width < 400
|
||||||
@@ -234,12 +296,37 @@ class _Thumbnail extends State<Thumbnail> {
|
|||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
value: _ThumbnailMenu.saveAs,
|
value: _ThumbnailMenu.saveAs,
|
||||||
child: Text(AppLocalizations.of(context)!.saveAs)),
|
child: Text(AppLocalizations.of(context)!.saveAs)),
|
||||||
|
const PopupMenuDivider(),
|
||||||
|
PopupMenuItem(
|
||||||
|
value: isNsfw
|
||||||
|
? _ThumbnailMenu.markAsSfw
|
||||||
|
: _ThumbnailMenu.markAsNsfw,
|
||||||
|
child: Text(isNsfw
|
||||||
|
? AppLocalizations.of(context)!.markAsSfw
|
||||||
|
: AppLocalizations.of(context)!.markAsNsfw)),
|
||||||
|
PopupMenuItem(
|
||||||
|
value: isAd
|
||||||
|
? _ThumbnailMenu.markAsNonAd
|
||||||
|
: _ThumbnailMenu.markAsAd,
|
||||||
|
child: Text(isAd
|
||||||
|
? AppLocalizations.of(context)!.markAsNonAd
|
||||||
|
: AppLocalizations.of(context)!.markAsAd)),
|
||||||
];
|
];
|
||||||
return list;
|
return list;
|
||||||
}));
|
}));
|
||||||
final timg = _data != null
|
final timg = _data != null
|
||||||
? ImageWithContextMenu(_data!,
|
? ImageWithContextMenu(_data!,
|
||||||
uri: _uri, fileName: _fileName, dir: _dir)
|
uri: _uri,
|
||||||
|
fileName: _fileName,
|
||||||
|
dir: _dir,
|
||||||
|
isNsfw: () => widget._pMeta.isNsfw,
|
||||||
|
changeNsfw: (isNsfw) {
|
||||||
|
_markAsNsfw(isNsfw);
|
||||||
|
},
|
||||||
|
isAd: () => widget._pMeta.isAd,
|
||||||
|
changeAd: (isAd) {
|
||||||
|
_markAsAd(isAd);
|
||||||
|
})
|
||||||
: null;
|
: null;
|
||||||
final img = widget.gid != null && widget.index != null && _data != null
|
final img = widget.gid != null && widget.index != null && _data != null
|
||||||
? GestureDetector(
|
? GestureDetector(
|
||||||
|
|||||||
@@ -25,9 +25,11 @@ class ThumbnailGridView extends StatelessWidget {
|
|||||||
final page = npages[index]!;
|
final page = npages[index]!;
|
||||||
final fileId =
|
final fileId =
|
||||||
files != null ? files!.files[page.token]!.first.id : null;
|
files != null ? files!.files[page.token]!.first.id : null;
|
||||||
|
final key = Key("thumbnail$gid-${page.index}");
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(4),
|
padding: const EdgeInsets.all(4),
|
||||||
child: Thumbnail(page,
|
child: Thumbnail(page,
|
||||||
|
key: key,
|
||||||
fileId: fileId,
|
fileId: fileId,
|
||||||
gid: gid,
|
gid: gid,
|
||||||
index: index + 1,
|
index: index + 1,
|
||||||
|
|||||||
@@ -52,12 +52,12 @@ class _GalleryPage extends State<GalleryPage>
|
|||||||
(await api.updateGalleryFileMeta(_gid,
|
(await api.updateGalleryFileMeta(_gid,
|
||||||
isNsfw: isNsfw, cancel: _markAsNsfwCancel))
|
isNsfw: isNsfw, cancel: _markAsNsfwCancel))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
if (!_cancel!.isCancelled) {
|
if (!_markAsNsfwCancel!.isCancelled) {
|
||||||
_fetchData();
|
_fetchData();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!_cancel!.isCancelled) {
|
if (!_markAsNsfwCancel!.isCancelled) {
|
||||||
_log.severe("Failed to mark gallery $_gid:", e);
|
_log.warning("Failed to mark gallery $_gid:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,14 +128,14 @@ final Path platformPath = Path();
|
|||||||
final TagsInfo tags = TagsInfo();
|
final TagsInfo tags = TagsInfo();
|
||||||
final GlobalKey<ScaffoldMessengerState> rootScaffoldMessengerKey =
|
final GlobalKey<ScaffoldMessengerState> rootScaffoldMessengerKey =
|
||||||
GlobalKey<ScaffoldMessengerState>();
|
GlobalKey<ScaffoldMessengerState>();
|
||||||
final EventListener listener = EventListener();
|
final EventListener listener = EventListener()..maxListeners = 0;
|
||||||
|
|
||||||
enum MoreVertSettings {
|
enum MoreVertSettings {
|
||||||
setServerUrl,
|
setServerUrl,
|
||||||
createRootUser,
|
createRootUser,
|
||||||
settings,
|
settings,
|
||||||
markAsNsfw,
|
markAsNsfw,
|
||||||
markAsNonNsfw,
|
markAsSfw,
|
||||||
}
|
}
|
||||||
|
|
||||||
void onMoreVertSettingsSelected(BuildContext context, MoreVertSettings value) {
|
void onMoreVertSettingsSelected(BuildContext context, MoreVertSettings value) {
|
||||||
@@ -152,7 +152,7 @@ void onMoreVertSettingsSelected(BuildContext context, MoreVertSettings value) {
|
|||||||
case MoreVertSettings.markAsNsfw:
|
case MoreVertSettings.markAsNsfw:
|
||||||
GalleryPage.maybeOf(context)?.markGalleryAsNsfw(true);
|
GalleryPage.maybeOf(context)?.markGalleryAsNsfw(true);
|
||||||
break;
|
break;
|
||||||
case MoreVertSettings.markAsNonNsfw:
|
case MoreVertSettings.markAsSfw:
|
||||||
GalleryPage.maybeOf(context)?.markGalleryAsNsfw(false);
|
GalleryPage.maybeOf(context)?.markGalleryAsNsfw(false);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -225,10 +225,10 @@ List<PopupMenuEntry<MoreVertSettings>> buildMoreVertSettings(
|
|||||||
if (isAllNsfw != null) {
|
if (isAllNsfw != null) {
|
||||||
list.add(PopupMenuItem(
|
list.add(PopupMenuItem(
|
||||||
value: isAllNsfw
|
value: isAllNsfw
|
||||||
? MoreVertSettings.markAsNonNsfw
|
? MoreVertSettings.markAsSfw
|
||||||
: MoreVertSettings.markAsNsfw,
|
: MoreVertSettings.markAsNsfw,
|
||||||
child: Text(isAllNsfw
|
child: Text(isAllNsfw
|
||||||
? AppLocalizations.of(context)!.markAsNonNsfw
|
? AppLocalizations.of(context)!.markAsSfw
|
||||||
: AppLocalizations.of(context)!.markAsNsfw),
|
: AppLocalizations.of(context)!.markAsNsfw),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,5 +89,7 @@
|
|||||||
"preventScreenCapture": "Prevent screen capture",
|
"preventScreenCapture": "Prevent screen capture",
|
||||||
"seeMoreInfo": "See more information",
|
"seeMoreInfo": "See more information",
|
||||||
"markAsNsfw": "Mark as NSFW",
|
"markAsNsfw": "Mark as NSFW",
|
||||||
"markAsNonNsfw": "Mark as non-NSFW"
|
"markAsSfw": "Mark as SFW",
|
||||||
|
"markAsAd": "Mark as Ad",
|
||||||
|
"markAsNonAd": "Mark as non-Ad"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,5 +89,7 @@
|
|||||||
"preventScreenCapture": "防止截屏",
|
"preventScreenCapture": "防止截屏",
|
||||||
"seeMoreInfo": "显示更多信息",
|
"seeMoreInfo": "显示更多信息",
|
||||||
"markAsNsfw": "标记为NSFW",
|
"markAsNsfw": "标记为NSFW",
|
||||||
"markAsNonNsfw": "标记为非NSFW"
|
"markAsSfw": "标记为SFW",
|
||||||
|
"markAsAd": "标记为广告",
|
||||||
|
"markAsNonAd": "标记为非广告"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user