2023-03-24 21:10:42 +01:00
|
|
|
import 'package:flutter/material.dart';
|
2023-03-28 14:54:39 +02:00
|
|
|
import 'package:go_router/go_router.dart';
|
2023-03-24 21:10:42 +01:00
|
|
|
import 'package:outbag_app/backend/permissions.dart';
|
|
|
|
import 'package:outbag_app/backend/request.dart';
|
|
|
|
import 'package:outbag_app/backend/room.dart';
|
2023-03-25 17:18:46 +01:00
|
|
|
import 'package:outbag_app/backend/user.dart';
|
2023-03-24 21:10:42 +01:00
|
|
|
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
2023-03-25 17:18:46 +01:00
|
|
|
import 'package:provider/provider.dart';
|
2023-03-24 21:10:42 +01:00
|
|
|
|
|
|
|
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() {
|
2023-03-28 14:54:39 +02:00
|
|
|
final router = GoRouter.of(context);
|
2023-03-24 21:10:42 +01:00
|
|
|
final sm = ScaffoldMessenger.of(context);
|
2023-03-25 17:18:46 +01:00
|
|
|
final user = context.read<User>();
|
2023-03-24 21:10:42 +01:00
|
|
|
|
|
|
|
doNetworkRequest(
|
|
|
|
sm,
|
2023-03-25 17:18:46 +01:00
|
|
|
req: () => postWithCreadentials(
|
2023-03-24 21:10:42 +01:00
|
|
|
path: 'getRoomInfo',
|
2023-03-25 17:18:46 +01:00
|
|
|
credentials: user,
|
|
|
|
target: user.server,
|
2023-03-24 21:10:42 +01:00
|
|
|
body: {'room': widget.tag, 'server': widget.server}),
|
|
|
|
onAnyErr: () {
|
|
|
|
// user should not be here
|
|
|
|
// close screen
|
2023-03-28 14:54:39 +02:00
|
|
|
router.pushReplacementNamed('home');
|
2023-03-24 21:10:42 +01:00
|
|
|
return false;
|
|
|
|
},
|
|
|
|
onOK: (body) async {
|
|
|
|
final info = RoomInfo.fromJSON(body['data']);
|
|
|
|
setState(() {
|
|
|
|
this.info = info;
|
|
|
|
});
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
void fetchMembers() {
|
2023-03-28 14:54:39 +02:00
|
|
|
final router = GoRouter.of(context);
|
2023-03-24 21:10:42 +01:00
|
|
|
final sm = ScaffoldMessenger.of(context);
|
2023-03-25 17:18:46 +01:00
|
|
|
final user = context.read<User>();
|
2023-03-24 21:10:42 +01:00
|
|
|
|
|
|
|
doNetworkRequest(sm,
|
2023-03-25 17:18:46 +01:00
|
|
|
req: () => postWithCreadentials(
|
|
|
|
credentials: user,
|
2023-03-24 21:10:42 +01:00
|
|
|
target: user.server,
|
|
|
|
path: 'getRoomMembers',
|
|
|
|
body: {'room': widget.tag, 'server': widget.server}),
|
|
|
|
onAnyErr: () {
|
|
|
|
// user should not be here
|
|
|
|
// close screen
|
2023-03-28 14:54:39 +02:00
|
|
|
router.pushReplacementNamed('home');
|
2023-03-24 21:10:42 +01:00
|
|
|
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",
|
2023-03-25 17:18:46 +01:00
|
|
|
),
|
|
|
|
//actions: [
|
|
|
|
// // NOTE: Maybe add a search icon
|
|
|
|
// // and general search functionality here
|
|
|
|
//],
|
2023-03-24 21:10:42 +01:00
|
|
|
),
|
|
|
|
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),
|
2023-03-25 17:18:46 +01:00
|
|
|
onTap: !enable
|
|
|
|
? null
|
|
|
|
: () {
|
2023-03-24 21:10:42 +01:00
|
|
|
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)! &
|
2023-03-25 17:18:46 +01:00
|
|
|
RoomPermission
|
|
|
|
.changeAdmin !=
|
2023-03-24 21:10:42 +01:00
|
|
|
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:
|
2023-03-25 17:18:46 +01:00
|
|
|
(context) =>
|
|
|
|
AlertDialog(
|
|
|
|
icon: const Icon(
|
|
|
|
Icons
|
2023-03-24 21:10:42 +01:00
|
|
|
.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(
|
2023-03-25 17:18:46 +01:00
|
|
|
onPressed:
|
|
|
|
() {
|
2023-03-24 21:10:42 +01:00
|
|
|
// close popup
|
|
|
|
// NOTE: cancel only closes the dialog
|
|
|
|
// whilst OK closes both
|
2023-03-25 17:18:46 +01:00
|
|
|
Navigator.of(context)
|
2023-03-24 21:10:42 +01:00
|
|
|
.pop();
|
|
|
|
},
|
|
|
|
child: const Text(
|
|
|
|
'Cancel'),
|
|
|
|
),
|
|
|
|
FilledButton(
|
|
|
|
onPressed:
|
|
|
|
() async {
|
|
|
|
// send request
|
|
|
|
final scaffMgr =
|
2023-03-25 17:18:46 +01:00
|
|
|
ScaffoldMessenger.of(context);
|
2023-03-24 21:10:42 +01:00
|
|
|
final nav =
|
2023-03-25 17:18:46 +01:00
|
|
|
Navigator.of(context);
|
|
|
|
final user =
|
|
|
|
context.read<User>();
|
2023-03-24 21:10:42 +01:00
|
|
|
|
|
|
|
doNetworkRequest(
|
|
|
|
scaffMgr,
|
2023-03-25 17:18:46 +01:00
|
|
|
req: () =>
|
|
|
|
postWithCreadentials(path: 'setAdminStatus', credentials: user, target: user.server, body: {
|
2023-03-24 21:10:42 +01:00
|
|
|
'room': widget.tag,
|
|
|
|
'roomServer': widget.server,
|
|
|
|
'server': item.serverTag,
|
|
|
|
'name': item.id,
|
|
|
|
'admin': !item.isAdmin
|
|
|
|
}),
|
|
|
|
onOK: (_) {
|
|
|
|
fetchMembers();
|
|
|
|
},
|
|
|
|
after: () {
|
|
|
|
// close popup
|
|
|
|
nav.pop();
|
|
|
|
nav.pop();
|
|
|
|
});
|
|
|
|
},
|
2023-03-25 17:18:46 +01:00
|
|
|
child: const Text(
|
2023-03-24 21:10:42 +01:00
|
|
|
'OK'),
|
|
|
|
)
|
|
|
|
],
|
|
|
|
));
|
|
|
|
},
|
|
|
|
)
|
|
|
|
]
|
|
|
|
: [],
|
|
|
|
...((info?.isAdmin)! ||
|
|
|
|
(info?.isOwner)! ||
|
|
|
|
((info?.permissions)! &
|
|
|
|
RoomPermission
|
|
|
|
.manageMembers !=
|
|
|
|
0))
|
|
|
|
? [
|
|
|
|
ListTile(
|
2023-03-25 17:18:46 +01:00
|
|
|
leading: const Icon(
|
|
|
|
Icons.person_remove),
|
|
|
|
title:
|
|
|
|
const Text('Kick User'),
|
2023-03-24 21:10:42 +01:00
|
|
|
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:
|
2023-03-28 17:21:35 +02:00
|
|
|
(ctx) =>
|
2023-03-25 17:18:46 +01:00
|
|
|
AlertDialog(
|
|
|
|
icon: const Icon(
|
|
|
|
Icons
|
2023-03-24 21:10:42 +01:00
|
|
|
.person_remove),
|
|
|
|
title: const Text(
|
|
|
|
'Kick User'),
|
|
|
|
content: Text(
|
|
|
|
'Do you really want to kick ${item.humanReadableName}?'),
|
|
|
|
actions: [
|
|
|
|
TextButton(
|
2023-03-25 17:18:46 +01:00
|
|
|
onPressed:
|
|
|
|
() {
|
2023-03-24 21:10:42 +01:00
|
|
|
// close popup
|
|
|
|
// NOTE: cancel only closes the dialog
|
|
|
|
// whilst OK closes both
|
|
|
|
|
2023-03-28 17:21:35 +02:00
|
|
|
Navigator.of(ctx)
|
2023-03-24 21:10:42 +01:00
|
|
|
.pop();
|
|
|
|
},
|
|
|
|
child: const Text(
|
|
|
|
'Cancel'),
|
|
|
|
),
|
|
|
|
FilledButton(
|
|
|
|
onPressed:
|
|
|
|
() async {
|
|
|
|
// send request
|
|
|
|
final scaffMgr =
|
2023-03-28 17:21:35 +02:00
|
|
|
ScaffoldMessenger.of(ctx);
|
2023-03-24 21:10:42 +01:00
|
|
|
final nav =
|
2023-03-28 17:21:35 +02:00
|
|
|
Navigator.of(ctx);
|
2023-03-25 17:18:46 +01:00
|
|
|
final user =
|
|
|
|
context.read<User>();
|
2023-03-24 21:10:42 +01:00
|
|
|
|
|
|
|
doNetworkRequest(
|
|
|
|
scaffMgr,
|
2023-03-25 17:18:46 +01:00
|
|
|
req: () =>
|
2023-03-28 14:54:39 +02:00
|
|
|
postWithCreadentials(path: 'kickMember', credentials: user, target: user.server, body: {
|
2023-03-24 21:10:42 +01:00
|
|
|
'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,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|