From d7f7751e5e3e1e3c082ead6747a766652b3b54e4 Mon Sep 17 00:00:00 2001 From: Krille Date: Wed, 5 Feb 2025 09:38:15 +0100 Subject: [PATCH] feat: Inspect and delete push rules --- assets/l10n/intl_en.arb | 4 +- .../settings_notifications.dart | 109 ++++++++++++++++++ .../settings_notifications_view.dart | 33 +++++- 3 files changed, 142 insertions(+), 4 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index dfd1fa3fb..b2ac93ac1 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -2893,5 +2893,7 @@ "placeholders": { "rule": {} } - } + }, + "deletePushRuleCanNotBeUndone": "If you delete this notification setting, this can not be undone.", + "more": "More" } diff --git a/lib/pages/settings_notifications/settings_notifications.dart b/lib/pages/settings_notifications/settings_notifications.dart index 476078f25..887d0246c 100644 --- a/lib/pages/settings_notifications/settings_notifications.dart +++ b/lib/pages/settings_notifications/settings_notifications.dart @@ -1,10 +1,16 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:matrix/matrix.dart'; +import 'package:fluffychat/config/app_config.dart'; +import 'package:fluffychat/pages/settings_notifications/push_rule_extensions.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; +import 'package:fluffychat/widgets/adaptive_dialogs/adaptive_dialog_action.dart'; import 'package:fluffychat/widgets/adaptive_dialogs/show_modal_action_popup.dart'; +import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart'; import 'package:fluffychat/widgets/future_loading_dialog.dart'; import '../../widgets/matrix.dart'; import 'settings_notifications_view.dart'; @@ -92,6 +98,109 @@ class SettingsNotificationsController extends State { } } + void editPushRule(PushRule rule, PushRuleKind kind) async { + final theme = Theme.of(context); + final action = await showAdaptiveDialog( + context: context, + builder: (context) => ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 256), + child: AlertDialog.adaptive( + title: Text(rule.getPushRuleName(L10n.of(context))), + content: Padding( + padding: const EdgeInsets.only(top: 16.0), + child: Material( + borderRadius: BorderRadius.circular(AppConfig.borderRadius), + color: theme.colorScheme.surfaceContainer, + child: SingleChildScrollView( + padding: const EdgeInsets.all(16), + scrollDirection: Axis.horizontal, + child: SelectableText( + prettyJson(rule.toJson()), + style: TextStyle( + color: theme.colorScheme.onSurface, + ), + ), + ), + ), + ), + actions: [ + AdaptiveDialogAction( + onPressed: Navigator.of(context).pop, + child: Text(L10n.of(context).close), + ), + if (!rule.ruleId.startsWith('.m.')) + AdaptiveDialogAction( + onPressed: () => + Navigator.of(context).pop(PushRuleDialogAction.delete), + child: Text( + L10n.of(context).delete, + style: TextStyle(color: theme.colorScheme.error), + ), + ), + ], + ), + ), + ); + if (action == null) return; + if (!mounted) return; + switch (action) { + case PushRuleDialogAction.delete: + final consent = await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).areYouSure, + message: L10n.of(context).deletePushRuleCanNotBeUndone, + okLabel: L10n.of(context).delete, + isDestructive: true, + ); + if (consent != OkCancelResult.ok) return; + if (!mounted) return; + setState(() { + isLoading = true; + }); + try { + final updateFromSync = Matrix.of(context) + .client + .onSync + .stream + .where( + (syncUpdate) => + syncUpdate.accountData?.any( + (accountData) => accountData.type == 'm.push_rules', + ) ?? + false, + ) + .first; + await Matrix.of(context).client.deletePushRule( + kind, + rule.ruleId, + ); + await updateFromSync; + } catch (e, s) { + Logs().w('Unable to delete push rule', e, s); + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(e.toLocalizedString(context))), + ); + } finally { + if (mounted) { + setState(() { + isLoading = false; + }); + } + } + return; + } + } + @override Widget build(BuildContext context) => SettingsNotificationsView(this); } + +enum PushRuleDialogAction { delete } + +String prettyJson(Map json) { + const decoder = JsonDecoder(); + const encoder = JsonEncoder.withIndent(' '); + final object = decoder.convert(jsonEncode(json)); + return encoder.convert(object); +} diff --git a/lib/pages/settings_notifications/settings_notifications_view.dart b/lib/pages/settings_notifications/settings_notifications_view.dart index a51ce7673..b7f093079 100644 --- a/lib/pages/settings_notifications/settings_notifications_view.dart +++ b/lib/pages/settings_notifications/settings_notifications_view.dart @@ -58,10 +58,37 @@ class SettingsNotificationsView extends StatelessWidget { ), for (final rule in category.rules) SwitchListTile.adaptive( - value: rule.enabled, title: Text(rule.getPushRuleName(L10n.of(context))), - subtitle: - Text(rule.getPushRuleDescription(L10n.of(context))), + subtitle: Text.rich( + TextSpan( + children: [ + TextSpan( + text: rule.getPushRuleDescription( + L10n.of(context), + ), + ), + const TextSpan(text: ' '), + WidgetSpan( + child: InkWell( + onTap: () => controller.editPushRule( + rule, + category.kind, + ), + child: Text( + L10n.of(context).more, + style: TextStyle( + color: theme.colorScheme.primary, + decoration: TextDecoration.underline, + decorationColor: + theme.colorScheme.primary, + ), + ), + ), + ), + ], + ), + ), + value: rule.enabled, onChanged: controller.isLoading ? null : Matrix.of(context)