This commit is contained in:
2023-09-03 16:04:32 +08:00
parent 95b8435f78
commit b65dc78fb2
9 changed files with 164 additions and 5 deletions

View File

@@ -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<String, dynamic> json) => _$GMetaFromJson(json);
Map<String, dynamic> toJson() => _$GMetaToJson(this);
String get preferredTitle => prefs.getBool("useTitleJpn") == true
? titleJpn.isEmpty
? title
: titleJpn
: title;
}
@JsonSerializable()

View File

@@ -50,6 +50,7 @@ class _GalleriesPage extends State<GalleriesPage> with ThemeModeWidget {
@override
Widget build(BuildContext context) {
tryInitApi(context);
return Scaffold(
appBar: AppBar(
leading: IconButton(
@@ -69,7 +70,7 @@ class _GalleriesPage extends State<GalleriesPage> with ThemeModeWidget {
builderDelegate: PagedChildBuilderDelegate<GMeta>(
itemBuilder: (context, item, index) {
return ListTile(
title: SelectableText(item.title),
title: Text(item.preferredTitle),
onTap: () {
context.push("/gallery/${item.gid}");
},

88
lib/gallery.dart Normal file
View File

@@ -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<GalleryPage> createState() => _GalleryPage();
}
class _GalleryPage extends State<GalleryPage> with ThemeModeWidget {
_GalleryPage();
int _gid = 0;
GalleryData? _data;
Object? _error;
bool _isLoading = false;
Future<void> _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"),
));
}
}

View File

@@ -19,5 +19,8 @@
"lang": "Language",
"systemLang": "System Language",
"reset": "Reset",
"galleries": "Galleries"
"galleries": "Galleries",
"loading": "Loading...",
"gallery": "Gallery",
"useTitleJpn": "Use Japanese title first"
}

View File

@@ -19,5 +19,8 @@
"lang": "语言",
"systemLang": "系统语言",
"reset": "重置",
"galleries": "画廊"
"galleries": "画廊",
"loading": "加载中…",
"gallery": "画廊",
"useTitleJpn": "优先使用日语标题"
}

View File

@@ -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());
}

View File

@@ -18,7 +18,9 @@ class SettingsPage extends StatefulWidget {
class _SettingsPage extends State<SettingsPage> 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<SettingsPage> 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<SettingsPage> with ThemeModeWidget {
if (_lang != Lang.system) MainApp.of(context).changeLang(Lang.system);
setState(() {
_lang = Lang.system;
_useTitleJpn = false;
});
}
Future<bool> 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<SettingsPage> 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: [

View File

@@ -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"

View File

@@ -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