90adcc6bb1
NOTE: Some bugs have not been fixed, and the member screen needs fixing, but before that can happen, localstore has to be replaced, because it causes loops on android and linux. It also seems like it might lead to memory leaks
349 lines
14 KiB
Dart
349 lines
14 KiB
Dart
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<StatefulWidget> createState() => _ManageRoomMembersPageState();
|
|
}
|
|
|
|
class _ManageRoomMembersPageState extends State<ManageRoomMembersPage> {
|
|
List<RoomMember> list = [];
|
|
RoomInfo? info;
|
|
|
|
void fetchUserInfo() {
|
|
final router = GoRouter.of(context);
|
|
final sm = ScaffoldMessenger.of(context);
|
|
final user = context.read<User>();
|
|
|
|
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<User>();
|
|
|
|
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<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);
|
|
final user =
|
|
context.read<User>();
|
|
|
|
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:
|
|
(ctx) =>
|
|
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(ctx)
|
|
.pop();
|
|
},
|
|
child: const Text(
|
|
'Cancel'),
|
|
),
|
|
FilledButton(
|
|
onPressed:
|
|
() async {
|
|
// send request
|
|
final scaffMgr =
|
|
ScaffoldMessenger.of(ctx);
|
|
final nav =
|
|
Navigator.of(ctx);
|
|
final user =
|
|
context.read<User>();
|
|
|
|
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,
|
|
),
|
|
);
|
|
}
|
|
}
|