remove item&product confirmation dialog
Because there currently is no way to auto-refresh the lists it will appear as if nothing changed. Switching to a different tab and back again will update the list though
This commit is contained in:
parent
384fbb0573
commit
13c071b8ca
8 changed files with 872 additions and 611 deletions
|
@ -429,5 +429,12 @@
|
|||
"newItemQueryEmpty": "Type to show quick access buttons",
|
||||
"newItemQueryHint": "Type item or product name",
|
||||
"newItemQuickAccessPrefix": "Create:",
|
||||
"newItemQuickProduct": "product: {text}"
|
||||
"newItemQuickProduct": "product: {text}",
|
||||
"deleteItem": "Delete Item",
|
||||
"deleteItemConfirm": "Do you really want to remove the item named {item}",
|
||||
|
||||
"deleteProductTitle": "Delete Product",
|
||||
"deleteProductSubtitle": "Remove the product from list of known products",
|
||||
"deleteProduct": "Delete Product",
|
||||
"deleteProductConfirm": "DO you really want to remove the product named {product}"
|
||||
}
|
||||
|
|
|
@ -123,38 +123,48 @@ class _HomePageState extends State<HomePage> {
|
|||
)
|
||||
],
|
||||
),
|
||||
body: ListView.builder(
|
||||
itemCount: rooms.length,
|
||||
itemBuilder: (ctx, i) {
|
||||
final room = rooms[i];
|
||||
return Card(
|
||||
margin: const EdgeInsets.all(8.0),
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
semanticContainer: true,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
// open room
|
||||
context.goNamed('room',
|
||||
params: {'server': room.serverTag, 'id': room.id});
|
||||
},
|
||||
onLongPress: () {
|
||||
// open bottom sheet
|
||||
// NOTE: feature yet to be confirmed
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.fromLTRB(10, 5, 5, 10),
|
||||
child: ListTile(
|
||||
title: Text(room.name),
|
||||
visualDensity: const VisualDensity(vertical: 3),
|
||||
subtitle: Text(room.description),
|
||||
leading: AspectRatio(
|
||||
aspectRatio: 1 / 1,
|
||||
child: SvgPicture.asset("${room.icon?.img}"),
|
||||
),
|
||||
hoverColor: Colors.transparent,
|
||||
))));
|
||||
},
|
||||
),
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(14),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 600),
|
||||
child: ListView.builder(
|
||||
itemCount: rooms.length,
|
||||
itemBuilder: (ctx, i) {
|
||||
final room = rooms[i];
|
||||
return Card(
|
||||
margin: const EdgeInsets.all(8.0),
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
semanticContainer: true,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
// open room
|
||||
context.goNamed('room', params: {
|
||||
'server': room.serverTag,
|
||||
'id': room.id
|
||||
});
|
||||
},
|
||||
onLongPress: () {
|
||||
// open bottom sheet
|
||||
// NOTE: feature yet to be confirmed
|
||||
},
|
||||
child: Container(
|
||||
padding:
|
||||
const EdgeInsets.fromLTRB(10, 5, 5, 10),
|
||||
child: ListTile(
|
||||
title: Text(room.name),
|
||||
visualDensity:
|
||||
const VisualDensity(vertical: 3),
|
||||
subtitle: Text(room.description),
|
||||
leading: AspectRatio(
|
||||
aspectRatio: 1 / 1,
|
||||
child:
|
||||
SvgPicture.asset("${room.icon?.img}"),
|
||||
),
|
||||
hoverColor: Colors.transparent,
|
||||
))));
|
||||
},
|
||||
)))),
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
label: Text(AppLocalizations.of(context)!.addRoom),
|
||||
icon: const Icon(Icons.add),
|
||||
|
|
|
@ -138,7 +138,7 @@ class _EditItemPageState extends State<EditItemPage> {
|
|||
child: Padding(
|
||||
padding: const EdgeInsets.all(14),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 400),
|
||||
constraints: const BoxConstraints(maxWidth: 600),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
|
|
|
@ -33,303 +33,383 @@ class _AboutRoomPageState extends State<AboutRoomPage> {
|
|||
|
||||
return SingleChildScrollView(
|
||||
child: Center(
|
||||
child: Column(children: [
|
||||
// room meta display
|
||||
...(widget.room != null)
|
||||
? [
|
||||
Padding(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(14),
|
||||
child: Column(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
(widget.room?.icon?.img)!,
|
||||
width: smallest * 0.2,
|
||||
height: smallest * 0.2,
|
||||
),
|
||||
Text(
|
||||
widget.room?.name ?? '',
|
||||
style: textTheme.displayMedium,
|
||||
),
|
||||
Text(
|
||||
'${widget.room?.id}@${widget.room?.serverTag}',
|
||||
style: textTheme.bodySmall,
|
||||
),
|
||||
Text(
|
||||
widget.room?.description ?? '',
|
||||
style: textTheme.bodyMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: SegmentedButton<int>(
|
||||
showSelectedIcon: true,
|
||||
multiSelectionEnabled: false,
|
||||
emptySelectionAllowed: false,
|
||||
segments: RoomVisibility.list().map((vis) {
|
||||
return ButtonSegment<int>(
|
||||
value: vis.type,
|
||||
label: Text(vis.text(context)),
|
||||
icon: Icon(vis.icon));
|
||||
}).toList(),
|
||||
onSelectionChanged: ((vset) {
|
||||
// check permission
|
||||
// only show confirm dialog when user
|
||||
// is admin, owner or has CHANGE_ADMIN permission
|
||||
if (widget.info == null ||
|
||||
(!(widget.info?.isAdmin ?? false) &&
|
||||
!(widget.info?.isOwner ?? false) &&
|
||||
((widget.info?.permissions)! &
|
||||
RoomPermission.ota ==
|
||||
0))) {
|
||||
// action not permitted
|
||||
// NOTE: no error dialog should be shown
|
||||
// because the action is supposed to be hidden
|
||||
return;
|
||||
}
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 600),
|
||||
child: Column(children: [
|
||||
// room meta display
|
||||
...(widget.room != null)
|
||||
? [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(14),
|
||||
child: Column(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
(widget.room?.icon?.img)!,
|
||||
width: smallest * 0.2,
|
||||
height: smallest * 0.2,
|
||||
),
|
||||
Text(
|
||||
widget.room?.name ?? '',
|
||||
style: textTheme.displayMedium,
|
||||
),
|
||||
Text(
|
||||
'${widget.room?.id}@${widget.room?.serverTag}',
|
||||
style: textTheme.bodySmall,
|
||||
),
|
||||
Text(
|
||||
widget.room?.description ?? '',
|
||||
style: textTheme.bodyMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: SegmentedButton<int>(
|
||||
showSelectedIcon: true,
|
||||
multiSelectionEnabled: false,
|
||||
emptySelectionAllowed: false,
|
||||
segments:
|
||||
RoomVisibility.list().map((vis) {
|
||||
return ButtonSegment<int>(
|
||||
value: vis.type,
|
||||
label: Text(vis.text(context)),
|
||||
icon: Icon(vis.icon));
|
||||
}).toList(),
|
||||
onSelectionChanged: ((vset) {
|
||||
// check permission
|
||||
// only show confirm dialog when user
|
||||
// is admin, owner or has CHANGE_ADMIN permission
|
||||
if (widget.info == null ||
|
||||
(!(widget.info?.isAdmin ??
|
||||
false) &&
|
||||
!(widget.info?.isOwner ??
|
||||
false) &&
|
||||
((widget.info
|
||||
?.permissions)! &
|
||||
RoomPermission
|
||||
.ota ==
|
||||
0))) {
|
||||
// action not permitted
|
||||
// NOTE: no error dialog should be shown
|
||||
// because the action is supposed to be hidden
|
||||
return;
|
||||
}
|
||||
|
||||
final vis = RoomVisibility(vset.first);
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: Text(AppLocalizations.of(context)!
|
||||
.changeRoomVisibilityTitle),
|
||||
content: Text(
|
||||
AppLocalizations.of(context)!
|
||||
.changeRoomVisibilitySubtitle(
|
||||
vis.text(context))),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.pop();
|
||||
final vis =
|
||||
RoomVisibility(vset.first);
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: Text(AppLocalizations
|
||||
.of(context)!
|
||||
.changeRoomVisibilityTitle),
|
||||
content: Text(AppLocalizations
|
||||
.of(context)!
|
||||
.changeRoomVisibilitySubtitle(
|
||||
vis.text(
|
||||
context))),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.pop();
|
||||
},
|
||||
child: Text(
|
||||
AppLocalizations.of(
|
||||
context)!
|
||||
.cancel),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () async {
|
||||
final scaffMgr =
|
||||
ScaffoldMessenger
|
||||
.of(context);
|
||||
final nav =
|
||||
Navigator.of(
|
||||
context);
|
||||
final user = context
|
||||
.read<User>();
|
||||
|
||||
doNetworkRequest(
|
||||
scaffMgr,
|
||||
req: () =>
|
||||
postWithCreadentials(
|
||||
path:
|
||||
'setVisibility',
|
||||
target: user
|
||||
.server,
|
||||
body: {
|
||||
'room': widget
|
||||
.room
|
||||
?.id,
|
||||
'server': (widget
|
||||
.room
|
||||
?.serverTag)!,
|
||||
'visibility':
|
||||
vset.first
|
||||
},
|
||||
credentials:
|
||||
user),
|
||||
onOK: (_) {
|
||||
Room r = widget
|
||||
.room!;
|
||||
r.visibility =
|
||||
vis;
|
||||
r.toDisk();
|
||||
},
|
||||
after: () {
|
||||
nav.pop();
|
||||
});
|
||||
},
|
||||
child: Text(
|
||||
AppLocalizations.of(
|
||||
context)!
|
||||
.ok),
|
||||
)
|
||||
],
|
||||
));
|
||||
}),
|
||||
selected: {
|
||||
(widget.room?.visibility?.type)!
|
||||
},
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!
|
||||
.cancel),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () async {
|
||||
final scaffMgr =
|
||||
ScaffoldMessenger.of(context);
|
||||
final nav = Navigator.of(context);
|
||||
final user = context.read<User>();
|
||||
selectedIcon: Icon(
|
||||
(widget.room?.visibility?.icon)!),
|
||||
)),
|
||||
],
|
||||
),
|
||||
)
|
||||
]
|
||||
: [],
|
||||
|
||||
doNetworkRequest(scaffMgr,
|
||||
req: () => postWithCreadentials(
|
||||
path: 'setVisibility',
|
||||
target: user.server,
|
||||
body: {
|
||||
'room': widget.room?.id,
|
||||
'server': (widget
|
||||
.room?.serverTag)!,
|
||||
'visibility': vset.first
|
||||
},
|
||||
credentials: user),
|
||||
onOK: (_) {
|
||||
Room r = widget.room!;
|
||||
r.visibility = vis;
|
||||
r.toDisk();
|
||||
},
|
||||
after: () {
|
||||
nav.pop();
|
||||
});
|
||||
},
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.ok),
|
||||
)
|
||||
],
|
||||
));
|
||||
}),
|
||||
selected: {(widget.room?.visibility?.type)!},
|
||||
selectedIcon: Icon((widget.room?.visibility?.icon)!),
|
||||
)),
|
||||
],
|
||||
),
|
||||
)
|
||||
]
|
||||
: [],
|
||||
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(14),
|
||||
child: Column(
|
||||
children: [
|
||||
// edit room meta button
|
||||
...(widget.info != null &&
|
||||
((widget.info?.isAdmin ?? false) ||
|
||||
(widget.info?.isOwner ?? false) ||
|
||||
((widget.info?.permissions)! &
|
||||
RoomPermission.changeMeta !=
|
||||
0)))
|
||||
? [
|
||||
ListTile(
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
title: Text(
|
||||
AppLocalizations.of(context)!.editRoomMetadata),
|
||||
subtitle: Text(AppLocalizations.of(context)!
|
||||
.editRoomMetadataSubtitle),
|
||||
onTap: () {
|
||||
// show edit room screen
|
||||
context.goNamed('edit-room', params: {
|
||||
'server': (widget.room?.serverTag)!,
|
||||
'id': (widget.room?.id)!
|
||||
});
|
||||
},
|
||||
),
|
||||
]
|
||||
: [],
|
||||
// open members view
|
||||
ListTile(
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
title: Text(AppLocalizations.of(context)!.showRoomMembers),
|
||||
subtitle:
|
||||
Text(AppLocalizations.of(context)!.showRoomMembersSubtitle),
|
||||
onTap: () {
|
||||
// open member view screen
|
||||
context.goNamed('room-members', params: {
|
||||
'server': (widget.room?.serverTag)!,
|
||||
'id': (widget.room?.id)!
|
||||
});
|
||||
},
|
||||
),
|
||||
// edit default member permission
|
||||
...(widget.info != null &&
|
||||
((widget.info?.isAdmin ?? false) ||
|
||||
(widget.info?.isOwner ?? false) ||
|
||||
((widget.info?.permissions)! &
|
||||
RoomPermission.changeAdmin !=
|
||||
0)))
|
||||
? [
|
||||
ListTile(
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
title: Text(
|
||||
AppLocalizations.of(context)!.editRoomPermissions),
|
||||
subtitle: Text(AppLocalizations.of(context)!
|
||||
.editRoomPermissionsSubtitle),
|
||||
onTap: () {
|
||||
// show checkbox screen
|
||||
context.goNamed('room-permissions', params: {
|
||||
'server': (widget.room?.serverTag)!,
|
||||
'id': (widget.room?.id)!
|
||||
});
|
||||
},
|
||||
),
|
||||
]
|
||||
: [],
|
||||
...(widget.info != null &&
|
||||
((widget.info?.isAdmin ?? false) ||
|
||||
(widget.info?.isOwner ?? false) ||
|
||||
((widget.info?.permissions)! & RoomPermission.ota !=
|
||||
0)))
|
||||
? [
|
||||
ListTile(
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
title:
|
||||
Text(AppLocalizations.of(context)!.manageRoomOTA),
|
||||
subtitle: Text(AppLocalizations.of(context)!
|
||||
.manageRoomOTASubtitle),
|
||||
onTap: () {
|
||||
// show manage ota screen
|
||||
context.goNamed('room-ota', params: {
|
||||
'server': (widget.room?.serverTag)!,
|
||||
'id': (widget.room?.id)!
|
||||
});
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
title: Text(
|
||||
AppLocalizations.of(context)!.manageRoomInvites),
|
||||
subtitle: Text(AppLocalizations.of(context)!
|
||||
.manageRoomInvitesSubtitle),
|
||||
onTap: () {
|
||||
// show manage ota screen
|
||||
context.goNamed('room-invite', params: {
|
||||
'server': (widget.room?.serverTag)!,
|
||||
'id': (widget.room?.id)!
|
||||
});
|
||||
},
|
||||
),
|
||||
]
|
||||
: [],
|
||||
],
|
||||
)),
|
||||
|
||||
...(widget.info != null)
|
||||
? [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: FilledButton.tonal(
|
||||
child: Text(((widget.info?.isOwner)!)
|
||||
? AppLocalizations.of(context)!.deleteRoom
|
||||
: AppLocalizations.of(context)!.leaveRoom),
|
||||
onPressed: () {
|
||||
// show confirm dialog
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: Text(((widget.info?.isOwner)!)
|
||||
? AppLocalizations.of(context)!.deleteRoom
|
||||
: AppLocalizations.of(context)!.leaveRoom),
|
||||
content: Text(((widget.info?.isOwner)!)
|
||||
? AppLocalizations.of(context)!
|
||||
.deleteRoomConfirm
|
||||
: AppLocalizations.of(context)!
|
||||
.leaveRoomConfirm),
|
||||
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);
|
||||
final nav = Navigator.of(ctx);
|
||||
final router = GoRouter.of(context);
|
||||
final user = context.read<User>();
|
||||
|
||||
doNetworkRequest(scaffMgr,
|
||||
req: () => postWithCreadentials(
|
||||
path: ((widget.info?.isOwner)!)
|
||||
? 'deleteRoom'
|
||||
: 'leaveRoom',
|
||||
target: user.server,
|
||||
body: {
|
||||
'room': widget.room?.id,
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(14),
|
||||
child: Column(
|
||||
children: [
|
||||
// edit room meta button
|
||||
...(widget.info != null &&
|
||||
((widget.info?.isAdmin ?? false) ||
|
||||
(widget.info?.isOwner ?? false) ||
|
||||
((widget.info?.permissions)! &
|
||||
RoomPermission.changeMeta !=
|
||||
0)))
|
||||
? [
|
||||
ListTile(
|
||||
trailing:
|
||||
const Icon(Icons.chevron_right),
|
||||
title: Text(
|
||||
AppLocalizations.of(context)!
|
||||
.editRoomMetadata),
|
||||
subtitle: Text(
|
||||
AppLocalizations.of(context)!
|
||||
.editRoomMetadataSubtitle),
|
||||
onTap: () {
|
||||
// show edit room screen
|
||||
context.goNamed('edit-room', params: {
|
||||
'server': (widget.room?.serverTag)!,
|
||||
'id': (widget.room?.id)!
|
||||
});
|
||||
},
|
||||
),
|
||||
]
|
||||
: [],
|
||||
// open members view
|
||||
ListTile(
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
title: Text(AppLocalizations.of(context)!
|
||||
.showRoomMembers),
|
||||
subtitle: Text(AppLocalizations.of(context)!
|
||||
.showRoomMembersSubtitle),
|
||||
onTap: () {
|
||||
// open member view screen
|
||||
context.goNamed('room-members', params: {
|
||||
'server': (widget.room?.serverTag)!,
|
||||
'id': (widget.room?.id)!
|
||||
});
|
||||
},
|
||||
),
|
||||
// edit default member permission
|
||||
...(widget.info != null &&
|
||||
((widget.info?.isAdmin ?? false) ||
|
||||
(widget.info?.isOwner ?? false) ||
|
||||
((widget.info?.permissions)! &
|
||||
RoomPermission.changeAdmin !=
|
||||
0)))
|
||||
? [
|
||||
ListTile(
|
||||
trailing:
|
||||
const Icon(Icons.chevron_right),
|
||||
title: Text(
|
||||
AppLocalizations.of(context)!
|
||||
.editRoomPermissions),
|
||||
subtitle: Text(
|
||||
AppLocalizations.of(context)!
|
||||
.editRoomPermissionsSubtitle),
|
||||
onTap: () {
|
||||
// show checkbox screen
|
||||
context.goNamed('room-permissions',
|
||||
params: {
|
||||
'server':
|
||||
(widget.room?.serverTag)!,
|
||||
},
|
||||
credentials: user),
|
||||
onOK: (_) async {
|
||||
// try delete room from disk
|
||||
try {
|
||||
await widget.room?.removeDisk();
|
||||
} catch (_) {}
|
||||
|
||||
// go back home
|
||||
router.pushReplacementNamed('home');
|
||||
},
|
||||
after: () {
|
||||
// close popup
|
||||
nav.pop();
|
||||
'id': (widget.room?.id)!
|
||||
});
|
||||
},
|
||||
),
|
||||
]
|
||||
: [],
|
||||
...(widget.info != null &&
|
||||
((widget.info?.isAdmin ?? false) ||
|
||||
(widget.info?.isOwner ?? false) ||
|
||||
((widget.info?.permissions)! &
|
||||
RoomPermission.ota !=
|
||||
0)))
|
||||
? [
|
||||
ListTile(
|
||||
trailing:
|
||||
const Icon(Icons.chevron_right),
|
||||
title: Text(
|
||||
AppLocalizations.of(context)!
|
||||
.manageRoomOTA),
|
||||
subtitle: Text(
|
||||
AppLocalizations.of(context)!
|
||||
.manageRoomOTASubtitle),
|
||||
onTap: () {
|
||||
// show manage ota screen
|
||||
context.goNamed('room-ota', params: {
|
||||
'server': (widget.room?.serverTag)!,
|
||||
'id': (widget.room?.id)!
|
||||
});
|
||||
},
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
trailing:
|
||||
const Icon(Icons.chevron_right),
|
||||
title: Text(
|
||||
AppLocalizations.of(context)!
|
||||
.manageRoomInvites),
|
||||
subtitle: Text(
|
||||
AppLocalizations.of(context)!
|
||||
.manageRoomInvitesSubtitle),
|
||||
onTap: () {
|
||||
// show manage ota screen
|
||||
context
|
||||
.goNamed('room-invite', params: {
|
||||
'server': (widget.room?.serverTag)!,
|
||||
'id': (widget.room?.id)!
|
||||
});
|
||||
},
|
||||
),
|
||||
]
|
||||
: [],
|
||||
],
|
||||
)),
|
||||
|
||||
...(widget.info != null)
|
||||
? [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: FilledButton.tonal(
|
||||
child: Text(((widget.info?.isOwner)!)
|
||||
? AppLocalizations.of(context)!
|
||||
.deleteRoomShort
|
||||
.deleteRoom
|
||||
: AppLocalizations.of(context)!
|
||||
.leaveRoomShort),
|
||||
)
|
||||
],
|
||||
));
|
||||
},
|
||||
))
|
||||
]
|
||||
: [],
|
||||
])));
|
||||
.leaveRoom),
|
||||
onPressed: () {
|
||||
// show confirm dialog
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: Text(
|
||||
((widget.info?.isOwner)!)
|
||||
? AppLocalizations.of(
|
||||
context)!
|
||||
.deleteRoom
|
||||
: AppLocalizations.of(
|
||||
context)!
|
||||
.leaveRoom),
|
||||
content: Text(
|
||||
((widget.info?.isOwner)!)
|
||||
? AppLocalizations.of(
|
||||
context)!
|
||||
.deleteRoomConfirm
|
||||
: AppLocalizations.of(
|
||||
context)!
|
||||
.leaveRoomConfirm),
|
||||
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);
|
||||
final nav =
|
||||
Navigator.of(ctx);
|
||||
final router =
|
||||
GoRouter.of(context);
|
||||
final user =
|
||||
context.read<User>();
|
||||
|
||||
doNetworkRequest(scaffMgr,
|
||||
req: () =>
|
||||
postWithCreadentials(
|
||||
path: ((widget
|
||||
.info
|
||||
?.isOwner)!)
|
||||
? 'deleteRoom'
|
||||
: 'leaveRoom',
|
||||
target: user
|
||||
.server,
|
||||
body: {
|
||||
'room': widget
|
||||
.room
|
||||
?.id,
|
||||
'server': (widget
|
||||
.room
|
||||
?.serverTag)!,
|
||||
},
|
||||
credentials:
|
||||
user),
|
||||
onOK: (_) async {
|
||||
// try delete room from disk
|
||||
try {
|
||||
await widget.room
|
||||
?.removeDisk();
|
||||
} catch (_) {}
|
||||
|
||||
// go back home
|
||||
router
|
||||
.pushReplacementNamed(
|
||||
'home');
|
||||
},
|
||||
after: () {
|
||||
// close popup
|
||||
nav.pop();
|
||||
});
|
||||
},
|
||||
child: Text(((widget
|
||||
.info?.isOwner)!)
|
||||
? AppLocalizations.of(
|
||||
context)!
|
||||
.deleteRoomShort
|
||||
: AppLocalizations.of(
|
||||
context)!
|
||||
.leaveRoomShort),
|
||||
)
|
||||
],
|
||||
));
|
||||
},
|
||||
))
|
||||
]
|
||||
: [],
|
||||
])))));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,178 +61,209 @@ class _RoomCategoriesPageState extends State<RoomCategoriesPage> {
|
|||
.apply(displayColor: Theme.of(context).colorScheme.onSurface);
|
||||
|
||||
return Scaffold(
|
||||
body: ReorderableListView.builder(
|
||||
buildDefaultDragHandles: false,
|
||||
itemBuilder: (context, index) {
|
||||
final item = list[index];
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(14),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 600),
|
||||
child: 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
|
||||
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;
|
||||
}
|
||||
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(
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
icon: const Icon(Icons.delete),
|
||||
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),
|
||||
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>();
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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()
|
||||
}));
|
||||
});
|
||||
},
|
||||
),
|
||||
// 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) ||
|
||||
|
|
|
@ -194,110 +194,115 @@ class _ShoppingListPageState extends State<ShoppingListPage> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: ListView(children: [
|
||||
LabeledDivider(AppLocalizations.of(context)!.shoppingList),
|
||||
ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const ClampingScrollPhysics(),
|
||||
itemCount: list.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = list[index];
|
||||
final cat =
|
||||
categories[item.category] ?? RoomCategory.other(context);
|
||||
return ShoppingListItem(
|
||||
name: item.name,
|
||||
description: item.description,
|
||||
category: cat,
|
||||
key: Key(item.id.toString()),
|
||||
inCart: item.state != 0,
|
||||
onDismiss: () {
|
||||
// move to cart
|
||||
item.state = 1;
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(14),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 600),
|
||||
child: ListView(children: [
|
||||
LabeledDivider(AppLocalizations.of(context)!.shoppingList),
|
||||
ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const ClampingScrollPhysics(),
|
||||
itemCount: list.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = list[index];
|
||||
final cat = categories[item.category] ??
|
||||
RoomCategory.other(context);
|
||||
return ShoppingListItem(
|
||||
name: item.name,
|
||||
description: item.description,
|
||||
category: cat,
|
||||
key: Key(item.id.toString()),
|
||||
inCart: item.state != 0,
|
||||
onDismiss: () {
|
||||
// move to cart
|
||||
item.state = 1;
|
||||
|
||||
setState(() {
|
||||
list.removeAt(index);
|
||||
cart.add(item);
|
||||
sortAll();
|
||||
});
|
||||
setState(() {
|
||||
list.removeAt(index);
|
||||
cart.add(item);
|
||||
sortAll();
|
||||
});
|
||||
|
||||
// network request
|
||||
// NOTE: for now we do not care if it is successfull,
|
||||
// because the shopping cart is supposed to work even
|
||||
// without network
|
||||
changeItemState(item);
|
||||
},
|
||||
onTap: () {
|
||||
// TODO: show modal bottom sheet
|
||||
// containing
|
||||
// - item info
|
||||
// - option to view linked product (if available)
|
||||
// - edit item (if allowed)
|
||||
// - delete item (if allowed)
|
||||
// - move to/from shopping cart?
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => ShoppingListItemInfo(
|
||||
products: products,
|
||||
category: cat,
|
||||
info: widget.info,
|
||||
item: item,
|
||||
room: widget.room!.id,
|
||||
server: widget.room!.serverTag));
|
||||
});
|
||||
},
|
||||
),
|
||||
LabeledDivider(AppLocalizations.of(context)!.shoppingCart),
|
||||
ListView.builder(
|
||||
itemCount: cart.length,
|
||||
shrinkWrap: true,
|
||||
physics: const ClampingScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
final item = cart[index];
|
||||
final cat =
|
||||
categories[item.category] ?? RoomCategory.other(context);
|
||||
// network request
|
||||
// NOTE: for now we do not care if it is successfull,
|
||||
// because the shopping cart is supposed to work even
|
||||
// without network
|
||||
changeItemState(item);
|
||||
},
|
||||
onTap: () {
|
||||
// TODO: show modal bottom sheet
|
||||
// containing
|
||||
// - item info
|
||||
// - option to view linked product (if available)
|
||||
// - edit item (if allowed)
|
||||
// - delete item (if allowed)
|
||||
// - move to/from shopping cart?
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => ShoppingListItemInfo(
|
||||
products: products,
|
||||
category: cat,
|
||||
info: widget.info,
|
||||
item: item,
|
||||
room: widget.room!.id,
|
||||
server: widget.room!.serverTag));
|
||||
});
|
||||
},
|
||||
),
|
||||
LabeledDivider(AppLocalizations.of(context)!.shoppingCart),
|
||||
ListView.builder(
|
||||
itemCount: cart.length,
|
||||
shrinkWrap: true,
|
||||
physics: const ClampingScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
final item = cart[index];
|
||||
final cat = categories[item.category] ??
|
||||
RoomCategory.other(context);
|
||||
|
||||
return ShoppingListItem(
|
||||
name: item.name,
|
||||
description: item.description,
|
||||
category: cat,
|
||||
key: Key(item.id.toString()),
|
||||
inCart: item.state != 0,
|
||||
onDismiss: () {
|
||||
// move back to list
|
||||
item.state = 0;
|
||||
setState(() {
|
||||
cart.removeAt(index);
|
||||
list.add(item);
|
||||
sortAll();
|
||||
});
|
||||
return ShoppingListItem(
|
||||
name: item.name,
|
||||
description: item.description,
|
||||
category: cat,
|
||||
key: Key(item.id.toString()),
|
||||
inCart: item.state != 0,
|
||||
onDismiss: () {
|
||||
// move back to list
|
||||
item.state = 0;
|
||||
setState(() {
|
||||
cart.removeAt(index);
|
||||
list.add(item);
|
||||
sortAll();
|
||||
});
|
||||
|
||||
// network request
|
||||
// NOTE: for now we do not care if it is successfull,
|
||||
// because the shopping cart is supposed to work even
|
||||
// without network
|
||||
changeItemState(item);
|
||||
},
|
||||
onTap: () {
|
||||
// show modal bottom sheet
|
||||
// containing
|
||||
// - item info
|
||||
// - option to view linked product (if available)
|
||||
// - edit item (if allowed)
|
||||
// - delete item (if allowed)
|
||||
// - move to/from shopping cart?
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => ShoppingListItemInfo(
|
||||
products: products,
|
||||
category: cat,
|
||||
item: item,
|
||||
info: widget.info,
|
||||
room: widget.room!.id,
|
||||
server: widget.room!.serverTag));
|
||||
});
|
||||
},
|
||||
)
|
||||
]),
|
||||
// network request
|
||||
// NOTE: for now we do not care if it is successfull,
|
||||
// because the shopping cart is supposed to work even
|
||||
// without network
|
||||
changeItemState(item);
|
||||
},
|
||||
onTap: () {
|
||||
// show modal bottom sheet
|
||||
// containing
|
||||
// - item info
|
||||
// - option to view linked product (if available)
|
||||
// - edit item (if allowed)
|
||||
// - delete item (if allowed)
|
||||
// - move to/from shopping cart?
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => ShoppingListItemInfo(
|
||||
products: products,
|
||||
category: cat,
|
||||
item: item,
|
||||
info: widget.info,
|
||||
room: widget.room!.id,
|
||||
server: widget.room!.serverTag));
|
||||
});
|
||||
},
|
||||
)
|
||||
])))),
|
||||
floatingActionButton: (widget.info != null &&
|
||||
((widget.info?.isAdmin ?? false) ||
|
||||
(widget.info?.isOwner ?? false) ||
|
||||
|
@ -459,7 +464,60 @@ class ShoppingListItemInfo extends StatelessWidget {
|
|||
AppLocalizations.of(context)!.deleteItemSubtitle),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {
|
||||
// TODO: show confirm dialog
|
||||
// show popup
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
icon: const Icon(Icons.delete),
|
||||
title: Text(
|
||||
AppLocalizations.of(context)!.deleteItem),
|
||||
content: Text(AppLocalizations.of(context)!
|
||||
.deleteItemConfirm(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: 'deleteItem',
|
||||
target: user.server,
|
||||
body: {
|
||||
'room': room,
|
||||
'server': server,
|
||||
'listItemID': item.id
|
||||
},
|
||||
credentials: user),
|
||||
onOK: (_) async {
|
||||
// TODO: remove cached item
|
||||
},
|
||||
after: () {
|
||||
// close popup
|
||||
navInner.pop();
|
||||
// close modal bottom sheet
|
||||
nav.pop();
|
||||
});
|
||||
},
|
||||
child: Text(AppLocalizations.of(context)!
|
||||
.deleteItem),
|
||||
)
|
||||
],
|
||||
));
|
||||
}),
|
||||
]
|
||||
: [],
|
||||
|
|
|
@ -55,32 +55,37 @@ class _RoomProductsPageState extends State<RoomProductsPage> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: ListView.builder(
|
||||
itemCount: products.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = products[index];
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(14),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 600),
|
||||
child: ListView.builder(
|
||||
itemCount: products.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = products[index];
|
||||
|
||||
return ListTile(
|
||||
title: Text(item.name),
|
||||
subtitle: Text(item.description),
|
||||
onTap: () {
|
||||
// NOTE: we could also show a bottom sheet here,
|
||||
// but because we need a seperate page/route either way
|
||||
// (for viewing item-links and exploring the product-tree)
|
||||
// we might as well use the view-product page here
|
||||
// NOTE: This might seem inconsistent,
|
||||
// but you probably wont ever need to read a product description,
|
||||
// where as reading the shopping item description,
|
||||
// might be a good idea
|
||||
context.pushNamed('view-product', params: {
|
||||
'server': widget.room!.serverTag,
|
||||
'id': widget.room!.id,
|
||||
'product': item.id.toString()
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
return ListTile(
|
||||
title: Text(item.name),
|
||||
subtitle: Text(item.description),
|
||||
onTap: () {
|
||||
// NOTE: we could also show a bottom sheet here,
|
||||
// but because we need a seperate page/route either way
|
||||
// (for viewing item-links and exploring the product-tree)
|
||||
// we might as well use the view-product page here
|
||||
// NOTE: This might seem inconsistent,
|
||||
// but you probably wont ever need to read a product description,
|
||||
// where as reading the shopping item description,
|
||||
// might be a good idea
|
||||
context.pushNamed('view-product', params: {
|
||||
'server': widget.room!.serverTag,
|
||||
'id': widget.room!.id,
|
||||
'product': item.id.toString()
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
)))),
|
||||
floatingActionButton: (widget.info != null &&
|
||||
((widget.info?.isAdmin ?? false) ||
|
||||
(widget.info?.isOwner ?? false) ||
|
||||
|
|
|
@ -207,6 +207,76 @@ class _ViewProductPageState extends State<ViewProductPage> {
|
|||
},
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
),
|
||||
...(info != null &&
|
||||
((info?.isAdmin ?? false) ||
|
||||
(info?.isOwner ?? false) ||
|
||||
((info?.permissions)! & RoomPermission.editRoomContent !=
|
||||
0)))
|
||||
? [
|
||||
// delete product
|
||||
ListTile(
|
||||
title: Text(AppLocalizations.of(context)!.deleteProductTitle),
|
||||
subtitle:
|
||||
Text(AppLocalizations.of(context)!.deleteProductSubtitle),
|
||||
onTap: () {
|
||||
// show popup
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
icon: const Icon(Icons.delete),
|
||||
title: Text(
|
||||
AppLocalizations.of(context)!.deleteProduct),
|
||||
content: Text(AppLocalizations.of(context)!
|
||||
.deleteProductConfirm(product?.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: 'deleteProduct',
|
||||
target: user.server,
|
||||
body: {
|
||||
'room': widget.room,
|
||||
'server': widget.server,
|
||||
'listProdID': product?.id ?? ""
|
||||
},
|
||||
credentials: user),
|
||||
onOK: (_) async {
|
||||
// TODO: remove cached product
|
||||
},
|
||||
after: () {
|
||||
// close popup
|
||||
navInner.pop();
|
||||
// close modal bottom sheet
|
||||
nav.pop();
|
||||
});
|
||||
},
|
||||
child: Text(AppLocalizations.of(context)!
|
||||
.deleteProduct),
|
||||
)
|
||||
],
|
||||
));
|
||||
},
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
),
|
||||
]
|
||||
: []
|
||||
])),
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue