✨ Notification preferences
This commit is contained in:
		| @@ -416,5 +416,11 @@ | ||||
|   "holdToSeeDetail": "Long press / Mouse hover to see detail", | ||||
|   "subscribe": "Subscribe", | ||||
|   "subscribed": "Subscribed", | ||||
|   "unsubscribe": "Unsubscribe" | ||||
|   "unsubscribe": "Unsubscribe", | ||||
|   "preferences": "Preferences", | ||||
|   "notificationPreferences": "Notification preferences", | ||||
|   "notificationTopicPostFeedback": "Post feedbacks", | ||||
|   "notificationTopicPostSubscription": "Post subscriptions", | ||||
|   "preferencesApplied": "Preferences has been applied.", | ||||
|   "save": "Save" | ||||
| } | ||||
|   | ||||
| @@ -417,5 +417,11 @@ | ||||
|   "holdToSeeDetail": "长按 / 鼠标悬浮来查看详情", | ||||
|   "subscribe": "订阅", | ||||
|   "subscribed": "已订阅", | ||||
|   "unsubscribe": "取消订阅" | ||||
|   "unsubscribe": "取消订阅", | ||||
|   "preferences": "偏好设置", | ||||
|   "notificationPreferences": "通知偏好设置", | ||||
|   "notificationTopicPostFeedback": "帖子反馈", | ||||
|   "notificationTopicPostSubscription": "订阅源", | ||||
|   "preferencesApplied": "偏好设置已应用", | ||||
|   "save": "保存" | ||||
| } | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import 'package:solian/models/realm.dart'; | ||||
| import 'package:solian/screens/about.dart'; | ||||
| import 'package:solian/screens/account.dart'; | ||||
| import 'package:solian/screens/account/friend.dart'; | ||||
| import 'package:solian/screens/account/preferences/notifications.dart'; | ||||
| import 'package:solian/screens/account/profile_edit.dart'; | ||||
| import 'package:solian/screens/account/profile_page.dart'; | ||||
| import 'package:solian/screens/auth/signin.dart'; | ||||
| @@ -245,6 +246,14 @@ abstract class AppRouter { | ||||
|           child: const PersonalizeScreen(), | ||||
|         ), | ||||
|       ), | ||||
|       GoRoute( | ||||
|         path: '/account/preferences/notifications', | ||||
|         name: 'notificationPreferences', | ||||
|         builder: (context, state) => TitleShell( | ||||
|           state: state, | ||||
|           child: const NotificationPreferencesScreen(), | ||||
|         ), | ||||
|       ), | ||||
|       GoRoute( | ||||
|         path: '/account/view/:name', | ||||
|         name: 'accountProfilePage', | ||||
|   | ||||
| @@ -131,6 +131,15 @@ class _AccountScreenState extends State<AccountScreen> { | ||||
|                     AppRouter.instance.pushNamed('settings'); | ||||
|                   }, | ||||
|                 ), | ||||
|                 if (auth.isAuthorized.value) | ||||
|                   ListTile( | ||||
|                     contentPadding: const EdgeInsets.symmetric(horizontal: 34), | ||||
|                     leading: const Icon(Icons.edit_notifications), | ||||
|                     title: Text('notificationPreferences'.tr), | ||||
|                     onTap: () { | ||||
|                       AppRouter.instance.pushNamed('notificationPreferences'); | ||||
|                     }, | ||||
|                   ), | ||||
|                 const Divider(thickness: 0.3, height: 1) | ||||
|                     .paddingSymmetric(vertical: 4), | ||||
|                 ListTile( | ||||
|   | ||||
							
								
								
									
										118
									
								
								lib/screens/account/preferences/notifications.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								lib/screens/account/preferences/notifications.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_animate/flutter_animate.dart'; | ||||
| import 'package:get/get.dart'; | ||||
| import 'package:get/get_connect/http/src/exceptions/exceptions.dart'; | ||||
| import 'package:google_fonts/google_fonts.dart'; | ||||
| import 'package:solian/exceptions/request.dart'; | ||||
| import 'package:solian/exts.dart'; | ||||
| import 'package:solian/providers/auth.dart'; | ||||
|  | ||||
| class NotificationPreferencesScreen extends StatefulWidget { | ||||
|   const NotificationPreferencesScreen({super.key}); | ||||
|  | ||||
|   @override | ||||
|   State<NotificationPreferencesScreen> createState() => | ||||
|       _NotificationPreferencesScreenState(); | ||||
| } | ||||
|  | ||||
| class _NotificationPreferencesScreenState | ||||
|     extends State<NotificationPreferencesScreen> { | ||||
|   bool _isBusy = true; | ||||
|  | ||||
|   Map<String, bool> _config = {}; | ||||
|  | ||||
|   final Map<String, String> _topicMap = { | ||||
|     'interactive.feedback': 'notificationTopicPostFeedback'.tr, | ||||
|     'interactive.subscription': 'notificationTopicPostSubscription'.tr, | ||||
|   }; | ||||
|  | ||||
|   Future<void> _getPreferences() async { | ||||
|     setState(() => _isBusy = true); | ||||
|  | ||||
|     final auth = Get.find<AuthProvider>(); | ||||
|     if (!auth.isAuthorized.value) throw UnauthorizedException(); | ||||
|  | ||||
|     final client = await auth.configureClient('id'); | ||||
|     final resp = await client.get('/preferences/notifications'); | ||||
|     if (resp.statusCode != 200 && resp.statusCode != 404) { | ||||
|       context.showErrorDialog(RequestException(resp)); | ||||
|     } | ||||
|  | ||||
|     if (resp.statusCode == 200) { | ||||
|       _config = resp.body['config'] | ||||
|           .map((k, v) => MapEntry(k, v as bool)) | ||||
|           .cast<String, bool>(); | ||||
|     } | ||||
|  | ||||
|     setState(() => _isBusy = false); | ||||
|   } | ||||
|  | ||||
|   Future<void> _savePreferences() async { | ||||
|     setState(() => _isBusy = true); | ||||
|  | ||||
|     final auth = Get.find<AuthProvider>(); | ||||
|     if (!auth.isAuthorized.value) throw UnauthorizedException(); | ||||
|  | ||||
|     final client = await auth.configureClient('id'); | ||||
|     final resp = await client.put('/preferences/notifications', { | ||||
|       'config': _config, | ||||
|     }); | ||||
|     if (resp.statusCode != 200) { | ||||
|       context.showErrorDialog(RequestException(resp)); | ||||
|     } | ||||
|  | ||||
|     context.showSnackbar('preferencesApplied'.tr); | ||||
|  | ||||
|     setState(() => _isBusy = false); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
|     _getPreferences(); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Material( | ||||
|       color: Theme.of(context).colorScheme.surface, | ||||
|       child: Column( | ||||
|         children: [ | ||||
|           if (_isBusy) const LinearProgressIndicator().animate().scaleX(), | ||||
|           ListTile( | ||||
|             tileColor: Theme.of(context).colorScheme.surfaceContainer, | ||||
|             contentPadding: const EdgeInsets.symmetric(horizontal: 24), | ||||
|             leading: const Icon(Icons.save), | ||||
|             title: Text('save'.tr), | ||||
|             enabled: !_isBusy, | ||||
|             onTap: () { | ||||
|               _savePreferences(); | ||||
|             }, | ||||
|           ), | ||||
|           Expanded( | ||||
|             child: ListView.builder( | ||||
|               itemCount: _topicMap.length, | ||||
|               itemBuilder: (context, index) { | ||||
|                 final element = _topicMap.entries.elementAt(index); | ||||
|                 return CheckboxListTile( | ||||
|                   title: Text(element.value), | ||||
|                   subtitle: Text( | ||||
|                     element.key, | ||||
|                     style: GoogleFonts.robotoMono(fontSize: 12), | ||||
|                   ), | ||||
|                   value: _config[element.key] ?? true, | ||||
|                   contentPadding: const EdgeInsets.symmetric(horizontal: 24), | ||||
|                   onChanged: (value) { | ||||
|                     setState(() { | ||||
|                       _config[element.key] = value ?? false; | ||||
|                     }); | ||||
|                   }, | ||||
|                 ); | ||||
|               }, | ||||
|             ), | ||||
|           ), | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @@ -400,7 +400,7 @@ class _AccountProfilePageState extends State<AccountProfilePage> { | ||||
|                             child: AttachmentListEntry( | ||||
|                               item: item, | ||||
|                               isDense: true, | ||||
|                               parentId: 'album', | ||||
|                               parentId: 'album-$index', | ||||
|                               showMature: _showMature, | ||||
|                               onReveal: (value) { | ||||
|                                 setState(() => _showMature = value); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user