5b398eb2ae
- Fixed bug where switching room pages (list,products,categories,about), would result an unknown error, due to setState being called on a widget that isn't mounted. This was solved by surrounding the setState function, with a condition to check if the widget is mounted - Fixed bug where room members weren't recognized as admins This was caused by a typedifference between the server and the app (The server now returns booleans, where as before a ==1 comparison was needed) - Fixed bug where successfully closing the admin/kick member dialog, would crash the application. This was caused by popping the same context twice. We are now using two navigator (the outer and the inner one)
378 lines
16 KiB
Dart
378 lines
16 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';
|
|
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<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(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<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();
|
|
// 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<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();
|
|
// 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,
|
|
),
|
|
);
|
|
}
|
|
}
|