✨ Complete the realm system
This commit is contained in:
		| @@ -87,6 +87,8 @@ | ||||
|   "realmDescriptionLabel": "Realm Description", | ||||
|   "realmPublicLabel": "It's public", | ||||
|   "realmCommunityLabel": "It's community realm", | ||||
|   "realmMember": "Member", | ||||
|   "realmManage": "Realm Manage", | ||||
|   "chatNew": "New Chat", | ||||
|   "chatNewCreate": "Create a channel", | ||||
|   "chatNewJoin": "Join a exists channel", | ||||
|   | ||||
| @@ -21,8 +21,10 @@ import 'package:solian/screens/posts/moment_editor.dart'; | ||||
| import 'package:solian/screens/posts/screen.dart'; | ||||
| import 'package:solian/screens/auth/signin.dart'; | ||||
| import 'package:solian/screens/realms/realm.dart'; | ||||
| import 'package:solian/screens/realms/realm_manage.dart'; | ||||
| import 'package:solian/screens/realms/realm_editor.dart'; | ||||
| import 'package:solian/screens/realms/realm_list.dart'; | ||||
| import 'package:solian/screens/realms/realm_member.dart'; | ||||
| import 'package:solian/screens/users/userinfo.dart'; | ||||
| import 'package:solian/utils/theme.dart'; | ||||
| import 'package:solian/widgets/empty.dart'; | ||||
| @@ -103,6 +105,16 @@ abstract class SolianRouter { | ||||
|               realm: state.uri.queryParameters['realm'], | ||||
|             ), | ||||
|           ), | ||||
|           GoRoute( | ||||
|             path: '/realms/:realm/manage', | ||||
|             name: 'realms.manage', | ||||
|             builder: (context, state) => RealmManageScreen(realm: state.extra as Realm), | ||||
|           ), | ||||
|           GoRoute( | ||||
|             path: '/realms/:realm/member', | ||||
|             name: 'realms.member', | ||||
|             builder: (context, state) => RealmMemberScreen(realm: state.extra as Realm), | ||||
|           ), | ||||
|           GoRoute( | ||||
|             path: '/realms/:realm/posts/:dataset/:alias', | ||||
|             name: 'realms.posts.details', | ||||
|   | ||||
| @@ -6,7 +6,6 @@ import 'package:solian/providers/realm.dart'; | ||||
| import 'package:solian/router.dart'; | ||||
| import 'package:solian/screens/chat/chat_list.dart'; | ||||
| import 'package:solian/screens/explore.dart'; | ||||
| import 'package:solian/screens/realms/realm_member.dart'; | ||||
| import 'package:solian/utils/theme.dart'; | ||||
| import 'package:solian/widgets/scaffold.dart'; | ||||
|  | ||||
| @@ -82,7 +81,7 @@ class _RealmWidgetState extends State<RealmWidget> { | ||||
|     } | ||||
|  | ||||
|     return DefaultTabController( | ||||
|       length: 3, | ||||
|       length: 2, | ||||
|       child: Column( | ||||
|         children: [ | ||||
|           TabBar( | ||||
| @@ -90,7 +89,6 @@ class _RealmWidgetState extends State<RealmWidget> { | ||||
|             tabs: const [ | ||||
|               Tab(icon: Icon(Icons.newspaper)), | ||||
|               Tab(icon: Icon(Icons.message)), | ||||
|               Tab(icon: Icon(Icons.supervisor_account)) | ||||
|             ], | ||||
|           ), | ||||
|           Expanded( | ||||
| @@ -98,11 +96,6 @@ class _RealmWidgetState extends State<RealmWidget> { | ||||
|               children: [ | ||||
|                 ExplorePostWidget(realm: widget.alias), | ||||
|                 ChatListWidget(realm: widget.alias), | ||||
|                 _realm.focusRealm != null | ||||
|                     ? RealmMemberWidget(realm: _realm.focusRealm!) | ||||
|                     : const Center( | ||||
|                         child: CircularProgressIndicator(), | ||||
|                       ), | ||||
|               ], | ||||
|             ), | ||||
|           ) | ||||
| @@ -127,8 +120,9 @@ class RealmManageAction extends StatelessWidget { | ||||
|     return IconButton( | ||||
|       onPressed: () async { | ||||
|         final did = await SolianRouter.router.pushNamed( | ||||
|           'realms.editor', | ||||
|           'realms.manage', | ||||
|           extra: realm, | ||||
|           pathParameters: {'realm': realm.alias}, | ||||
|         ); | ||||
|         if (did == true) onUpdate(); | ||||
|       }, | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import 'package:solian/models/realm.dart'; | ||||
| import 'package:solian/providers/auth.dart'; | ||||
| import 'package:solian/router.dart'; | ||||
| import 'package:solian/utils/service_url.dart'; | ||||
| import 'package:solian/utils/theme.dart'; | ||||
| import 'package:solian/widgets/exts.dart'; | ||||
| import 'package:solian/widgets/scaffold.dart'; | ||||
| import 'package:uuid/uuid.dart'; | ||||
| @@ -117,6 +118,7 @@ class _RealmEditorScreenState extends State<RealmEditorScreen> { | ||||
|           child: Text(AppLocalizations.of(context)!.apply.toUpperCase()), | ||||
|         ), | ||||
|       ], | ||||
|       fixedAppBarColor: SolianTheme.isLargeScreen(context), | ||||
|       child: Column( | ||||
|         children: [ | ||||
|           _isSubmitting ? const LinearProgressIndicator().animate().scaleX() : Container(), | ||||
|   | ||||
							
								
								
									
										119
									
								
								lib/screens/realms/realm_manage.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								lib/screens/realms/realm_manage.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:solian/models/realm.dart'; | ||||
| import 'package:solian/providers/auth.dart'; | ||||
| import 'package:solian/router.dart'; | ||||
| import 'package:solian/widgets/realms/realm_deletion.dart'; | ||||
| import 'package:solian/widgets/scaffold.dart'; | ||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||
|  | ||||
| class RealmManageScreen extends StatefulWidget { | ||||
|   final Realm realm; | ||||
|  | ||||
|   const RealmManageScreen({super.key, required this.realm}); | ||||
|  | ||||
|   @override | ||||
|   State<RealmManageScreen> createState() => _RealmManageScreenState(); | ||||
| } | ||||
|  | ||||
| class _RealmManageScreenState extends State<RealmManageScreen> { | ||||
|   bool _isOwned = false; | ||||
|  | ||||
|   void promptLeaveChannel() async { | ||||
|     final did = await showDialog( | ||||
|       context: context, | ||||
|       builder: (context) => RealmDeletion( | ||||
|         realm: widget.realm, | ||||
|         isOwned: _isOwned, | ||||
|       ), | ||||
|     ); | ||||
|     if (did == true && SolianRouter.router.canPop()) { | ||||
|       SolianRouter.router.pop('disposed'); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
|  | ||||
|     Future.delayed(Duration.zero, () async { | ||||
|       final auth = context.read<AuthProvider>(); | ||||
|       final prof = await auth.getProfiles(); | ||||
|  | ||||
|       setState(() { | ||||
|         _isOwned = prof['id'] == widget.realm.accountId; | ||||
|       }); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     final authorizedItems = [ | ||||
|       ListTile( | ||||
|         leading: const Icon(Icons.settings), | ||||
|         title: Text(AppLocalizations.of(context)!.settings), | ||||
|         onTap: () async { | ||||
|           SolianRouter.router.pushNamed('realms.editor', extra: widget.realm).then((did) { | ||||
|             if (did == true) { | ||||
|               if (SolianRouter.router.canPop()) SolianRouter.router.pop('refresh'); | ||||
|             } | ||||
|           }); | ||||
|         }, | ||||
|       ), | ||||
|     ]; | ||||
|  | ||||
|     return IndentScaffold( | ||||
|       title: AppLocalizations.of(context)!.realmManage, | ||||
|       hideDrawer: true, | ||||
|       noSafeArea: true, | ||||
|       child: Column( | ||||
|         children: [ | ||||
|           Padding( | ||||
|             padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), | ||||
|             child: Row( | ||||
|               children: [ | ||||
|                 const CircleAvatar( | ||||
|                   radius: 24, | ||||
|                   backgroundColor: Colors.teal, | ||||
|                   child: Icon(Icons.tag, color: Colors.white), | ||||
|                 ), | ||||
|                 const SizedBox(width: 16), | ||||
|                 Expanded( | ||||
|                   child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ | ||||
|                     Text(widget.realm.name, style: Theme.of(context).textTheme.bodyLarge), | ||||
|                     Text(widget.realm.description, style: Theme.of(context).textTheme.bodySmall), | ||||
|                   ]), | ||||
|                 ) | ||||
|               ], | ||||
|             ), | ||||
|           ), | ||||
|           const Divider(thickness: 0.3), | ||||
|           Expanded( | ||||
|             child: ListView( | ||||
|               children: [ | ||||
|                 ListTile( | ||||
|                   leading: const Icon(Icons.supervisor_account), | ||||
|                   title: Text(AppLocalizations.of(context)!.chatMember), | ||||
|                   onTap: () { | ||||
|                     SolianRouter.router.pushNamed( | ||||
|                       'realms.member', | ||||
|                       extra: widget.realm, | ||||
|                       pathParameters: {'realm': widget.realm.alias}, | ||||
|                     ); | ||||
|                   }, | ||||
|                 ), | ||||
|                 ...(_isOwned ? authorizedItems : List.empty()), | ||||
|                 const Divider(thickness: 0.3), | ||||
|                 ListTile( | ||||
|                   leading: _isOwned ? const Icon(Icons.delete) : const Icon(Icons.exit_to_app), | ||||
|                   title: Text(_isOwned ? AppLocalizations.of(context)!.delete : AppLocalizations.of(context)!.exit), | ||||
|                   onTap: () => promptLeaveChannel(), | ||||
|                 ), | ||||
|               ], | ||||
|             ), | ||||
|           ), | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @@ -7,20 +7,23 @@ import 'package:solian/models/account.dart'; | ||||
| import 'package:solian/models/realm.dart'; | ||||
| import 'package:solian/providers/auth.dart'; | ||||
| import 'package:solian/utils/service_url.dart'; | ||||
| import 'package:solian/utils/theme.dart'; | ||||
| import 'package:solian/widgets/account/account_avatar.dart'; | ||||
| import 'package:solian/widgets/account/friend_picker.dart'; | ||||
| import 'package:solian/widgets/exts.dart'; | ||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||
| import 'package:solian/widgets/scaffold.dart'; | ||||
|  | ||||
| class RealmMemberWidget extends StatefulWidget { | ||||
| class RealmMemberScreen extends StatefulWidget { | ||||
|   final Realm realm; | ||||
|  | ||||
|   const RealmMemberWidget({super.key, required this.realm}); | ||||
|   const RealmMemberScreen({super.key, required this.realm}); | ||||
|  | ||||
|   @override | ||||
|   State<RealmMemberWidget> createState() => _RealmMemberWidgetState(); | ||||
|   State<RealmMemberScreen> createState() => _RealmMemberScreenState(); | ||||
| } | ||||
|  | ||||
| class _RealmMemberWidgetState extends State<RealmMemberWidget> { | ||||
| class _RealmMemberScreenState extends State<RealmMemberScreen> { | ||||
|   bool _isSubmitting = false; | ||||
|  | ||||
|   List<RealmMember> _members = List.empty(); | ||||
| @@ -136,12 +139,18 @@ class _RealmMemberWidgetState extends State<RealmMemberWidget> { | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Scaffold( | ||||
|       floatingActionButton: FloatingActionButton( | ||||
|         child: const Icon(Icons.add), | ||||
|         onPressed: () => promptAddMember(), | ||||
|       ), | ||||
|       body: RefreshIndicator( | ||||
|     return IndentScaffold( | ||||
|       title: AppLocalizations.of(context)!.realmMember, | ||||
|       fixedAppBarColor: SolianTheme.isLargeScreen(context), | ||||
|       noSafeArea: true, | ||||
|       hideDrawer: true, | ||||
|       appBarActions: [ | ||||
|         IconButton( | ||||
|           icon: const Icon(Icons.add), | ||||
|           onPressed: () => promptAddMember(), | ||||
|         ), | ||||
|       ], | ||||
|       child: RefreshIndicator( | ||||
|         onRefresh: () => fetchMemberships(), | ||||
|         child: CustomScrollView( | ||||
|           slivers: [ | ||||
|   | ||||
							
								
								
									
										101
									
								
								lib/widgets/realms/realm_deletion.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								lib/widgets/realms/realm_deletion.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| import 'dart:convert'; | ||||
|  | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||
| import 'package:solian/models/realm.dart'; | ||||
| import 'package:solian/providers/auth.dart'; | ||||
| import 'package:solian/utils/service_url.dart'; | ||||
| import 'package:solian/widgets/exts.dart'; | ||||
|  | ||||
| class RealmDeletion extends StatefulWidget { | ||||
|   final Realm realm; | ||||
|   final bool isOwned; | ||||
|  | ||||
|   const RealmDeletion({ | ||||
|     super.key, | ||||
|     required this.realm, | ||||
|     required this.isOwned, | ||||
|   }); | ||||
|  | ||||
|   @override | ||||
|   State<RealmDeletion> createState() => _RealmDeletionState(); | ||||
| } | ||||
|  | ||||
| class _RealmDeletionState extends State<RealmDeletion> { | ||||
|   bool _isSubmitting = false; | ||||
|  | ||||
|   Future<void> deleteChannel() async { | ||||
|     setState(() => _isSubmitting = true); | ||||
|  | ||||
|     final auth = context.read<AuthProvider>(); | ||||
|     if (!await auth.isAuthorized()) { | ||||
|       setState(() => _isSubmitting = false); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     var res = await auth.client!.delete( | ||||
|       getRequestUri('passport', '/api/realms/${widget.realm.alias}'), | ||||
|     ); | ||||
|     if (res.statusCode != 200) { | ||||
|       var message = utf8.decode(res.bodyBytes); | ||||
|       context.showErrorDialog(message); | ||||
|     } else if (Navigator.canPop(context)) { | ||||
|       Navigator.pop(context, true); | ||||
|     } | ||||
|  | ||||
|     setState(() => _isSubmitting = false); | ||||
|   } | ||||
|  | ||||
|   Future<void> leaveChannel() async { | ||||
|     setState(() => _isSubmitting = true); | ||||
|  | ||||
|     final auth = context.read<AuthProvider>(); | ||||
|     if (!await auth.isAuthorized()) { | ||||
|       setState(() => _isSubmitting = false); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     var res = await auth.client!.delete( | ||||
|       getRequestUri('passport', '/api/realms/${widget.realm.alias}/members/me'), | ||||
|     ); | ||||
|     if (res.statusCode != 200) { | ||||
|       var message = utf8.decode(res.bodyBytes); | ||||
|       context.showErrorDialog(message); | ||||
|     } else if (Navigator.canPop(context)) { | ||||
|       Navigator.pop(context, true); | ||||
|     } | ||||
|  | ||||
|     setState(() => _isSubmitting = false); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     final content = widget.isOwned | ||||
|         ? AppLocalizations.of(context)!.chatChannelDeleteConfirm | ||||
|         : AppLocalizations.of(context)!.chatChannelLeaveConfirm; | ||||
|  | ||||
|     return AlertDialog( | ||||
|       title: Text(AppLocalizations.of(context)!.confirmation), | ||||
|       content: Text(content), | ||||
|       actions: <Widget>[ | ||||
|         TextButton( | ||||
|           onPressed: _isSubmitting ? null : () => Navigator.pop(context), | ||||
|           child: Text(AppLocalizations.of(context)!.confirmCancel), | ||||
|         ), | ||||
|         TextButton( | ||||
|           onPressed: _isSubmitting | ||||
|               ? null | ||||
|               : () { | ||||
|                   if (widget.isOwned) { | ||||
|                     deleteChannel(); | ||||
|                   } else { | ||||
|                     leaveChannel(); | ||||
|                   } | ||||
|                 }, | ||||
|           child: Text(AppLocalizations.of(context)!.confirmOkay), | ||||
|         ), | ||||
|       ], | ||||
|     ); | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user