fix: Archive

This commit is contained in:
Krille 2023-01-08 12:32:35 +01:00
parent 8632154832
commit a1f60b7ff9
11 changed files with 89 additions and 53 deletions

View File

@ -94,6 +94,13 @@ class AppRoutes {
VWidget( VWidget(
path: '/archive', path: '/archive',
widget: const Archive(), widget: const Archive(),
stackedRoutes: [
VWidget(
path: ':roomid',
widget: const Chat(),
buildTransition: _dynamicTransition,
),
],
), ),
VWidget( VWidget(
path: '/newprivatechat', path: '/newprivatechat',
@ -220,13 +227,25 @@ class AppRoutes {
), ),
], ],
), ),
VWidget( VNester(
path: '/archive', path: '/archive',
widget: const TwoColumnLayout( widgetBuilder: (child) => TwoColumnLayout(
mainView: Archive(), mainView: const Archive(),
sideView: EmptyPage(), sideView: child,
), ),
buildTransition: _fadeTransition, buildTransition: _fadeTransition,
nestedRoutes: [
VWidget(
path: '',
widget: const EmptyPage(),
buildTransition: _dynamicTransition,
),
VWidget(
path: ':roomid',
widget: const Chat(),
buildTransition: _dynamicTransition,
),
],
), ),
], ],
), ),

View File

@ -21,11 +21,9 @@ class ArchiveController extends State<Archive> {
Future<List<Room>> getArchive(BuildContext context) async { Future<List<Room>> getArchive(BuildContext context) async {
final archive = this.archive; final archive = this.archive;
if (archive != null) return archive; if (archive != null) return archive;
return await Matrix.of(context).client.loadArchive(); return this.archive = await Matrix.of(context).client.loadArchive();
} }
void forgetAction(int i) => setState(() => archive?.removeAt(i));
void forgetAllAction() async { void forgetAllAction() async {
final archive = this.archive; final archive = this.archive;
if (archive == null) return; if (archive == null) return;

View File

@ -21,10 +21,14 @@ class ArchiveView extends StatelessWidget {
leading: const BackButton(), leading: const BackButton(),
title: Text(L10n.of(context)!.archive), title: Text(L10n.of(context)!.archive),
actions: [ actions: [
if (snapshot.hasData && archive != null && archive!.isNotEmpty) if (snapshot.data?.isNotEmpty ?? false)
TextButton( Padding(
onPressed: controller.forgetAllAction, padding: const EdgeInsets.all(8.0),
child: Text(L10n.of(context)!.clearArchive), child: TextButton.icon(
onPressed: controller.forgetAllAction,
label: Text(L10n.of(context)!.clearArchive),
icon: const Icon(Icons.cleaning_services_outlined),
),
) )
], ],
), ),
@ -50,7 +54,6 @@ class ArchiveView extends StatelessWidget {
itemCount: archive!.length, itemCount: archive!.length,
itemBuilder: (BuildContext context, int i) => ChatListItem( itemBuilder: (BuildContext context, int i) => ChatListItem(
archive![i], archive![i],
onForget: controller.forgetAction,
), ),
); );
} }

View File

