Update mobile gallery page layout

This commit is contained in:
2023-11-29 22:31:35 +08:00
parent 03539f508c
commit abb95ba1ba
9 changed files with 217 additions and 7 deletions

View File

@@ -26,7 +26,10 @@ class GalleryBasicInfo extends StatelessWidget {
child: Row(children: [
Expanded(
flex: 2,
child: Thumbnail(firstPage, fileId: fileId, gid: gMeta.gid)),
child: Container(
margin: const EdgeInsets.only(right: 8),
child: Thumbnail(firstPage, fileId: fileId, gid: gMeta.gid),
)),
Expanded(
flex: 3,
child: Column(

View File

@@ -5,6 +5,7 @@ import '../api/file.dart';
import '../api/gallery.dart';
import 'gallery_basic_info.dart';
import 'gallery_info_desktop.dart';
import 'gallery_info_detail.dart';
import 'tags.dart';
import 'thumbnail_gridview.dart';
@@ -63,6 +64,8 @@ class _GalleryInfo extends State<GalleryInfo> with ThemeModeWidget {
gData: widget.gData,
files: widget.files),
const Divider(indent: 20, endIndent: 20),
GalleryInfoDetail(widget.gData.meta),
const Divider(indent: 20, endIndent: 20),
]),
)
: SliverList(

View File

@@ -125,7 +125,7 @@ class GalleryInfoDesktop extends StatelessWidget {
style: TextStyle(
color: cs.primary,
fontSize: 12))),
Rate(gData.meta.rating),
Rate(gData.meta.rating, fontSize: 12),
],
)
])),

View File

@@ -0,0 +1,50 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import '../api/gallery.dart';
import '../dialog/gallery_details_page.dart';
import '../main.dart';
import '../utils/filesize.dart';
import 'rate.dart';
class GalleryInfoDetail extends StatelessWidget {
const GalleryInfoDetail(this.meta, {Key? key}) : super(key: key);
final GMeta meta;
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
final i18n = AppLocalizations.of(context)!;
final locale = MainApp.of(context).lang.toLocale().toString();
return Container(
alignment: Alignment.center,
margin: const EdgeInsets.symmetric(horizontal: 40),
child: SizedBox(
height: 73,
child: Column(children: [
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text(i18n.pages(meta.filecount),
style: TextStyle(color: cs.secondary)),
Text(getFileSize(meta.filesize),
style: TextStyle(color: cs.secondary)),
]),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Rate(meta.rating, fontSize: 14),
Text(DateFormat.yMd(locale).add_jms().format(meta.posted),
style: TextStyle(color: cs.secondary)),
],
),
TextButton(
onPressed: () {
context.push('/dialog/gallery/details/${meta.gid}',
extra: GalleryDetailsPageExtra(meta: meta));
},
child: Text(i18n.seeMoreInfo)),
]),
),
);
}
}

View File

@@ -1,8 +1,9 @@
import 'package:flutter/material.dart';
class Rate extends StatelessWidget {
const Rate(this.rate, {Key? key}) : super(key: key);
const Rate(this.rate, {Key? key, this.fontSize}) : super(key: key);
final double rate;
final double? fontSize;
@override
Widget build(BuildContext context) {
@@ -17,9 +18,10 @@ class Rate extends StatelessWidget {
? Icons.star_border
: Icons.star_half,
color: cs.primary,
size: 12,
size: fontSize,
),
Text(" $rate", style: TextStyle(color: cs.secondary, fontSize: 12)),
Text(" $rate",
style: TextStyle(color: cs.secondary, fontSize: fontSize)),
],
);
}

View File

