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:
@@ -1,4 +1,5 @@
|
|||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
import '../globals.dart';
|
||||||
|
|
||||||
part 'gallery.g.dart';
|
part 'gallery.g.dart';
|
||||||
|
|
||||||
@@ -48,6 +49,11 @@ class GMeta {
|
|||||||
static int _toJson(DateTime posted) => posted.millisecondsSinceEpoch ~/ 1000;
|
static int _toJson(DateTime posted) => posted.millisecondsSinceEpoch ~/ 1000;
|
||||||
factory GMeta.fromJson(Map<String, dynamic> json) => _$GMetaFromJson(json);
|
factory GMeta.fromJson(Map<String, dynamic> json) => _$GMetaFromJson(json);
|
||||||
Map<String, dynamic> toJson() => _$GMetaToJson(this);
|
Map<String, dynamic> toJson() => _$GMetaToJson(this);
|
||||||
|
String get preferredTitle => prefs.getBool("useTitleJpn") == true
|
||||||
|
? titleJpn.isEmpty
|
||||||
|
? title
|
||||||
|
: titleJpn
|
||||||
|
: title;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ class _GalleriesPage extends State<GalleriesPage> with ThemeModeWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
tryInitApi(context);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
@@ -69,7 +70,7 @@ class _GalleriesPage extends State<GalleriesPage> with ThemeModeWidget {
|
|||||||
builderDelegate: PagedChildBuilderDelegate<GMeta>(
|
builderDelegate: PagedChildBuilderDelegate<GMeta>(
|
||||||
itemBuilder: (context, item, index) {
|
itemBuilder: (context, item, index) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: SelectableText(item.title),
|
title: Text(item.preferredTitle),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.push("/gallery/${item.gid}");
|
context.push("/gallery/${item.gid}");
|
||||||
},
|
},
|
||||||
|
|||||||
88
lib/gallery.dart
Normal file
88
lib/gallery.dart
Normal 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"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,5 +19,8 @@
|
|||||||
"lang": "Language",
|
"lang": "Language",
|
||||||
"systemLang": "System Language",
|
"systemLang": "System Language",
|
||||||
"reset": "Reset",
|
"reset": "Reset",
|
||||||
"galleries": "Galleries"
|
"galleries": "Galleries",
|
||||||
|
"loading": "Loading...",
|
||||||
|
"gallery": "Gallery",
|
||||||
|
"useTitleJpn": "Use Japanese title first"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,5 +19,8 @@
|
|||||||
"lang": "语言",
|
"lang": "语言",
|
||||||
"systemLang": "系统语言",
|
"systemLang": "系统语言",
|
||||||
"reset": "重置",
|
"reset": "重置",
|
||||||
"galleries": "画廊"
|
"galleries": "画廊",
|
||||||
|
"loading": "加载中…",
|
||||||
|
"gallery": "画廊",
|
||||||
|
"useTitleJpn": "优先使用日语标题"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import 'package:logging/logging.dart';
|
|||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
import 'create_root_user.dart';
|
import 'create_root_user.dart';
|
||||||
import 'galleries.dart';
|
import 'galleries.dart';
|
||||||
|
import 'gallery.dart';
|
||||||
import 'globals.dart';
|
import 'globals.dart';
|
||||||
import 'home.dart';
|
import 'home.dart';
|
||||||
import 'login.dart';
|
import 'login.dart';
|
||||||
@@ -16,6 +17,8 @@ import 'set_server.dart';
|
|||||||
import 'settings.dart';
|
import 'settings.dart';
|
||||||
import 'utils.dart';
|
import 'utils.dart';
|
||||||
|
|
||||||
|
final _routerLog = Logger("Router");
|
||||||
|
|
||||||
final _router = GoRouter(
|
final _router = GoRouter(
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
@@ -41,6 +44,24 @@ final _router = GoRouter(
|
|||||||
GoRoute(
|
GoRoute(
|
||||||
path: GalleriesPage.routeName,
|
path: GalleriesPage.routeName,
|
||||||
builder: (context, state) => const GalleriesPage(),
|
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 windowManager.ensureInitialized();
|
||||||
}
|
}
|
||||||
await initLogger();
|
await initLogger();
|
||||||
|
GoRouter.optionURLReflectsImperativeAPIs = true;
|
||||||
runApp(const MainApp());
|
runApp(const MainApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ class SettingsPage extends StatefulWidget {
|
|||||||
|
|
||||||
class _SettingsPage extends State<SettingsPage> with ThemeModeWidget {
|
class _SettingsPage extends State<SettingsPage> with ThemeModeWidget {
|
||||||
Lang _oriLang = Lang.system;
|
Lang _oriLang = Lang.system;
|
||||||
|
bool _oriUseTitleJpn = false;
|
||||||
Lang _lang = Lang.system;
|
Lang _lang = Lang.system;
|
||||||
|
bool _useTitleJpn = false;
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@@ -30,6 +32,14 @@ class _SettingsPage extends State<SettingsPage> with ThemeModeWidget {
|
|||||||
_oriLang = Lang.system;
|
_oriLang = Lang.system;
|
||||||
_lang = 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) {
|
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);
|
if (_lang != Lang.system) MainApp.of(context).changeLang(Lang.system);
|
||||||
setState(() {
|
setState(() {
|
||||||
_lang = Lang.system;
|
_lang = Lang.system;
|
||||||
|
_useTitleJpn = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> save() async {
|
Future<bool> save() async {
|
||||||
bool re = true;
|
bool re = true;
|
||||||
if (!await prefs.setInt("lang", _lang.index)) {
|
if (_lang != _oriLang && !await prefs.setInt("lang", _lang.index)) {
|
||||||
re = false;
|
re = false;
|
||||||
_log.warning("Failed to save lang.");
|
_log.warning("Failed to save lang.");
|
||||||
} else {
|
} else {
|
||||||
_oriLang = _lang;
|
_oriLang = _lang;
|
||||||
}
|
}
|
||||||
|
if (_oriUseTitleJpn != _useTitleJpn) {
|
||||||
|
if (!await prefs.setBool("useTitleJpn", _useTitleJpn)) {
|
||||||
|
re = false;
|
||||||
|
_log.warning("Failed to save useTitleJpn.");
|
||||||
|
} else {
|
||||||
|
_oriUseTitleJpn = _useTitleJpn;
|
||||||
|
}
|
||||||
|
}
|
||||||
return re;
|
return re;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +130,21 @@ class _SettingsPage extends State<SettingsPage> with ThemeModeWidget {
|
|||||||
.toList(),
|
.toList(),
|
||||||
leadingIcon: const Icon(Icons.language),
|
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(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ packages:
|
|||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
flutter_web_plugins:
|
flutter_web_plugins:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ dependencies:
|
|||||||
flutter_hooks: ^0.20.0
|
flutter_hooks: ^0.20.0
|
||||||
flutter_localizations:
|
flutter_localizations:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
flutter_web_plugins:
|
||||||
|
sdk: flutter
|
||||||
go_router: ^10.1.0
|
go_router: ^10.1.0
|
||||||
infinite_scroll_pagination: ^4.0.0
|
infinite_scroll_pagination: ^4.0.0
|
||||||
intl: any
|
intl: any
|
||||||
|
|||||||
Reference in New Issue
Block a user