actions-test/lib/screens/room/members.dart
Jakob Meier 6b98c696ea
Finishied room member screen
The screen allows every room member,
to view a list of other room members,
and their role (Owner, Admin or Member).

If the user is allowed
(Owner, Admin, changeAdmin/manageMembers),
to either kick or promote members to the admin role,
the list tile will have a tap event.
NOTE: This is why some members do not have a hover animation.
For example the owner cannot be kicked.
2023-03-25 10:31:14 +01:00

346 lines
14 KiB
Dart

import 'package:flutter/material.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/tools/fetch_wrapper.dart';
import 'package:routemaster/routemaster.dart';
class ManageRoomMembersPage extends StatefulWidget {
final String server;
final String tag;
const ManageRoomMembersPage(this.server, this.tag, {super.key});
@override
State<StatefulWidget> createState() => _ManageRoomMembersPageState();
}
class _ManageRoomMembersPageState extends State<ManageRoomMembersPage> {
List<RoomMember> list = [];
RoomInfo? info;
void fetchUserInfo() {
final rmaster = Routemaster.of(context);
final sm = ScaffoldMessenger.of(context);
doNetworkRequest(
sm,
req: (user) => postWithCreadentials(
path: 'getRoomInfo',
credentials: user!,
target: (user.server),
body: {'room': widget.tag, 'server': widget.server}),
onAnyErr: () {
// user should not be here
// close screen
rmaster.replace('/');
return false;
},
onOK: (body) async {
final info = RoomInfo.fromJSON(body['data']);
setState(() {
this.info = info;
});
return true;
},
);
}
void fetchMembers() {
final rmaster = Routemaster.of(context);
final sm = ScaffoldMessenger.of(context);
doNetworkRequest(sm,
req: (user) => postWithCreadentials(
credentials: user!,
target: user.server,
path: 'getRoomMembers',
body: {'room': widget.tag, 'server': widget.server}),
onAnyErr: () {
// user should not be here
// close screen
rmaster.replace('/');
return false;
},
onOK: (body) {
final List<RoomMember> list = body['data'].map<RoomMember>((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);
doNetworkRequest(
scaffMgr,
req: (user) =>
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);
doNetworkRequest(
scaffMgr,
req: (user) =>
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,
),
);
}
}