import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:outbag_app/backend/permissions.dart'; import 'package:outbag_app/backend/request.dart'; import 'package:outbag_app/backend/room.dart'; import 'package:outbag_app/backend/user.dart'; import 'package:outbag_app/tools/fetch_wrapper.dart'; import 'package:provider/provider.dart'; class ManageRoomMembersPage extends StatefulWidget { final String server; final String tag; const ManageRoomMembersPage(this.server, this.tag, {super.key}); @override State createState() => _ManageRoomMembersPageState(); } class _ManageRoomMembersPageState extends State { List list = []; RoomInfo? info; void fetchUserInfo() { final router = GoRouter.of(context); final sm = ScaffoldMessenger.of(context); final user = context.read(); doNetworkRequest( sm, req: () => postWithCreadentials( path: 'getRoomInfo', credentials: user, target: user.server, body: {'room': widget.tag, 'server': widget.server}), onAnyErr: () { // user should not be here // close screen router.pushReplacementNamed('home'); return false; }, onOK: (body) async { final info = RoomInfo.fromJSON(body['data']); setState(() { this.info = info; }); return true; }, ); } void fetchMembers() { final router = GoRouter.of(context); final sm = ScaffoldMessenger.of(context); final user = context.read(); doNetworkRequest(sm, req: () => postWithCreadentials( credentials: user, target: user.server, path: 'getRoomMembers', body: {'room': widget.tag, 'server': widget.server}), onAnyErr: () { // user should not be here // close screen router.pushReplacementNamed('home'); return false; }, onOK: (body) { final List list = body['data'].map((json) { return RoomMember.fromJSON(json); }).toList(); setState(() { this.list = list; }); }); } @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { fetchUserInfo(); fetchMembers(); }); } @override Widget build(BuildContext context) { final textTheme = Theme.of(context) .textTheme .apply(displayColor: Theme.of(context).colorScheme.onSurface); return Scaffold( appBar: AppBar( title: Text('Room Members (${list.length})'), leading: IconButton( onPressed: () { // go back Navigator.of(context).pop(); }, icon: const Icon(Icons.arrow_back), tooltip: "Go back", ), //actions: [ // // NOTE: Maybe add a search icon // // and general search functionality here //], ), body: ListView.builder( itemBuilder: (BuildContext context, int index) { final item = list[index]; String role = "Member"; if (info != null && (info?.owner)! == item.id && widget.server == item.serverTag) { role = "Owner"; } else if (item.isAdmin) { role = "Admin"; } bool enable = true; // perform permission check if (info == null || !((info?.isAdmin)! || (info?.isOwner)! || ((info?.permissions)! & oB("1100000") != 0))) { // NOTE: do not show error message // user should assume, // that it wasn't even possible // to click on ListTile enable = false; } else if (info != null && item.id == info?.owner && widget.server == item.serverTag) { // cannot kick admin enable = false; } return ListTile( title: Text(item.humanReadableName), subtitle: Text(role), leading: const Icon(Icons.person), onTap: !enable ? null : () { showModalBottomSheet( context: context, builder: (context) => BottomSheet( onClosing: () {}, builder: (context) => Column( children: [ Padding( padding: const EdgeInsets.all(8), child: Text(item.humanReadableName, style: textTheme.displaySmall)), Padding( padding: const EdgeInsets.all(8), child: Column( children: [ ...((info?.isAdmin)! || (info?.isOwner)! || ((info?.permissions)! & RoomPermission .changeAdmin != 0)) ? [ ListTile( leading: const Icon( Icons.supervisor_account), title: Text(item.isAdmin ? 'Remove admin privileges' : 'Make Admin'), subtitle: Text(item.isAdmin ? 'Revokes admin privileges from the user' : 'Grants the user the permission to do everything'), onTap: () { // make user admin showDialog( context: context, builder: (context) => AlertDialog( icon: const Icon( Icons .supervisor_account), title: Text(item .isAdmin ? 'Remove admin privileges' : 'Make Admin'), content: Text(item .isAdmin ? "Do you really want to remove ${item.humanReadableName}'s admin privileges" : 'Do you really want to make ${item.humanReadableName} admin?'), actions: [ TextButton( onPressed: () { // close popup // NOTE: cancel only closes the dialog // whilst OK closes both Navigator.of(context) .pop(); }, child: const Text( 'Cancel'), ), FilledButton( onPressed: () async { // send request final scaffMgr = ScaffoldMessenger.of(context); final nav = Navigator.of(context); final user = context.read(); doNetworkRequest( scaffMgr, req: () => postWithCreadentials(path: 'setAdminStatus', credentials: user, target: user.server, body: { 'room': widget.tag, 'roomServer': widget.server, 'server': item.serverTag, 'name': item.id, 'admin': !item.isAdmin }), onOK: (_) { fetchMembers(); }, after: () { // close popup nav.pop(); nav.pop(); }); }, child: const Text( 'OK'), ) ], )); }, ) ] : [], ...((info?.isAdmin)! || (info?.isOwner)! || ((info?.permissions)! & RoomPermission .manageMembers != 0)) ? [ ListTile( leading: const Icon( Icons.person_remove), title: const Text('Kick User'), subtitle: const Text( "Temporarrily remove user from server (they'll be able to join the room again)"), onTap: () { // remove user from room showDialog( context: context, builder: (context) => AlertDialog( icon: const Icon( Icons .person_remove), title: const Text( 'Kick User'), content: Text( 'Do you really want to kick ${item.humanReadableName}?'), actions: [ TextButton( onPressed: () { // close popup // NOTE: cancel only closes the dialog // whilst OK closes both Navigator.of(context) .pop(); }, child: const Text( 'Cancel'), ), FilledButton( onPressed: () async { // send request final scaffMgr = ScaffoldMessenger.of(context); final nav = Navigator.of(context); final user = context.read(); doNetworkRequest( scaffMgr, req: () => postWithCreadentials(path: 'kickMember', credentials: user, target: user.server, body: { 'room': widget.tag, 'roomServer': widget.server, 'name': item.id, 'server': item.serverTag }), onOK: (_) { fetchMembers(); }, after: () { // close popup nav.pop(); nav.pop(); }); }, child: const Text( 'Kick User'), ) ], )); }, ) ] : [], ], ), ), FilledButton( child: const Text('Close'), onPressed: () { Navigator.of(context).pop(); }, ) ], ), )); }, ); }, itemCount: list.length, ), ); } }