// SPDX-FileCopyrightText: 2019-Present Christian Kußowski // SPDX-FileCopyrightText: 2019-Present Contributors to FluffyChat // // SPDX-License-Identifier: AGPL-3.0-or-later import 'package:tatchat/config/setting_keys.dart'; import 'package:tatchat/config/themes.dart'; import 'package:tatchat/l10n/l10n.dart'; import 'package:tatchat/pages/settings_notifications/push_rule_extensions.dart'; import 'package:tatchat/utils/background_push.dart'; import 'package:tatchat/utils/platform_infos.dart'; import 'package:tatchat/utils/push_helper.dart'; import 'package:tatchat/widgets/layouts/max_width_body.dart'; import 'package:tatchat/widgets/settings_switch_list_tile.dart'; import 'package:flutter/foundation.dart'; import 'package:material_ui/material_ui.dart'; import 'package:matrix/matrix.dart'; import 'package:unifiedpush/unifiedpush.dart'; import 'package:unifiedpush_ui/unifiedpush_ui.dart'; import '../../utils/localized_exception_extension.dart'; import '../../widgets/matrix.dart'; import 'settings_notifications.dart'; class SettingsNotificationsView extends StatelessWidget { final SettingsNotificationsController controller; const SettingsNotificationsView(this.controller, {super.key}); @override Widget build(BuildContext context) { final pushRules = Matrix.of(context).client.globalPushRules; final pushCategories = [ if (pushRules?.override?.isNotEmpty ?? false) (rules: pushRules?.override ?? [], kind: PushRuleKind.override), if (pushRules?.content?.isNotEmpty ?? false) (rules: pushRules?.content ?? [], kind: PushRuleKind.content), if (pushRules?.sender?.isNotEmpty ?? false) (rules: pushRules?.sender ?? [], kind: PushRuleKind.sender), if (pushRules?.underride?.isNotEmpty ?? false) (rules: pushRules?.underride ?? [], kind: PushRuleKind.underride), ]; final pushService = Matrix.of(context).backgroundPush; return Scaffold( appBar: AppBar( automaticallyImplyLeading: !FluffyThemes.isColumnMode(context), centerTitle: FluffyThemes.isColumnMode(context), title: Text(L10n.of(context).notifications), ), body: MaxWidthBody( child: StreamBuilder( stream: Matrix.of(context).client.onSync.stream.where( (syncUpdate) => syncUpdate.accountData?.any( (accountData) => accountData.type == 'm.push_rules', ) ?? false, ), builder: (BuildContext context, _) { final theme = Theme.of(context); final lastReceivedPush = lastReceivedPushNotification[Matrix.of( context, ).client.clientName]; return SelectionArea( child: Column( children: [ if (kDebugMode && lastReceivedPush != null) ListTile( title: Text('Last received push notification'), subtitle: Text(lastReceivedPush.toIso8601String()), ), if (kIsWeb) SettingsSwitchListTile.adaptive( title: L10n.of(context).playSoundOnNotification, setting: AppSettings.webNotificationSound, ), if (pushRules != null) for (final category in pushCategories) ...[ ListTile( title: Text( category.kind.localized(L10n.of(context)), style: TextStyle( color: theme.colorScheme.secondary, fontWeight: FontWeight.bold, ), ), ), for (final rule in category.rules) ListTile( title: Text(rule.getPushRuleName(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, ), ), ), ), ], ), ), trailing: Switch.adaptive( value: rule.enabled, onChanged: controller.isLoading ? null : rule.ruleId != '.m.rule.master' && Matrix.of( context, ).client.allPushNotificationsMuted ? null : (_) => controller.togglePushRule( category.kind, rule, ), ), ), Divider(color: theme.dividerColor), ], if (pushService?.firebaseEnabled != true) ListTile( title: Text(L10n.of(context).buildDoesNotSupportFirebase), leading: Icon( Icons.close, color: theme.colorScheme.error, ), ), if (PlatformInfos.isAndroid) FutureBuilder( future: UnifiedPush.getDistributors(), builder: (context, snapshot) { final distributors = snapshot.data; if (distributors == null || distributors.isEmpty) { if (pushService?.firebaseEnabled == true && pushService?.fcmToken == null) { return ListTile( title: Text( L10n.of( context, ).unableToRegisterDeviceForFirebase, ), leading: Icon( Icons.close, color: theme.colorScheme.error, ), ); } return SizedBox.shrink(); } return ListTile( title: Text(L10n.of(context).unifiedPushDistributors), leading: Icon(Icons.info_outlined), subtitle: SelectableText(distributors.join(', ')), trailing: distributors.length >= 2 ? IconButton( onPressed: () => UnifiedPushUi( context: context, instances: ['default'], unifiedPushFunctions: UPFunctions(), showNoDistribDialog: false, onNoDistribDialogDismissed: () {}, // TODO: Implement me ).registerAppWithDialog(), icon: Icon(Icons.edit_outlined), style: IconButton.styleFrom( backgroundColor: theme.colorScheme.primaryContainer, foregroundColor: theme.colorScheme.onPrimaryContainer, ), ) : null, ); }, ), ListTile( title: Text( L10n.of(context).devices, style: TextStyle( color: theme.colorScheme.secondary, fontWeight: FontWeight.bold, ), ), ), FutureBuilder?>( future: controller.pusherFuture ??= Matrix.of( context, ).client.getPushers(), builder: (context, snapshot) { if (snapshot.hasError) { Center( child: Text( snapshot.error!.toLocalizedString(context), ), ); } if (snapshot.connectionState != ConnectionState.done) { const Center( child: CircularProgressIndicator.adaptive( strokeWidth: 2, ), ); } final pushers = snapshot.data ?? []; if (pushers.isEmpty) { return Center( child: Padding( padding: const EdgeInsets.only(bottom: 16.0), child: Text(L10n.of(context).noOtherDevicesFound), ), ); } return SelectionArea( child: ListView.builder( physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: pushers.length, itemBuilder: (_, i) => ListTile( title: Text(pushers[i].appId), subtitle: Text(pushers[i].data.url.toString()), onTap: () => controller.onPusherTap(pushers[i]), ), ), ); }, ), ], ), ); }, ), ), ); } }