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'; import 'package:flutter_gen/gen_l10n/app_localizations.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(AppLocalizations.of(context)!.roomMembersTitle(list.length)), //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 = AppLocalizations.of(context)!.roleMember; if (info != null && (info?.owner)! == item.id && widget.server == item.serverTag) { role = AppLocalizations.of(context)!.roleOwner; } else if (item.isAdmin) { role = AppLocalizations.of(context)!.roleAdmin; } 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 ? AppLocalizations.of( context)! .removeAdminTitle : AppLocalizations.of( context)! .makeAdminTitle), subtitle: Text(item.isAdmin ? AppLocalizations.of( context)! .removeAdminSubtitle : AppLocalizations.of( context)! .makeAdminSubtitle), onTap: () { // make user admin showDialog( context: context, builder: (ctx) => AlertDialog( icon: const Icon( Icons .supervisor_account), title: Text(item.isAdmin ? AppLocalizations.of( context)! .removeAdminTitle : AppLocalizations.of( context)! .makeAdminTitle), content: Text(item .isAdmin ? AppLocalizations.of( context)! .removeAdminConfirm(item .humanReadableName) : AppLocalizations.of( context)! .makeAdminConfirm( item.humanReadableName)), actions: [ TextButton( onPressed: () { // close popup // NOTE: cancel only closes the dialog // whilst OK closes both Navigator.of(ctx) .pop(); }, child: Text( AppLocalizations.of(context)! .cancel), ), FilledButton( onPressed: () async { // send request final scaffMgr = ScaffoldMessenger.of(context); final nav = Navigator.of(ctx); final nav2 = 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(); // close bottom sheet nav2.pop(); }); }, child: Text( AppLocalizations.of(context)! .ok), ) ], )); }, ) ] : [], ...((info?.isAdmin)! || (info?.isOwner)! || ((info?.permissions)! & RoomPermission .manageMembers != 0)) ? [ ListTile( leading: const Icon( Icons.person_remove), title: Text( AppLocalizations.of( context)! .kickUserTitle), subtitle: Text( AppLocalizations.of( context)! .kickUserSubtitle), onTap: () { // remove user from room showDialog( context: context, builder: (ctx) => AlertDialog( icon: const Icon( Icons .person_remove), title: Text(AppLocalizations.of( context)! .kickUserTitle), content: Text(AppLocalizations.of( context)! .kichUserConfirm( item.humanReadableName)), actions: [ TextButton( onPressed: () { // close popup // NOTE: cancel only closes the dialog // whilst OK closes both Navigator.of(ctx) .pop(); }, child: Text( AppLocalizations.of(context)! .cancel), ), FilledButton( onPressed: () async { // send request final scaffMgr = ScaffoldMessenger.of(ctx); final nav = Navigator.of(ctx); final nav2 = 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(); // close bottom sheet nav2.pop(); }); }, child: Text( AppLocalizations.of(context)! .ok), ) ], )); }, ) ] : [], ], ), ), FilledButton( child: Text( AppLocalizations.of(context)!.close), onPressed: () { Navigator.of(context).pop(); }, ) ], ), )); }, ); }, itemCount: list.length, ), ); } }