From b65dc78fb250e6a6b76d2a42e4e5f1a52d7d3eda Mon Sep 17 00:00:00 2001 From: lifegpc Date: Sun, 3 Sep 2023 16:04:32 +0800 Subject: [PATCH] Update --- lib/api/gallery.dart | 6 +++ lib/galleries.dart | 3 +- lib/gallery.dart | 88 ++++++++++++++++++++++++++++++++++++++++++++ lib/l10n/app_en.arb | 5 ++- lib/l10n/app_zh.arb | 5 ++- lib/main.dart | 22 +++++++++++ lib/settings.dart | 36 +++++++++++++++++- pubspec.lock | 2 +- pubspec.yaml | 2 + 9 files changed, 164 insertions(+), 5 deletions(-) create mode 100644 lib/gallery.dart diff --git a/lib/api/gallery.dart b/lib/api/gallery.dart index 35221c4..3d58312 100644 --- a/lib/api/gallery.dart +++ b/lib/api/gallery.dart @@ -1,4 +1,5 @@ import 'package:json_annotation/json_annotation.dart'; +import '../globals.dart'; part 'gallery.g.dart'; @@ -48,6 +49,11 @@ class GMeta { static int _toJson(DateTime posted) => posted.millisecondsSinceEpoch ~/ 1000; factory GMeta.fromJson(Map json) => _$GMetaFromJson(json); Map toJson() => _$GMetaToJson(this); + String get preferredTitle => prefs.getBool("useTitleJpn") == true + ? titleJpn.isEmpty + ? title + : titleJpn + : title; } @JsonSerializable() diff --git a/lib/galleries.dart b/lib/galleries.dart index 5f6f261..1bae5d6 100644 --- a/lib/galleries.dart +++ b/lib/galleries.dart @@ -50,6 +50,7 @@ class _GalleriesPage extends State with ThemeModeWidget { @override Widget build(BuildContext context) { + tryInitApi(context); return Scaffold( appBar: AppBar( leading: IconButton( @@ -69,7 +70,7 @@ class _GalleriesPage extends State with ThemeModeWidget { builderDelegate: PagedChildBuilderDelegate( itemBuilder: (context, item, index) { return ListTile( - title: SelectableText(item.title), + title: Text(item.preferredTitle), onTap: () { context.push("/gallery/${item.gid}"); }, diff --git a/lib/gallery.dart b/lib/gallery.dart new file mode 100644 index 0000000..49da547 --- /dev/null +++ b/lib/gallery.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:go_router/go_router.dart'; +import 'package:logging/logging.dart'; +import 'api/gallery.dart'; +import 'globals.dart'; + +final _log = Logger("GalleryPage"); + +class GalleryPage extends StatefulWidget { + const GalleryPage(int gid, {Key? key}) + : _gid = gid, + super(key: key); + + final int _gid; + static const String routeName = '/gallery/:gid'; + + @override + State createState() => _GalleryPage(); +} + +class _GalleryPage extends State with ThemeModeWidget { + _GalleryPage(); + int _gid = 0; + GalleryData? _data; + Object? _error; + bool _isLoading = false; + + Future _fetchData() async { + try { + _isLoading = true; + final data = (await api.getGallery(_gid)).unwrap(); + setState(() { + _data = data; + _isLoading = false; + }); + } catch (e) { + _log.severe("Failed to load gallery $_gid:", e); + setState(() { + _error = e; + _isLoading = false; + }); + } + } + + @override + void initState() { + _gid = widget._gid; + _data = null; + _error = null; + super.initState(); + } + + @override + Widget build(BuildContext context) { + tryInitApi(context); + final isLoading = _data == null && _error == null; + if (isLoading && !_isLoading) _fetchData(); + final title = isLoading + ? AppLocalizations.of(context)!.loading + : _data != null + ? _data!.meta.preferredTitle + : AppLocalizations.of(context)!.gallery; + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () { + context.canPop() ? context.pop() : context.go("/"); + }, + ), + title: _data != null ? SelectableText(title) : Text(title), + actions: [ + buildThemeModeIcon(context), + buildMoreVertSettingsButon(context), + ], + ), + body: isLoading + ? const Center(child: CircularProgressIndicator()) + : _data != null + ? Center( + child: Text("Gallery $_gid"), + ) + : Center( + child: Text("Error: $_error"), + )); + } +} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index cb031a8..ea64445 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -19,5 +19,8 @@ "lang": "Language", "systemLang": "System Language", "reset": "Reset", - "galleries": "Galleries" + "galleries": "Galleries", + "loading": "Loading...", + "gallery": "Gallery", + "useTitleJpn": "Use Japanese title first" } diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 6f0bb6e..64d18e9 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -19,5 +19,8 @@ "lang": "语言", "systemLang": "系统语言", "reset": "重置", - "galleries": "画廊" + "galleries": "画廊", + "loading": "加载中…", + "gallery": "画廊", + "useTitleJpn": "优先使用日语标题" } diff --git a/lib/main.dart b/lib/main.dart index 8ea0fe7..5f75615 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,6 +8,7 @@ import 'package:logging/logging.dart'; import 'package:window_manager/window_manager.dart'; import 'create_root_user.dart'; import 'galleries.dart'; +import 'gallery.dart'; import 'globals.dart'; import 'home.dart'; import 'login.dart'; @@ -16,6 +17,8 @@ import 'set_server.dart'; import 'settings.dart'; import 'utils.dart'; +final _routerLog = Logger("Router"); + final _router = GoRouter( routes: [ GoRoute( @@ -41,6 +44,24 @@ final _router = GoRouter( GoRoute( path: GalleriesPage.routeName, builder: (context, state) => const GalleriesPage(), + ), + GoRoute( + path: GalleryPage.routeName, + builder: (context, state) => GalleryPage( + int.parse(state.pathParameters["gid"]!), + ), + redirect: (context, state) { + try { + int.parse(state.pathParameters["gid"]!); + return null; + } catch (e) { + _routerLog.warning("Failed to parse gid:", e); + return "/"; + } + }), + GoRoute( + path: "/gallery", + redirect: (context, state) => "/galleries", ) ], ); @@ -87,6 +108,7 @@ void main() async { await windowManager.ensureInitialized(); } await initLogger(); + GoRouter.optionURLReflectsImperativeAPIs = true; runApp(const MainApp()); } diff --git a/lib/settings.dart b/lib/settings.dart index ce5a295..aaa4464 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -18,7 +18,9 @@ class SettingsPage extends StatefulWidget { class _SettingsPage extends State with ThemeModeWidget { Lang _oriLang = Lang.system; + bool _oriUseTitleJpn = false; Lang _lang = Lang.system; + bool _useTitleJpn = false; @override void initState() { super.initState(); @@ -30,6 +32,14 @@ class _SettingsPage extends State with ThemeModeWidget { _oriLang = Lang.system; _lang = Lang.system; } + try { + _oriUseTitleJpn = prefs.getBool("useTitleJpn") ?? false; + _useTitleJpn = _oriUseTitleJpn; + } catch (e) { + _log.warning("Failed to get useTitleJpn:", e); + _oriUseTitleJpn = false; + _useTitleJpn = false; + } } void fallback(BuildContext context) { @@ -42,17 +52,26 @@ class _SettingsPage extends State with ThemeModeWidget { if (_lang != Lang.system) MainApp.of(context).changeLang(Lang.system); setState(() { _lang = Lang.system; + _useTitleJpn = false; }); } Future save() async { bool re = true; - if (!await prefs.setInt("lang", _lang.index)) { + if (_lang != _oriLang && !await prefs.setInt("lang", _lang.index)) { re = false; _log.warning("Failed to save lang."); } else { _oriLang = _lang; } + if (_oriUseTitleJpn != _useTitleJpn) { + if (!await prefs.setBool("useTitleJpn", _useTitleJpn)) { + re = false; + _log.warning("Failed to save useTitleJpn."); + } else { + _oriUseTitleJpn = _useTitleJpn; + } + } return re; } @@ -111,6 +130,21 @@ class _SettingsPage extends State with ThemeModeWidget { .toList(), leadingIcon: const Icon(Icons.language), )), + Container( + padding: + const EdgeInsets.symmetric(vertical: 8), + child: CheckboxMenuButton( + value: _useTitleJpn, + onChanged: (bool? value) { + if (value != null) { + setState(() { + _useTitleJpn = value; + }); + } + }, + child: Text(AppLocalizations.of(context)! + .useTitleJpn), + )), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ diff --git a/pubspec.lock b/pubspec.lock index 041b168..6f7913b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -298,7 +298,7 @@ packages: source: sdk version: "0.0.0" flutter_web_plugins: - dependency: transitive + dependency: "direct main" description: flutter source: sdk version: "0.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 7a6ac34..08d1a6b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,6 +19,8 @@ dependencies: flutter_hooks: ^0.20.0 flutter_localizations: sdk: flutter + flutter_web_plugins: + sdk: flutter go_router: ^10.1.0 infinite_scroll_pagination: ^4.0.0 intl: any