💄 Optimized notification list
This commit is contained in:
		| @@ -487,5 +487,6 @@ | |||||||
|   "shareImageFooter": "Only on the Solar Network", |   "shareImageFooter": "Only on the Solar Network", | ||||||
|   "fileSavedAt": "File saved at @path", |   "fileSavedAt": "File saved at @path", | ||||||
|   "showIp": "Show IP Address", |   "showIp": "Show IP Address", | ||||||
|   "shotOn": "Shot on @device" |   "shotOn": "Shot on @device", | ||||||
|  |   "unread": "Unread" | ||||||
| } | } | ||||||
|   | |||||||
| @@ -483,5 +483,6 @@ | |||||||
|   "shareImageFooter": "上 Solar Network 看更多有趣帖子", |   "shareImageFooter": "上 Solar Network 看更多有趣帖子", | ||||||
|   "fileSavedAt": "文件保存于 @path", |   "fileSavedAt": "文件保存于 @path", | ||||||
|   "showIp": "显示 IP 地址", |   "showIp": "显示 IP 地址", | ||||||
|   "shotOn": "由 @device 拍摄" |   "shotOn": "由 @device 拍摄", | ||||||
|  |   "unread": "未读" | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,6 +5,9 @@ part 'notification.g.dart'; | |||||||
|  |  | ||||||
| const Map<String, IconData> NotificationTopicIcons = { | const Map<String, IconData> NotificationTopicIcons = { | ||||||
|   'passport.security.alert': Icons.gpp_maybe, |   'passport.security.alert': Icons.gpp_maybe, | ||||||
|  |   'interactive.subscription': Icons.subscriptions, | ||||||
|  |   'interactive.feedback': Icons.add_reaction, | ||||||
|  |   'messaging.callStart': Icons.call_received, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @JsonSerializable() | @JsonSerializable() | ||||||
|   | |||||||
| @@ -55,7 +55,11 @@ class NotificationProvider extends GetxController { | |||||||
|       await client.put('/notifications/read', {'messages': markList}); |       await client.put('/notifications/read', {'messages': markList}); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     nty.notifications.clear(); |     nty.notifications.value = nty.notifications.map((x) { | ||||||
|  |       x.readAt = DateTime.now(); | ||||||
|  |       return x; | ||||||
|  |     }).toList(); | ||||||
|  |     nty.notifications.refresh(); | ||||||
|  |  | ||||||
|     isBusy.value = false; |     isBusy.value = false; | ||||||
|   } |   } | ||||||
| @@ -79,7 +83,8 @@ class NotificationProvider extends GetxController { | |||||||
|  |  | ||||||
|     await client.put('/notifications/read/${element.id}', {}); |     await client.put('/notifications/read/${element.id}', {}); | ||||||
|  |  | ||||||
|     nty.notifications.removeAt(index); |     nty.notifications[0].readAt = DateTime.now(); | ||||||
|  |     nty.notifications.refresh(); | ||||||
|  |  | ||||||
|     isBusy.value = false; |     isBusy.value = false; | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import 'package:solian/models/notification.dart'; | |||||||
| import 'package:solian/providers/notifications.dart'; | import 'package:solian/providers/notifications.dart'; | ||||||
| import 'package:solian/widgets/loading_indicator.dart'; | import 'package:solian/widgets/loading_indicator.dart'; | ||||||
| import 'package:solian/widgets/markdown_text_content.dart'; | import 'package:solian/widgets/markdown_text_content.dart'; | ||||||
|  | import 'package:solian/widgets/relative_date.dart'; | ||||||
| import 'package:uuid/uuid.dart'; | import 'package:uuid/uuid.dart'; | ||||||
|  |  | ||||||
| class NotificationScreen extends StatefulWidget { | class NotificationScreen extends StatefulWidget { | ||||||
| @@ -107,12 +108,26 @@ class _NotificationScreenState extends State<NotificationScreen> { | |||||||
|                                 crossAxisAlignment: CrossAxisAlignment.start, |                                 crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                                 children: [ |                                 children: [ | ||||||
|                                   Icon(NotificationTopicIcons[element.topic]), |                                   Icon(NotificationTopicIcons[element.topic]), | ||||||
|                                   const Gap(12), |                                   const Gap(16), | ||||||
|                                   Expanded( |                                   Expanded( | ||||||
|                                     child: Column( |                                     child: Column( | ||||||
|                                       crossAxisAlignment: |                                       crossAxisAlignment: | ||||||
|                                           CrossAxisAlignment.start, |                                           CrossAxisAlignment.start, | ||||||
|                                       children: [ |                                       children: [ | ||||||
|  |                                         if (element.readAt == null) | ||||||
|  |                                           Badge( | ||||||
|  |                                             label: Row( | ||||||
|  |                                               children: [ | ||||||
|  |                                                 const Icon( | ||||||
|  |                                                   Icons.new_releases_outlined, | ||||||
|  |                                                   color: Colors.white, | ||||||
|  |                                                   size: 12, | ||||||
|  |                                                 ), | ||||||
|  |                                                 const Gap(4), | ||||||
|  |                                                 Text('unread'.tr), | ||||||
|  |                                               ], | ||||||
|  |                                             ), | ||||||
|  |                                           ).paddingOnly(bottom: 4), | ||||||
|                                         Text( |                                         Text( | ||||||
|                                           element.title, |                                           element.title, | ||||||
|                                           style: Theme.of(context) |                                           style: Theme.of(context) | ||||||
| @@ -126,7 +141,8 @@ class _NotificationScreenState extends State<NotificationScreen> { | |||||||
|                                                 .textTheme |                                                 .textTheme | ||||||
|                                                 .titleSmall, |                                                 .titleSmall, | ||||||
|                                           ), |                                           ), | ||||||
|                                         const Gap(4), |                                         if (element.subtitle != null) | ||||||
|  |                                           const Gap(4), | ||||||
|                                         MarkdownTextContent( |                                         MarkdownTextContent( | ||||||
|                                           content: element.body, |                                           content: element.body, | ||||||
|                                           isAutoWarp: true, |                                           isAutoWarp: true, | ||||||
| @@ -134,6 +150,29 @@ class _NotificationScreenState extends State<NotificationScreen> { | |||||||
|                                           parentId: |                                           parentId: | ||||||
|                                               'notification-${element.id}', |                                               'notification-${element.id}', | ||||||
|                                         ), |                                         ), | ||||||
|  |                                         const Gap(8), | ||||||
|  |                                         Opacity( | ||||||
|  |                                           opacity: 0.75, | ||||||
|  |                                           child: Row( | ||||||
|  |                                             children: [ | ||||||
|  |                                               RelativeDate( | ||||||
|  |                                                 element.createdAt, | ||||||
|  |                                                 style: TextStyle(fontSize: 12), | ||||||
|  |                                               ), | ||||||
|  |                                               const Gap(4), | ||||||
|  |                                               Text( | ||||||
|  |                                                 '·', | ||||||
|  |                                                 style: TextStyle(fontSize: 12), | ||||||
|  |                                               ), | ||||||
|  |                                               const Gap(4), | ||||||
|  |                                               RelativeDate( | ||||||
|  |                                                 element.createdAt, | ||||||
|  |                                                 style: TextStyle(fontSize: 12), | ||||||
|  |                                                 isFull: true, | ||||||
|  |                                               ), | ||||||
|  |                                             ], | ||||||
|  |                                           ), | ||||||
|  |                                         ), | ||||||
|                                       ], |                                       ], | ||||||
|                                     ), |                                     ), | ||||||
|                                   ), |                                   ), | ||||||
|   | |||||||
| @@ -4,20 +4,25 @@ import 'package:timeago/timeago.dart'; | |||||||
|  |  | ||||||
| class RelativeDate extends StatelessWidget { | class RelativeDate extends StatelessWidget { | ||||||
|   final DateTime date; |   final DateTime date; | ||||||
|  |   final TextStyle? style; | ||||||
|   final bool isFull; |   final bool isFull; | ||||||
|  |  | ||||||
|   const RelativeDate(this.date, {super.key, this.isFull = false}); |   const RelativeDate(this.date, {super.key, this.style, this.isFull = false}); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     if (isFull) { |     if (isFull) { | ||||||
|       return Text(DateFormat('y/M/d HH:mm').format(date)); |       return Text( | ||||||
|  |         DateFormat('y/M/d HH:mm').format(date), | ||||||
|  |         style: style, | ||||||
|  |       ); | ||||||
|     } |     } | ||||||
|     return Text( |     return Text( | ||||||
|       format( |       format( | ||||||
|         date, |         date, | ||||||
|         locale: 'en_short', |         locale: 'en_short', | ||||||
|       ), |       ), | ||||||
|  |       style: style, | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user