@ -630,6 +630,7 @@ class ChatController extends State<Chat> {
} }
bool get canRedactSelectedEvents { bool get canRedactSelectedEvents {
if (isArchived) return false;
final clients = matrix!.currentBundle; final clients = matrix!.currentBundle;
for (final event in selectedEvents) { for (final event in selectedEvents) {
if (event.canRedact == false && if (event.canRedact == false &&
@ -639,7 +640,9 @@ class ChatController extends State<Chat> {
} }
bool get canEditSelectedEvents { bool get canEditSelectedEvents {
if (selectedEvents.length != 1 || !selectedEvents.first.status.isSent) { if (isArchived ||
selectedEvents.length != 1 ||
!selectedEvents.first.status.isSent) {
return false; return false;
} }
return currentRoomBundle return currentRoomBundle
@ -757,6 +760,15 @@ class ChatController extends State<Chat> {
return sendEmojiAction(emoji.emoji); return sendEmojiAction(emoji.emoji);
} }
void forgetRoom() async {
final result = await showFutureLoadingDialog(
context: context,
future: room!.forget,
);
if (result.error != null) return;
VRouter.of(context).to('/archive');
}
void typeEmoji(Emoji? emoji) { void typeEmoji(Emoji? emoji) {
if (emoji == null) return; if (emoji == null) return;
final text = sendController.text; final text = sendController.text;
@ -1008,6 +1020,9 @@ class ChatController extends State<Chat> {
setState(() => inputText = text); setState(() => inputText = text);
} }
bool get isArchived =>
{Membership.leave, Membership.ban}.contains(room?.membership);
void showEventInfo([Event? event]) => void showEventInfo([Event? event]) =>
(event ?? selectedEvents.single).showInfoDialog(context); (event ?? selectedEvents.single).showInfoDialog(context);

View File

@ -37,7 +37,10 @@ class ChatAppBarTitle extends StatelessWidget {
'${room.unsafeGetUserFromMemoryOrFallback(directChatMatrixID).mention} ', '${room.unsafeGetUserFromMemoryOrFallback(directChatMatrixID).mention} ',
), ),
) )
: () => VRouter.of(context).toSegments(['rooms', room.id, 'details']), : controller.isArchived
? null
: () =>
VRouter.of(context).toSegments(['rooms', room.id, 'details']),
child: Row( child: Row(
children: [ children: [
Hero( Hero(

View File

@ -108,6 +108,20 @@ class ChatView extends StatelessWidget {
], ],
), ),
]; ];
} else if (controller.isArchived) {
return [
Padding(
padding: const EdgeInsets.all(8.0),
child: TextButton.icon(
onPressed: controller.forgetRoom,
style: TextButton.styleFrom(
foregroundColor: Theme.of(context).colorScheme.error,
),
icon: const Icon(Icons.delete_forever_outlined),
label: Text(L10n.of(context)!.delete),
),
)
];
} else { } else {
return [ return [
if (Matrix.of(context).voipPlugin != null && if (Matrix.of(context).voipPlugin != null &&

View File

@ -21,10 +21,11 @@ class PinnedEvents extends StatelessWidget {
BuildContext context, List<Event?> events) async { BuildContext context, List<Event?> events) async {
final eventId = events.length == 1 final eventId = events.length == 1
? events.single?.eventId ? events.single?.eventId
: await showModalActionSheet<String>( : await showConfirmationDialog<String>(
context: context, context: context,
title: L10n.of(context)!.pinMessage,
actions: events actions: events
.map((event) => SheetAction( .map((event) => AlertDialogAction(
key: event?.eventId ?? '', key: event?.eventId ?? '',
label: event?.calcLocalizedBodyFallback( label: event?.calcLocalizedBodyFallback(
MatrixLocals(L10n.of(context)!), MatrixLocals(L10n.of(context)!),

View File

@ -21,7 +21,6 @@ class ChatListItem extends StatelessWidget {
final Room room; final Room room;
final bool activeChat; final bool activeChat;
final bool selected; final bool selected;
final Function? onForget;
final void Function()? onTap; final void Function()? onTap;
final void Function()? onLongPress; final void Function()? onLongPress;
@ -31,7 +30,6 @@ class ChatListItem extends StatelessWidget {
this.selected = false, this.selected = false,
this.onTap, this.onTap,
this.onLongPress, this.onLongPress,
this.onForget,
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
@ -62,35 +60,7 @@ class ChatListItem extends StatelessWidget {
} }
if (room.membership == Membership.leave) { if (room.membership == Membership.leave) {
final action = await showModalActionSheet<ArchivedRoomAction>( VRouter.of(context).toSegments(['archive', room.id]);
context: context,
title: L10n.of(context)!.archivedRoom,
message: L10n.of(context)!.thisRoomHasBeenArchived,
actions: [
SheetAction(
label: L10n.of(context)!.rejoin,
key: ArchivedRoomAction.rejoin,
),
SheetAction(
label: L10n.of(context)!.delete,
key: ArchivedRoomAction.delete,
isDestructiveAction: true,
),
],
);
if (action != null) {
switch (action) {
case ArchivedRoomAction.delete:
await archiveAction(context);
break;
case ArchivedRoomAction.rejoin:
await showFutureLoadingDialog(
context: context,
future: () => room.join(),
);
break;
}
}
} }
if (room.membership == Membership.join) { if (room.membership == Membership.join) {
@ -122,13 +92,10 @@ class ChatListItem extends StatelessWidget {
Future<void> archiveAction(BuildContext context) async { Future<void> archiveAction(BuildContext context) async {
{ {
if ([Membership.leave, Membership.ban].contains(room.membership)) { if ([Membership.leave, Membership.ban].contains(room.membership)) {
final success = await showFutureLoadingDialog( await showFutureLoadingDialog(
context: context, context: context,
future: () => room.forget(), future: () => room.forget(),
); );
if (success.error == null) {
if (onForget != null) onForget!();
}
return; return;
} }
final confirmed = await showOkCancelAlertDialog( final confirmed = await showOkCancelAlertDialog(

View File

@ -66,6 +66,16 @@ class ClientChooserButton extends StatelessWidget {
], ],
), ),
), ),
PopupMenuItem(
value: SettingsAction.archive,
child: Row(
children: [
const Icon(Icons.archive_outlined),
const SizedBox(width: 18),
Text(L10n.of(context)!.archive),
],
),
),
PopupMenuItem( PopupMenuItem(
value: SettingsAction.settings, value: SettingsAction.settings,
child: Row( child: Row(
@ -259,6 +269,9 @@ class ClientChooserButton extends StatelessWidget {
case SettingsAction.settings: case SettingsAction.settings:
VRouter.of(context).to('/settings'); VRouter.of(context).to('/settings');
break; break;
case SettingsAction.archive:
VRouter.of(context).to('/archive');
break;
} }
} }
} }
@ -336,4 +349,5 @@ enum SettingsAction {
newSpace, newSpace,
invite, invite,
settings, settings,
archive,
} }

View File

@ -8,12 +8,14 @@ Future<T?> showAdaptiveBottomSheet<T>({
required BuildContext context, required BuildContext context,
required Widget Function(BuildContext) builder, required Widget Function(BuildContext) builder,
bool isDismissible = true, bool isDismissible = true,
bool isScrollControlled = false,
}) => }) =>
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
builder: builder, builder: builder,
useRootNavigator: !PlatformInfos.isMobile, useRootNavigator: !PlatformInfos.isMobile,
isDismissible: isDismissible, isDismissible: isDismissible,
isScrollControlled: isScrollControlled,
constraints: BoxConstraints( constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height - 128, maxHeight: MediaQuery.of(context).size.height - 128,
maxWidth: FluffyThemes.columnWidth * 1.5, maxWidth: FluffyThemes.columnWidth * 1.5,

View File

@ -29,12 +29,12 @@ extension on PermissionLevel {
Future<int?> showPermissionChooser(BuildContext context, Future<int?> showPermissionChooser(BuildContext context,
{int currentLevel = 0}) async { {int currentLevel = 0}) async {
final permissionLevel = await showModalActionSheet( final permissionLevel = await showConfirmationDialog(
context: context, context: context,
title: L10n.of(context)!.setPermissionsLevel, title: L10n.of(context)!.setPermissionsLevel,
actions: PermissionLevel.values actions: PermissionLevel.values
.map( .map(
(level) => SheetAction( (level) => AlertDialogAction(
key: level, key: level,
label: level.toLocalizedString(context), label: level.toLocalizedString(context),
), ),