2023-03-22 21:16:00 +01:00
|
|
|
import 'package:flutter/material.dart';
|
2023-04-01 20:13:03 +02:00
|
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
import 'package:outbag_app/backend/permissions.dart';
|
2023-03-31 21:52:14 +02:00
|
|
|
import 'package:outbag_app/backend/request.dart';
|
2023-03-22 21:16:00 +01:00
|
|
|
import 'package:outbag_app/backend/room.dart';
|
2023-03-31 21:52:14 +02:00
|
|
|
import 'package:outbag_app/backend/user.dart';
|
|
|
|
import 'package:outbag_app/tools/fetch_wrapper.dart';
|
|
|
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|
|
|
import 'package:provider/provider.dart';
|
2023-03-22 21:16:00 +01:00
|
|
|
|
|
|
|
class RoomCategoriesPage extends StatefulWidget {
|
|
|
|
final RoomInfo? info;
|
|
|
|
final Room? room;
|
|
|
|
|
|
|
|
const RoomCategoriesPage(this.room, this.info, {super.key});
|
|
|
|
|
|
|
|
@override
|
|
|
|
State<StatefulWidget> createState() => _RoomCategoriesPageState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _RoomCategoriesPageState extends State<RoomCategoriesPage> {
|
2023-03-31 21:52:14 +02:00
|
|
|
List<RoomCategory> list = [];
|
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
super.initState();
|
|
|
|
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
|
|
fetchCategories();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void fetchCategories() async {
|
|
|
|
final user = context.read<User>();
|
|
|
|
|
|
|
|
// TODO: load cached rooms
|
|
|
|
|
|
|
|
doNetworkRequest(ScaffoldMessenger.of(context),
|
|
|
|
req: () => postWithCreadentials(
|
|
|
|
credentials: user,
|
|
|
|
target: user.server,
|
|
|
|
path: 'getCategories',
|
|
|
|
body: {'room': widget.room?.id, 'server': widget.room?.serverTag}),
|
|
|
|
onOK: (json) {
|
|
|
|
final resp = json['data']
|
|
|
|
.map<RoomCategory>((raw) => RoomCategory.fromJSON(raw))
|
|
|
|
.toList();
|
|
|
|
setState(() {
|
|
|
|
list = resp;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-03-22 21:16:00 +01:00
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2023-04-01 20:13:03 +02:00
|
|
|
final textTheme = Theme.of(context)
|
|
|
|
.textTheme
|
|
|
|
.apply(displayColor: Theme.of(context).colorScheme.onSurface);
|
|
|
|
|
2023-03-31 21:52:14 +02:00
|
|
|
return Scaffold(
|
|
|
|
body: ReorderableListView.builder(
|
2023-04-01 20:13:03 +02:00
|
|
|
buildDefaultDragHandles: false,
|
2023-03-31 21:52:14 +02:00
|
|
|
itemBuilder: (context, index) {
|
|
|
|
final item = list[index];
|
|
|
|
|
|
|
|
return ListTile(
|
|
|
|
key: Key('cat-${item.id}'),
|
|
|
|
leading: Icon(Icons.square_rounded, color: item.color),
|
2023-04-01 20:13:03 +02:00
|
|
|
trailing: ((widget.info?.isAdmin ?? false) ||
|
|
|
|
(widget.info?.isOwner ?? false) ||
|
|
|
|
((widget.info?.permissions)! &
|
|
|
|
RoomPermission.editRoomContent !=
|
|
|
|
0))
|
|
|
|
? ReorderableDragStartListener(
|
|
|
|
index: index,
|
|
|
|
child: const Icon(Icons.drag_handle)
|
|
|
|
)
|
|
|
|
: null,
|
2023-03-31 21:52:14 +02:00
|
|
|
title: Text(item.name),
|
|
|
|
onTap: () {
|
|
|
|
// TODO show edit category popup
|
|
|
|
// NOTE: maybe use ModalBottomSheet
|
|
|
|
// and show delete button in there
|
2023-04-01 20:13:03 +02:00
|
|
|
|
|
|
|
if (!((widget.info?.isAdmin ?? false) ||
|
|
|
|
(widget.info?.isOwner ?? false) ||
|
|
|
|
((widget.info?.permissions)! &
|
|
|
|
RoomPermission.editRoomContent !=
|
|
|
|
0))) {
|
|
|
|
// user is not allowed to edit or delete categories
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
showModalBottomSheet(
|
|
|
|
context: context,
|
|
|
|
builder: (context) => BottomSheet(
|
|
|
|
builder: (context) => Column(children: [
|
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.all(8),
|
|
|
|
child: Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
|
children: [
|
|
|
|
Icon(Icons.square_rounded,
|
|
|
|
size: 48.0, color: item.color),
|
|
|
|
Text(item.name, style: textTheme.titleLarge)
|
|
|
|
],
|
|
|
|
)),
|
|
|
|
// edit category
|
|
|
|
ListTile(
|
|
|
|
leading: const Icon(Icons.edit),
|
|
|
|
title: Text(AppLocalizations.of(context)!.editCategory),
|
|
|
|
subtitle:
|
|
|
|
Text(AppLocalizations.of(context)!.editCategoryLong),
|
|
|
|
trailing: const Icon(Icons.chevron_right),
|
|
|
|
onTap: () {
|
|
|
|
// close the modal bottom sheet
|
|
|
|
// so the user returns to the list,
|
|
|
|
// when leaving the category editor
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
|
|
|
|
// launch category editor
|
|
|
|
context.pushNamed('edit-category', params: {
|
|
|
|
'server': widget.room!.serverTag,
|
|
|
|
'id': widget.room!.id,
|
|
|
|
'cid': item.id.toString()
|
|
|
|
});
|
|
|
|
},
|
|
|
|
),
|
|
|
|
// delete category
|
|
|
|
ListTile(
|
|
|
|
leading: const Icon(Icons.delete),
|
|
|
|
title: Text(AppLocalizations.of(context)!.deleteCategory),
|
|
|
|
subtitle: Text(
|
|
|
|
AppLocalizations.of(context)!.deleteCategoryLong),
|
|
|
|
trailing: const Icon(Icons.chevron_right),
|
|
|
|
onTap: () {
|
|
|
|
// show popup
|
|
|
|
showDialog(
|
|
|
|
context: context,
|
|
|
|
builder: (ctx) => AlertDialog(
|
|
|
|
icon: const Icon(Icons.delete),
|
|
|
|
title: Text(AppLocalizations.of(context)!
|
|
|
|
.deleteCategory),
|
|
|
|
content: Text(AppLocalizations.of(context)!
|
|
|
|
.deleteCategoryConfirm(item.name)),
|
|
|
|
actions: [
|
|
|
|
TextButton(
|
|
|
|
onPressed: () {
|
|
|
|
// close popup
|
|
|
|
Navigator.of(ctx).pop();
|
|
|
|
},
|
|
|
|
child: Text(
|
|
|
|
AppLocalizations.of(context)!.cancel),
|
|
|
|
),
|
|
|
|
FilledButton(
|
|
|
|
onPressed: () async {
|
|
|
|
// send request
|
|
|
|
final scaffMgr =
|
|
|
|
ScaffoldMessenger.of(ctx);
|
|
|
|
// popup context
|
|
|
|
final navInner = Navigator.of(ctx);
|
|
|
|
// bottomsheet context
|
|
|
|
final nav = Navigator.of(context);
|
|
|
|
final user = context.read<User>();
|
|
|
|
|
|
|
|
doNetworkRequest(scaffMgr,
|
|
|
|
req: () => postWithCreadentials(
|
|
|
|
path: 'deleteCategory',
|
|
|
|
target: user.server,
|
|
|
|
body: {
|
|
|
|
'room': widget.room?.id,
|
|
|
|
'server':
|
|
|
|
widget.room?.serverTag,
|
|
|
|
'listCatID': item.id
|
|
|
|
},
|
|
|
|
credentials: user),
|
|
|
|
onOK: (_) async {
|
|
|
|
// TODO: remove cached category
|
|
|
|
},
|
|
|
|
after: () {
|
|
|
|
// close popup
|
|
|
|
navInner.pop();
|
|
|
|
// close modal bottom sheet
|
|
|
|
nav.pop();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
child: Text(AppLocalizations.of(context)!
|
|
|
|
.deleteCategory),
|
|
|
|
)
|
|
|
|
],
|
|
|
|
));
|
|
|
|
},
|
|
|
|
),
|
|
|
|
]),
|
|
|
|
onClosing: () {},
|
|
|
|
),
|
|
|
|
);
|
2023-03-31 21:52:14 +02:00
|
|
|
},
|
|
|
|
);
|
|
|
|
},
|
|
|
|
itemCount: list.length,
|
2023-04-01 20:13:03 +02:00
|
|
|
onReorder: (int oldIndex, int newIndex) {
|
|
|
|
|
|
|
|
if (!((widget.info?.isAdmin ?? false) ||
|
|
|
|
(widget.info?.isOwner ?? false) ||
|
|
|
|
((widget.info?.permissions)! &
|
|
|
|
RoomPermission.editRoomContent !=
|
|
|
|
0))) {
|
|
|
|
// user is not allowed to edit or delete categories
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
setState(() {
|
|
|
|
if (oldIndex < newIndex) {
|
|
|
|
newIndex -= 1;
|
|
|
|
}
|
|
|
|
final item = list.removeAt(oldIndex);
|
|
|
|
list.insert(newIndex, item);
|
|
|
|
|
|
|
|
// network request
|
|
|
|
final user = context.read<User>();
|
|
|
|
doNetworkRequest(ScaffoldMessenger.of(context),
|
|
|
|
req: () => postWithCreadentials(
|
|
|
|
credentials: user,
|
|
|
|
target: user.server,
|
|
|
|
path: 'changeCategoriesOrder',
|
|
|
|
body: {
|
|
|
|
'room': widget.room?.id,
|
|
|
|
'server': widget.room?.serverTag,
|
|
|
|
'listCatIDs': list.map((item) => item.id).toList()
|
|
|
|
}));
|
|
|
|
});
|
|
|
|
},
|
2023-03-31 21:52:14 +02:00
|
|
|
),
|
2023-04-01 20:13:03 +02:00
|
|
|
floatingActionButton: ((widget.info?.isAdmin ?? false) ||
|
|
|
|
(widget.info?.isOwner ?? false) ||
|
|
|
|
((widget.info?.permissions)! &
|
|
|
|
RoomPermission.editRoomContent !=
|
|
|
|
0))?FloatingActionButton.extended(
|
2023-03-31 21:52:14 +02:00
|
|
|
icon: const Icon(Icons.add),
|
|
|
|
label: Text(AppLocalizations.of(context)!.newCategoryShort),
|
|
|
|
tooltip: AppLocalizations.of(context)!.newCategoryLong,
|
|
|
|
onPressed: () {
|
2023-04-01 20:13:03 +02:00
|
|
|
// show new category popup
|
|
|
|
context.pushNamed('new-category', params: {
|
|
|
|
'server': widget.room!.serverTag,
|
|
|
|
'id': widget.room!.id,
|
|
|
|
});
|
2023-03-31 21:52:14 +02:00
|
|
|
},
|
2023-04-01 20:13:03 +02:00
|
|
|
):null,
|
2023-03-31 21:52:14 +02:00
|
|
|
);
|
2023-03-22 21:16:00 +01:00
|
|
|
}
|
|
|
|
}
|