@@ -0,0 +1,128 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:logging/logging.dart';
import '../api/gallery.dart';
import '../globals.dart';
final _log = Logger("GalleryDetailsPage");
class _KeyValue extends StatelessWidget {
const _KeyValue(this.name, this.value, {Key? key, this.fontSize})
: super(key: key);
final String name;
final String value;
final double? fontSize;
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return Row(children: [
SizedBox(
width: 80,
child: Text(name,
style: TextStyle(color: cs.primary, fontSize: fontSize))),
Expanded(
child: SelectableText(value,
style: TextStyle(color: cs.secondary, fontSize: fontSize)),
)
]);
}
}
class GalleryDetailsPageExtra {
const GalleryDetailsPageExtra({this.meta});
final GMeta? meta;
}
class GalleryDetailsPage extends StatefulWidget {
const GalleryDetailsPage(this.gid, {Key? key, this.meta}) : super(key: key);
final int gid;
final GMeta? meta;
@override
State<GalleryDetailsPage> createState() => _GalleryDetailsPage();
}
class _GalleryDetailsPage extends State<GalleryDetailsPage> {
GMeta? _meta;
CancelToken? _cancel;
bool _isLoading = false;
Object? _error;
Future<void> _fetchData() async {
try {
_cancel = CancelToken();
_isLoading = true;
final data = (await api.getGallery(widget.gid)).unwrap();
if (!_cancel!.isCancelled) {
setState(() {
_meta = data.meta;
_isLoading = false;
});
}
} catch (e) {
if (!_cancel!.isCancelled) {
_log.severe("Failed to load gallery ${widget.gid}:", e);
setState(() {
_error = e;
_isLoading = false;
});
}
}
}
@override
void initState() {
_meta = widget.meta;
super.initState();
}
@override
void dispose() {
_cancel?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
tryInitApi(context);
final isLoading = _meta == null && _error == null;
final i18n = AppLocalizations.of(context)!;
final maxWidth = MediaQuery.of(context).size.width;
if (isLoading && !_isLoading) _fetchData();
return Container(
padding: maxWidth < 400
? const EdgeInsets.symmetric(vertical: 20, horizontal: 5)
: const EdgeInsets.all(20),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(10)),
child: isLoading
? const Center(child: CircularProgressIndicator())
: _error != null
? SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Error: $_error"),
ElevatedButton.icon(
onPressed: () {
_fetchData();
setState(() {
_error = null;
});
},
icon: const Icon(Icons.refresh),
label: Text(i18n.retry)),
],
))
: SingleChildScrollView(
child: Column(children: [
_KeyValue(
i18n.gid,
_meta!.gid.toString(),
fontSize: 14,
),
])),
);
}
}

View File

@@ -86,5 +86,6 @@
"downloadComplete": "Download completed.",
"downloadZipFailed": "Failed to download ZIP file.",
"rating": "Rating",
"preventScreenCapture": "Prevent screen capture"
"preventScreenCapture": "Prevent screen capture",
"seeMoreInfo": "See more information"
}

View File

@@ -86,5 +86,6 @@
"downloadComplete": "下载完毕。",
"downloadZipFailed": "Zip文件下载失败。",
"rating": "评分",
"preventScreenCapture": "防止截屏"
"preventScreenCapture": "防止截屏",
"seeMoreInfo": "显示更多信息"
}

View File

@@ -10,6 +10,7 @@ import 'api/client.dart';
import 'create_root_user.dart';
import 'dialog/dialog_page.dart';
import 'dialog/download_zip_page.dart';
import 'dialog/gallery_details_page.dart';
import 'galleries.dart';
import 'gallery.dart';
import 'globals.dart';
@@ -134,6 +135,27 @@ final _router = GoRouter(
return "/gallery/${state.pathParameters["gid"]}";
}
}),
GoRoute(
path: '/dialog/gallery/details/:gid',
pageBuilder: (context, state) {
final extra = state.extra as GalleryDetailsPageExtra?;
return DialogPage(
key: state.pageKey,
builder: (context) {
return GalleryDetailsPage(
int.parse(state.pathParameters["gid"]!),
meta: extra?.meta);
});
},
redirect: (context, state) {
try {
int.parse(state.pathParameters["gid"]!);
return null;
} catch (e) {
_routerLog.warning("Failed to parse gid:", e);
return "/";
}
}),
],
);