actions-test/lib/screens/room/pages/categories.dart
2023-12-22 20:14:36 +01:00

257 lines
10 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:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart';
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> {
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();
if (mounted) {
setState(() {
list = resp;
});
}
});
}
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context)
.textTheme
.apply(displayColor: Theme.of(context).colorScheme.onSurface);
return Scaffold(
body: ReorderableListView.builder(
buildDefaultDragHandles: false,
itemBuilder: (context, index) {
final item = list[index];
return ListTile(
key: Key('cat-${item.id}'),
leading: Icon(Icons.square_rounded, color: item.color),
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,
title: Text(item.name),
onTap: () {
// TODO show edit category popup
// NOTE: maybe use ModalBottomSheet
// and show delete button in there
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,
'category': 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
fetchCategories();
},
after: () {
// close popup
navInner.pop();
// close modal bottom sheet
nav.pop();
});
},
child: Text(AppLocalizations.of(context)!
.deleteCategory),
)
],
));
},
),
]),
onClosing: () {},
),
);
},
);
},
itemCount: list.length,
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()
}));
});
},
),
floatingActionButton: (widget.info != null &&
((widget.info?.isAdmin ?? false) ||
(widget.info?.isOwner ?? false) ||
((widget.info?.permissions)! &
RoomPermission.editRoomContent !=
0)))
? FloatingActionButton.extended(
icon: const Icon(Icons.add),
label: Text(AppLocalizations.of(context)!.newCategoryShort),
tooltip: AppLocalizations.of(context)!.newCategoryLong,
onPressed: () {
// show new category popup
context.pushNamed('new-category', params: {
'server': widget.room!.serverTag,
'id': widget.room!.id,
});
},
)
: null,
);
}
}