From eab939928fb9c113ff1b43ffe391df97fef8dc09 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Mon, 9 Dec 2024 23:45:10 +0800 Subject: [PATCH] :sparkles: Notification card :bug: Fix post item truncate hint from overflowing --- assets/translations/en.json | 6 ++ assets/translations/zh.json | 6 ++ lib/screens/home.dart | 78 ++++++++++--------- lib/theme.dart | 4 - .../navigation/app_drawer_navigation.dart | 3 +- lib/widgets/post/post_item.dart | 55 ++++++------- 6 files changed, 83 insertions(+), 69 deletions(-) diff --git a/assets/translations/en.json b/assets/translations/en.json index 3d94d22..a98d131 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -274,6 +274,12 @@ "attachmentUnsetAsPostThumbnail": "Unset as post thumbnail", "attachmentSetThumbnail": "Set thumbnail", "attachmentUpload": "Upload", + "notification": "Notification", + "notificationUnreadCount": { + "zero": "All notifications read", + "one": "{} unread notification", + "other": "{} unread notifications" + }, "notificationUnread": "Unread", "notificationRead": "Read", "notificationMarkAllRead": "Mark all notifications as read", diff --git a/assets/translations/zh.json b/assets/translations/zh.json index ff733ed..54b2bf0 100644 --- a/assets/translations/zh.json +++ b/assets/translations/zh.json @@ -272,6 +272,12 @@ "attachmentUnsetAsPostThumbnail": "取消设置为帖子缩略图", "attachmentSetThumbnail": "设置缩略图", "attachmentUpload": "上传", + "notification": "通知", + "notificationUnreadCount": { + "zero": "无未读通知", + "one": "有 {} 个未读通知", + "other": "有 {} 个未读通知" + }, "notificationUnread": "未读", "notificationRead": "已读", "notificationMarkAllRead": "已读所有通知", diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 20a6cb8..9911ec2 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -3,6 +3,7 @@ import 'dart:math' as math; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:gap/gap.dart'; +import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:provider/provider.dart'; @@ -40,6 +41,10 @@ class _HomeScreenState extends State { name: 'dashEntryCheckIn', child: _HomeDashCheckInWidget(), ), + HomeScreenDashEntry( + name: 'dashEntryNotification', + child: _HomeDashNotificationWidget(), + ), ]; @override @@ -52,16 +57,12 @@ class _HomeScreenState extends State { body: LayoutBuilder( builder: (context, constraints) { return Align( - alignment: constraints.maxWidth > 640 - ? Alignment.center - : Alignment.topCenter, + alignment: constraints.maxWidth > 640 ? Alignment.center : Alignment.topCenter, child: Container( constraints: const BoxConstraints(maxWidth: 640), child: SingleChildScrollView( child: Column( - mainAxisAlignment: constraints.maxWidth > 640 - ? MainAxisAlignment.center - : MainAxisAlignment.start, + mainAxisAlignment: constraints.maxWidth > 640 ? MainAxisAlignment.center : MainAxisAlignment.start, children: [ if (constraints.maxWidth <= 640) const Gap(8), _HomeDashSpecialDayWidget().padding(top: 8, horizontal: 8), @@ -96,9 +97,7 @@ class _HomeDashSpecialDayWidget extends StatelessWidget { final ua = context.watch(); final today = DateTime.now(); final birthday = ua.user?.profile?.birthday?.toLocal(); - final isBirthday = birthday != null && - birthday.day == today.day && - birthday.month == today.month; + final isBirthday = birthday != null && birthday.day == today.day && birthday.month == today.month; return Column( children: [ if (isBirthday) @@ -154,20 +153,15 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> { } Widget _buildDetailChunk(int index, bool positive) { - final prefix = - positive ? 'dailyCheckPositiveHint' : 'dailyCheckNegativeHint'; - final mod = - positive ? kSuggestionPositiveHintCount : kSuggestionNegativeHintCount; + final prefix = positive ? 'dailyCheckPositiveHint' : 'dailyCheckNegativeHint'; + final mod = positive ? kSuggestionPositiveHintCount : kSuggestionNegativeHintCount; final pos = math.max(1, _todayRecord!.resultModifiers[index] % mod); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( prefix.tr(args: ['$prefix$pos'.tr()]), - style: Theme.of(context) - .textTheme - .titleMedium! - .copyWith(fontWeight: FontWeight.bold), + style: Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.bold), ).tr(), Text( '$prefix${pos}Description', @@ -202,10 +196,7 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> { else Text( 'dailyCheckEverythingIsNegative', - style: Theme.of(context) - .textTheme - .titleMedium! - .copyWith(fontWeight: FontWeight.bold), + style: Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.bold), ).tr(), const Gap(8), if (_todayRecord?.resultTier != 4) @@ -221,10 +212,7 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> { else Text( 'dailyCheckEverythingIsPositive', - style: Theme.of(context) - .textTheme - .titleMedium! - .copyWith(fontWeight: FontWeight.bold), + style: Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.bold), ).tr(), ], ), @@ -338,14 +326,28 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> { } } -class _HomeDashLinkWidget extends StatelessWidget { - final String title; - final String subtitle; - const _HomeDashLinkWidget({ - super.key, - required this.title, - required this.subtitle, - }); +class _HomeDashNotificationWidget extends StatefulWidget { + const _HomeDashNotificationWidget({super.key}); + + @override + State<_HomeDashNotificationWidget> createState() => _HomeDashNotificationWidgetState(); +} + +class _HomeDashNotificationWidgetState extends State<_HomeDashNotificationWidget> { + int? _count; + + Future _fetchNotificationCount() async { + final sn = context.read(); + final resp = await sn.client.get('/cgi/id/notifications/count'); + _count = resp.data['count']; + setState(() {}); + } + + @override + void initState() { + super.initState(); + _fetchNotificationCount(); + } @override Widget build(BuildContext context) { @@ -358,11 +360,11 @@ class _HomeDashLinkWidget extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - title, + 'notification', style: Theme.of(context).textTheme.titleLarge, - ), + ).tr(), Text( - subtitle, + _count == null ? 'loading'.tr() : 'notificationUnreadCount'.plural(_count ?? 0), style: Theme.of(context).textTheme.bodyLarge, ), ], @@ -377,7 +379,9 @@ class _HomeDashLinkWidget extends StatelessWidget { ), child: IconButton( icon: const Icon(Symbols.arrow_right_alt), - onPressed: () {}, + onPressed: () { + GoRouter.of(context).goNamed('notification'); + }, ), ), ) diff --git a/lib/theme.dart b/lib/theme.dart index bec7f77..36e52a5 100644 --- a/lib/theme.dart +++ b/lib/theme.dart @@ -1,8 +1,4 @@ -import 'dart:io'; - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; const kMaterialYouToggleStoreKey = 'app_theme_material_you'; diff --git a/lib/widgets/navigation/app_drawer_navigation.dart b/lib/widgets/navigation/app_drawer_navigation.dart index 2edbf74..7c51e9d 100644 --- a/lib/widgets/navigation/app_drawer_navigation.dart +++ b/lib/widgets/navigation/app_drawer_navigation.dart @@ -60,8 +60,7 @@ class _AppNavigationDrawerState extends State { ], ).padding( horizontal: 32, - top: MediaQuery.of(context).padding.top + 12, - bottom: 12, + vertical: 12, ), ...destinations.where((ele) => ele.isPinned).map((ele) { return NavigationDrawerDestination( diff --git a/lib/widgets/post/post_item.dart b/lib/widgets/post/post_item.dart index 6cdb870..9405893 100644 --- a/lib/widgets/post/post_item.dart +++ b/lib/widgets/post/post_item.dart @@ -720,32 +720,35 @@ class _PostTruncatedHint extends StatelessWidget { @override Widget build(BuildContext context) { - return Row( - children: [ - if (data.body['content_length'] != null) - Row( - children: [ - const Icon(Symbols.timer, size: 20), - const Gap(4), - Text('postReadEstimate').tr(args: [ - '${Duration( - seconds: (data.body['content_length'] as num).toDouble() * 60 ~/ kHumanReadSpeed, - ).inSeconds}s', - ]), - ], - ).padding(right: 8), - if (data.body['content_length'] != null) - Row( - children: [ - const Icon(Symbols.height, size: 20), - const Gap(4), - Text( - 'postTotalLength'.plural(data.body['content_length']), - ) - ], - ), - ], - ).opacity(0.75); + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + if (data.body['content_length'] != null) + Row( + children: [ + const Icon(Symbols.timer, size: 20), + const Gap(4), + Text('postReadEstimate').tr(args: [ + '${Duration( + seconds: (data.body['content_length'] as num).toDouble() * 60 ~/ kHumanReadSpeed, + ).inSeconds}s', + ]), + ], + ).padding(right: 8), + if (data.body['content_length'] != null) + Row( + children: [ + const Icon(Symbols.height, size: 20), + const Gap(4), + Text( + 'postTotalLength'.plural(data.body['content_length']), + ) + ], + ), + ], + ).opacity(0.75), + ); } }