diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 1f05124..eb625ce 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -143,6 +143,14 @@ "settings_deviceInfo": "Device Info", "settings_appSettings": "App Settings", "settings_appSettingsSubtitle": "Notifications, messaging, and map preferences", + "settings_messageSettings": "Message Settings", + "@settings_messageSettings": { + "description": "Settings category title for notification and message-handling preferences" + }, + "settings_messageSettingsSubtitle": "Notifications and message handling", + "@settings_messageSettingsSubtitle": { + "description": "Settings category subtitle for the message settings pane" + }, "settings_nodeSettings": "Node Settings", "settings_nodeName": "Node Name", "settings_nodeNameNotSet": "Not set", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index b45facf..a17413e 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -694,6 +694,18 @@ abstract class AppLocalizations { /// **'Notifications, messaging, and map preferences'** String get settings_appSettingsSubtitle; + /// Settings category title for notification and message-handling preferences + /// + /// In en, this message translates to: + /// **'Message Settings'** + String get settings_messageSettings; + + /// Settings category subtitle for the message settings pane + /// + /// In en, this message translates to: + /// **'Notifications and message handling'** + String get settings_messageSettingsSubtitle; + /// No description provided for @settings_nodeSettings. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index af9e693..214ec46 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -319,6 +319,13 @@ class AppLocalizationsBg extends AppLocalizations { String get settings_appSettingsSubtitle => 'Уведомления, съобщения и предпочитания за карта'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'Настройки на възела'; diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 3fa9c4a..92d9db7 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -322,6 +322,13 @@ class AppLocalizationsDe extends AppLocalizations { String get settings_appSettingsSubtitle => 'Benachrichtigungen, Messaging und Kartenwahrnehmung'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'Knoten-Einstellungen'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 4fbfd5b..ac70215 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -316,6 +316,13 @@ class AppLocalizationsEn extends AppLocalizations { String get settings_appSettingsSubtitle => 'Notifications, messaging, and map preferences'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'Node Settings'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index 383dd03..d755321 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -320,6 +320,13 @@ class AppLocalizationsEs extends AppLocalizations { String get settings_appSettingsSubtitle => 'Notificaciones, mensajes y preferencias de mapa'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'Configuración del Nodo'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index 990c49c..10df065 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -322,6 +322,13 @@ class AppLocalizationsFr extends AppLocalizations { String get settings_appSettingsSubtitle => 'Notifications, messagerie et préférences de carte'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'Paramètres du nœud'; diff --git a/lib/l10n/app_localizations_hu.dart b/lib/l10n/app_localizations_hu.dart index 58f263b..78c65b1 100644 --- a/lib/l10n/app_localizations_hu.dart +++ b/lib/l10n/app_localizations_hu.dart @@ -319,6 +319,13 @@ class AppLocalizationsHu extends AppLocalizations { String get settings_appSettingsSubtitle => 'Értesítések, üzenetküldés és térképi beállítások'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'Műközép beállítások'; diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index a0149bd..c7fa3fc 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -322,6 +322,13 @@ class AppLocalizationsIt extends AppLocalizations { String get settings_appSettingsSubtitle => 'Notifiche, messaggi e preferenze della mappa'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'Impostazioni Nodo'; diff --git a/lib/l10n/app_localizations_ja.dart b/lib/l10n/app_localizations_ja.dart index 1239608..1f54912 100644 --- a/lib/l10n/app_localizations_ja.dart +++ b/lib/l10n/app_localizations_ja.dart @@ -308,6 +308,13 @@ class AppLocalizationsJa extends AppLocalizations { @override String get settings_appSettingsSubtitle => '通知、メッセージング、および地図の表示設定'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'ノード設定'; diff --git a/lib/l10n/app_localizations_ko.dart b/lib/l10n/app_localizations_ko.dart index 606a33d..3e1d8f5 100644 --- a/lib/l10n/app_localizations_ko.dart +++ b/lib/l10n/app_localizations_ko.dart @@ -307,6 +307,13 @@ class AppLocalizationsKo extends AppLocalizations { @override String get settings_appSettingsSubtitle => '알림, 메시징, 지도 설정'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => '노드 설정'; diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index 90a446d..774ec6d 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -318,6 +318,13 @@ class AppLocalizationsNl extends AppLocalizations { String get settings_appSettingsSubtitle => 'Notificaties, berichten en kaartinstellingen'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'Node Instellingen'; diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index f30cbb7..a1c0d2e 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -323,6 +323,13 @@ class AppLocalizationsPl extends AppLocalizations { String get settings_appSettingsSubtitle => 'Powiadomienia, wiadomości i preferencje mapy'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'Ustawienia węzła'; diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index 5fe1502..e922f0a 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -321,6 +321,13 @@ class AppLocalizationsPt extends AppLocalizations { String get settings_appSettingsSubtitle => 'Notificações, mensagens e preferências de mapa'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'Configurações do Nó'; diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 8492942..d373fda 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -321,6 +321,13 @@ class AppLocalizationsRu extends AppLocalizations { String get settings_appSettingsSubtitle => 'Уведомления, сообщения и настройки карты'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'Настройки ноды'; diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index 2072b63..08ed163 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -320,6 +320,13 @@ class AppLocalizationsSk extends AppLocalizations { String get settings_appSettingsSubtitle => 'Upozornenia, správy a nastavenia mapy'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'Nastavenia uzla'; diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index e91086e..8c33f31 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -318,6 +318,13 @@ class AppLocalizationsSl extends AppLocalizations { String get settings_appSettingsSubtitle => 'Obveščanja, sporoščanje in zemljevidi.'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'Nastavitev časa'; diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index 95af0f6..a31f97d 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -317,6 +317,13 @@ class AppLocalizationsSv extends AppLocalizations { String get settings_appSettingsSubtitle => 'Meddelanden, notiser och kartinställningar'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'Nodinställningar'; diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index ae82d64..55c4740 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -320,6 +320,13 @@ class AppLocalizationsUk extends AppLocalizations { String get settings_appSettingsSubtitle => 'Сповіщення, повідомлення та налаштування карти'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => 'Налаштування вузла'; diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index 79e4e22..7b8cf74 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -305,6 +305,13 @@ class AppLocalizationsZh extends AppLocalizations { @override String get settings_appSettingsSubtitle => '通知、消息和地图偏好'; + @override + String get settings_messageSettings => 'Message Settings'; + + @override + String get settings_messageSettingsSubtitle => + 'Notifications and message handling'; + @override String get settings_nodeSettings => '节点设置'; diff --git a/lib/screens/app_settings_screen.dart b/lib/screens/settings/app_settings_view.dart similarity index 76% rename from lib/screens/app_settings_screen.dart rename to lib/screens/settings/app_settings_view.dart index 9b0fb37..c4e2421 100644 --- a/lib/screens/app_settings_screen.dart +++ b/lib/screens/settings/app_settings_view.dart @@ -3,74 +3,50 @@ import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import '../connector/meshcore_connector.dart'; -import '../l10n/l10n.dart'; -import '../models/app_settings.dart'; -import '../models/translation_support.dart'; -import '../services/app_settings_service.dart'; -import '../services/notification_service.dart'; -import '../services/translation_service.dart'; -import '../widgets/adaptive_app_bar_title.dart'; -import '../widgets/sync_progress_overlay.dart'; -import '../helpers/snack_bar_builder.dart'; -import 'map_cache_screen.dart'; +import '../../connector/meshcore_connector.dart'; +import '../../l10n/l10n.dart'; +import '../../models/app_settings.dart'; +import '../../models/translation_support.dart'; +import '../../services/app_settings_service.dart'; +import '../../services/translation_service.dart'; +import '../../helpers/snack_bar_builder.dart'; +import '../map_cache_screen.dart'; -class AppSettingsScreen extends StatelessWidget { - const AppSettingsScreen({super.key}); +/// Embeddable view (no Scaffold) for the App Settings shell pane. +/// +/// Renders appearance, translation, battery, map, Cyr2Lat, and debug cards. +/// Notifications and message-handling settings live in [MessageSettingsView]. +class AppSettingsView extends StatelessWidget { + const AppSettingsView({super.key}); @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: AdaptiveAppBarTitle(context.l10n.appSettings_title), - centerTitle: true, - bottom: const SyncProgressAppBarBottom(), - ), - body: SafeArea( - top: false, - child: - Consumer3< - AppSettingsService, - MeshCoreConnector, - TranslationService - >( - builder: - ( + return Consumer3( + builder: + (context, settingsService, connector, translationService, child) { + return ListView( + padding: const EdgeInsets.all(16), + children: [ + _buildAppearanceCard(context, settingsService), + const SizedBox(height: 16), + if (!kIsWeb) ...[ + _buildTranslationCard( context, settingsService, - connector, translationService, - child, - ) { - return ListView( - padding: const EdgeInsets.all(16), - children: [ - _buildAppearanceCard(context, settingsService), - const SizedBox(height: 16), - _buildNotificationsCard(context, settingsService), - const SizedBox(height: 16), - _buildMessagingCard(context, settingsService), - const SizedBox(height: 16), - if (!kIsWeb) ...[ - _buildTranslationCard( - context, - settingsService, - translationService, - ), - const SizedBox(height: 16), - ], - _buildBatteryCard(context, settingsService, connector), - const SizedBox(height: 16), - _buildMapSettingsCard(context, settingsService), - const SizedBox(height: 16), - _buildCyr2LatCard(context, settingsService), - const SizedBox(height: 16), - _buildDebugCard(context, settingsService), - ], - ); - }, - ), - ), + ), + const SizedBox(height: 16), + ], + _buildBatteryCard(context, settingsService, connector), + const SizedBox(height: 16), + _buildMapSettingsCard(context, settingsService), + const SizedBox(height: 16), + _buildCyr2LatCard(context, settingsService), + const SizedBox(height: 16), + _buildDebugCard(context, settingsService), + ], + ); + }, ); } @@ -128,338 +104,6 @@ class AppSettingsScreen extends StatelessWidget { ); } - Widget _buildNotificationsCard( - BuildContext context, - AppSettingsService settingsService, - ) { - return Card( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), - child: Text( - context.l10n.appSettings_notifications, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - ), - ), - SwitchListTile( - secondary: const Icon(Icons.notifications_outlined), - title: Text(context.l10n.appSettings_enableNotifications), - subtitle: Text( - context.l10n.appSettings_enableNotificationsSubtitle, - ), - value: settingsService.settings.notificationsEnabled, - onChanged: (value) async { - if (value) { - // Request permission when enabling - final granted = await NotificationService() - .requestPermissions(); - if (!granted) { - if (context.mounted) { - showDismissibleSnackBar( - context, - content: Text( - context.l10n.appSettings_notificationPermissionDenied, - ), - duration: const Duration(seconds: 2), - ); - } - return; - } - } - - await settingsService.setNotificationsEnabled(value); - if (context.mounted) { - showDismissibleSnackBar( - context, - content: Text( - value - ? context.l10n.appSettings_notificationsEnabled - : context.l10n.appSettings_notificationsDisabled, - ), - duration: const Duration(seconds: 2), - ); - } - }, - ), - const Divider(height: 1), - SwitchListTile( - secondary: Icon( - Icons.message_outlined, - color: settingsService.settings.notificationsEnabled - ? null - : Colors.grey, - ), - title: Text( - context.l10n.appSettings_messageNotifications, - style: TextStyle( - color: settingsService.settings.notificationsEnabled - ? null - : Colors.grey, - ), - ), - subtitle: Text( - context.l10n.appSettings_messageNotificationsSubtitle, - style: TextStyle( - color: settingsService.settings.notificationsEnabled - ? null - : Colors.grey, - ), - ), - value: settingsService.settings.notifyOnNewMessage, - onChanged: settingsService.settings.notificationsEnabled - ? (value) { - settingsService.setNotifyOnNewMessage(value); - } - : null, - ), - const Divider(height: 1), - SwitchListTile( - secondary: Icon( - Icons.forum_outlined, - color: settingsService.settings.notificationsEnabled - ? null - : Colors.grey, - ), - title: Text( - context.l10n.appSettings_channelMessageNotifications, - style: TextStyle( - color: settingsService.settings.notificationsEnabled - ? null - : Colors.grey, - ), - ), - subtitle: Text( - context.l10n.appSettings_channelMessageNotificationsSubtitle, - style: TextStyle( - color: settingsService.settings.notificationsEnabled - ? null - : Colors.grey, - ), - ), - value: settingsService.settings.notifyOnNewChannelMessage, - onChanged: settingsService.settings.notificationsEnabled - ? (value) { - settingsService.setNotifyOnNewChannelMessage(value); - } - : null, - ), - const Divider(height: 1), - SwitchListTile( - secondary: Icon( - Icons.cell_tower, - color: settingsService.settings.notificationsEnabled - ? null - : Colors.grey, - ), - title: Text( - context.l10n.appSettings_advertisementNotifications, - style: TextStyle( - color: settingsService.settings.notificationsEnabled - ? null - : Colors.grey, - ), - ), - subtitle: Text( - context.l10n.appSettings_advertisementNotificationsSubtitle, - style: TextStyle( - color: settingsService.settings.notificationsEnabled - ? null - : Colors.grey, - ), - ), - value: settingsService.settings.notifyOnNewAdvert, - onChanged: settingsService.settings.notificationsEnabled - ? (value) { - settingsService.setNotifyOnNewAdvert(value); - } - : null, - ), - ], - ), - ); - } - - Widget _buildMessagingCard( - BuildContext context, - AppSettingsService settingsService, - ) { - return Card( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), - child: Text( - context.l10n.appSettings_messaging, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - ), - ), - SwitchListTile( - secondary: const Icon(Icons.refresh_outlined), - title: Text(context.l10n.appSettings_clearPathOnMaxRetry), - subtitle: Text( - context.l10n.appSettings_clearPathOnMaxRetrySubtitle, - ), - value: settingsService.settings.clearPathOnMaxRetry, - onChanged: (value) { - settingsService.setClearPathOnMaxRetry(value); - showDismissibleSnackBar( - context, - content: Text( - value - ? context.l10n.appSettings_pathsWillBeCleared - : context.l10n.appSettings_pathsWillNotBeCleared, - ), - duration: const Duration(seconds: 2), - ); - }, - ), - const Divider(height: 1), - SwitchListTile( - secondary: const Icon(Icons.vertical_align_top), - title: Text(context.l10n.appSettings_jumpToOldestUnread), - subtitle: Text(context.l10n.appSettings_jumpToOldestUnreadSubtitle), - value: settingsService.settings.jumpToOldestUnread, - onChanged: settingsService.setJumpToOldestUnread, - ), - const Divider(height: 1), - SwitchListTile( - secondary: const Icon(Icons.alt_route), - title: Text(context.l10n.appSettings_autoRouteRotation), - subtitle: Text(context.l10n.appSettings_autoRouteRotationSubtitle), - value: settingsService.settings.autoRouteRotationEnabled, - onChanged: (value) { - settingsService.setAutoRouteRotationEnabled(value); - showDismissibleSnackBar( - context, - content: Text( - value - ? context.l10n.appSettings_autoRouteRotationEnabled - : context.l10n.appSettings_autoRouteRotationDisabled, - ), - duration: const Duration(seconds: 2), - ); - }, - ), - if (settingsService.settings.autoRouteRotationEnabled) ...[ - const Divider(height: 1), - ListTile( - title: Text(context.l10n.appSettings_maxRouteWeight), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(context.l10n.appSettings_maxRouteWeightSubtitle), - Slider( - value: settingsService.settings.maxRouteWeight, - min: 1, - max: 10, - divisions: 9, - label: settingsService.settings.maxRouteWeight - .round() - .toString(), - onChanged: (value) => - settingsService.setMaxRouteWeight(value), - ), - ], - ), - ), - const Divider(height: 1), - ListTile( - title: Text(context.l10n.appSettings_initialRouteWeight), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(context.l10n.appSettings_initialRouteWeightSubtitle), - Slider( - value: settingsService.settings.initialRouteWeight, - min: 0.5, - max: 5.0, - divisions: 9, - label: settingsService.settings.initialRouteWeight - .toStringAsFixed(1), - onChanged: (value) => - settingsService.setInitialRouteWeight(value), - ), - ], - ), - ), - const Divider(height: 1), - ListTile( - title: Text(context.l10n.appSettings_routeWeightSuccessIncrement), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - context - .l10n - .appSettings_routeWeightSuccessIncrementSubtitle, - ), - Slider( - value: settingsService.settings.routeWeightSuccessIncrement, - min: 0.1, - max: 2.0, - divisions: 19, - label: settingsService.settings.routeWeightSuccessIncrement - .toStringAsFixed(1), - onChanged: (value) => - settingsService.setRouteWeightSuccessIncrement(value), - ), - ], - ), - ), - const Divider(height: 1), - ListTile( - title: Text(context.l10n.appSettings_routeWeightFailureDecrement), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - context - .l10n - .appSettings_routeWeightFailureDecrementSubtitle, - ), - Slider( - value: settingsService.settings.routeWeightFailureDecrement, - min: 0.1, - max: 2.0, - divisions: 19, - label: settingsService.settings.routeWeightFailureDecrement - .toStringAsFixed(1), - onChanged: (value) => - settingsService.setRouteWeightFailureDecrement(value), - ), - ], - ), - ), - const Divider(height: 1), - ListTile( - title: Text(context.l10n.appSettings_maxMessageRetries), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(context.l10n.appSettings_maxMessageRetriesSubtitle), - Slider( - value: settingsService.settings.maxMessageRetries - .toDouble(), - min: 2, - max: 10, - divisions: 8, - label: settingsService.settings.maxMessageRetries - .toString(), - onChanged: (value) => - settingsService.setMaxMessageRetries(value.toInt()), - ), - ], - ), - ), - ], - ], - ), - ); - } - Widget _buildMapSettingsCard( BuildContext context, AppSettingsService settingsService, diff --git a/lib/screens/settings/message_settings_view.dart b/lib/screens/settings/message_settings_view.dart new file mode 100644 index 0000000..8ca3820 --- /dev/null +++ b/lib/screens/settings/message_settings_view.dart @@ -0,0 +1,363 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../../l10n/l10n.dart'; +import '../../services/app_settings_service.dart'; +import '../../services/notification_service.dart'; +import '../../helpers/snack_bar_builder.dart'; + +/// Embeddable view (no Scaffold) for the Message Settings shell pane. +/// +/// Renders notification toggles and message-handling settings. Both cards read +/// and write only [AppSettingsService]. +class MessageSettingsView extends StatelessWidget { + const MessageSettingsView({super.key}); + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, settingsService, child) { + return ListView( + padding: const EdgeInsets.all(16), + children: [ + _buildNotificationsCard(context, settingsService), + const SizedBox(height: 16), + _buildMessagingCard(context, settingsService), + ], + ); + }, + ); + } + + Widget _buildNotificationsCard( + BuildContext context, + AppSettingsService settingsService, + ) { + return Card( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), + child: Text( + context.l10n.appSettings_notifications, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + ), + SwitchListTile( + secondary: const Icon(Icons.notifications_outlined), + title: Text(context.l10n.appSettings_enableNotifications), + subtitle: Text( + context.l10n.appSettings_enableNotificationsSubtitle, + ), + value: settingsService.settings.notificationsEnabled, + onChanged: (value) async { + if (value) { + // Request permission when enabling + final granted = await NotificationService() + .requestPermissions(); + if (!granted) { + if (context.mounted) { + showDismissibleSnackBar( + context, + content: Text( + context.l10n.appSettings_notificationPermissionDenied, + ), + duration: const Duration(seconds: 2), + ); + } + return; + } + } + + await settingsService.setNotificationsEnabled(value); + if (context.mounted) { + showDismissibleSnackBar( + context, + content: Text( + value + ? context.l10n.appSettings_notificationsEnabled + : context.l10n.appSettings_notificationsDisabled, + ), + duration: const Duration(seconds: 2), + ); + } + }, + ), + const Divider(height: 1), + SwitchListTile( + secondary: Icon( + Icons.message_outlined, + color: settingsService.settings.notificationsEnabled + ? null + : Colors.grey, + ), + title: Text( + context.l10n.appSettings_messageNotifications, + style: TextStyle( + color: settingsService.settings.notificationsEnabled + ? null + : Colors.grey, + ), + ), + subtitle: Text( + context.l10n.appSettings_messageNotificationsSubtitle, + style: TextStyle( + color: settingsService.settings.notificationsEnabled + ? null + : Colors.grey, + ), + ), + value: settingsService.settings.notifyOnNewMessage, + onChanged: settingsService.settings.notificationsEnabled + ? (value) { + settingsService.setNotifyOnNewMessage(value); + } + : null, + ), + const Divider(height: 1), + SwitchListTile( + secondary: Icon( + Icons.forum_outlined, + color: settingsService.settings.notificationsEnabled + ? null + : Colors.grey, + ), + title: Text( + context.l10n.appSettings_channelMessageNotifications, + style: TextStyle( + color: settingsService.settings.notificationsEnabled + ? null + : Colors.grey, + ), + ), + subtitle: Text( + context.l10n.appSettings_channelMessageNotificationsSubtitle, + style: TextStyle( + color: settingsService.settings.notificationsEnabled + ? null + : Colors.grey, + ), + ), + value: settingsService.settings.notifyOnNewChannelMessage, + onChanged: settingsService.settings.notificationsEnabled + ? (value) { + settingsService.setNotifyOnNewChannelMessage(value); + } + : null, + ), + const Divider(height: 1), + SwitchListTile( + secondary: Icon( + Icons.cell_tower, + color: settingsService.settings.notificationsEnabled + ? null + : Colors.grey, + ), + title: Text( + context.l10n.appSettings_advertisementNotifications, + style: TextStyle( + color: settingsService.settings.notificationsEnabled + ? null + : Colors.grey, + ), + ), + subtitle: Text( + context.l10n.appSettings_advertisementNotificationsSubtitle, + style: TextStyle( + color: settingsService.settings.notificationsEnabled + ? null + : Colors.grey, + ), + ), + value: settingsService.settings.notifyOnNewAdvert, + onChanged: settingsService.settings.notificationsEnabled + ? (value) { + settingsService.setNotifyOnNewAdvert(value); + } + : null, + ), + ], + ), + ); + } + + Widget _buildMessagingCard( + BuildContext context, + AppSettingsService settingsService, + ) { + return Card( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), + child: Text( + context.l10n.appSettings_messaging, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + ), + SwitchListTile( + secondary: const Icon(Icons.refresh_outlined), + title: Text(context.l10n.appSettings_clearPathOnMaxRetry), + subtitle: Text( + context.l10n.appSettings_clearPathOnMaxRetrySubtitle, + ), + value: settingsService.settings.clearPathOnMaxRetry, + onChanged: (value) { + settingsService.setClearPathOnMaxRetry(value); + showDismissibleSnackBar( + context, + content: Text( + value + ? context.l10n.appSettings_pathsWillBeCleared + : context.l10n.appSettings_pathsWillNotBeCleared, + ), + duration: const Duration(seconds: 2), + ); + }, + ), + const Divider(height: 1), + SwitchListTile( + secondary: const Icon(Icons.vertical_align_top), + title: Text(context.l10n.appSettings_jumpToOldestUnread), + subtitle: Text(context.l10n.appSettings_jumpToOldestUnreadSubtitle), + value: settingsService.settings.jumpToOldestUnread, + onChanged: settingsService.setJumpToOldestUnread, + ), + const Divider(height: 1), + SwitchListTile( + secondary: const Icon(Icons.alt_route), + title: Text(context.l10n.appSettings_autoRouteRotation), + subtitle: Text(context.l10n.appSettings_autoRouteRotationSubtitle), + value: settingsService.settings.autoRouteRotationEnabled, + onChanged: (value) { + settingsService.setAutoRouteRotationEnabled(value); + showDismissibleSnackBar( + context, + content: Text( + value + ? context.l10n.appSettings_autoRouteRotationEnabled + : context.l10n.appSettings_autoRouteRotationDisabled, + ), + duration: const Duration(seconds: 2), + ); + }, + ), + if (settingsService.settings.autoRouteRotationEnabled) ...[ + const Divider(height: 1), + ListTile( + title: Text(context.l10n.appSettings_maxRouteWeight), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(context.l10n.appSettings_maxRouteWeightSubtitle), + Slider( + value: settingsService.settings.maxRouteWeight, + min: 1, + max: 10, + divisions: 9, + label: settingsService.settings.maxRouteWeight + .round() + .toString(), + onChanged: (value) => + settingsService.setMaxRouteWeight(value), + ), + ], + ), + ), + const Divider(height: 1), + ListTile( + title: Text(context.l10n.appSettings_initialRouteWeight), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(context.l10n.appSettings_initialRouteWeightSubtitle), + Slider( + value: settingsService.settings.initialRouteWeight, + min: 0.5, + max: 5.0, + divisions: 9, + label: settingsService.settings.initialRouteWeight + .toStringAsFixed(1), + onChanged: (value) => + settingsService.setInitialRouteWeight(value), + ), + ], + ), + ), + const Divider(height: 1), + ListTile( + title: Text(context.l10n.appSettings_routeWeightSuccessIncrement), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context + .l10n + .appSettings_routeWeightSuccessIncrementSubtitle, + ), + Slider( + value: settingsService.settings.routeWeightSuccessIncrement, + min: 0.1, + max: 2.0, + divisions: 19, + label: settingsService.settings.routeWeightSuccessIncrement + .toStringAsFixed(1), + onChanged: (value) => + settingsService.setRouteWeightSuccessIncrement(value), + ), + ], + ), + ), + const Divider(height: 1), + ListTile( + title: Text(context.l10n.appSettings_routeWeightFailureDecrement), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context + .l10n + .appSettings_routeWeightFailureDecrementSubtitle, + ), + Slider( + value: settingsService.settings.routeWeightFailureDecrement, + min: 0.1, + max: 2.0, + divisions: 19, + label: settingsService.settings.routeWeightFailureDecrement + .toStringAsFixed(1), + onChanged: (value) => + settingsService.setRouteWeightFailureDecrement(value), + ), + ], + ), + ), + const Divider(height: 1), + ListTile( + title: Text(context.l10n.appSettings_maxMessageRetries), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(context.l10n.appSettings_maxMessageRetriesSubtitle), + Slider( + value: settingsService.settings.maxMessageRetries + .toDouble(), + min: 2, + max: 10, + divisions: 8, + label: settingsService.settings.maxMessageRetries + .toString(), + onChanged: (value) => + settingsService.setMaxMessageRetries(value.toInt()), + ), + ], + ), + ), + ], + ], + ), + ); + } +} diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index a75f7db..3109913 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -12,7 +12,8 @@ import '../models/radio_settings.dart'; import '../services/app_debug_log_service.dart'; import '../helpers/snack_bar_builder.dart'; import 'settings/settings_shell.dart'; -import 'app_settings_screen.dart'; +import 'settings/app_settings_view.dart'; +import 'settings/message_settings_view.dart'; import 'app_debug_log_screen.dart'; import 'ble_debug_log_screen.dart'; import '../widgets/radio_stats_entry.dart'; @@ -94,6 +95,12 @@ class _SettingsScreenState extends State { subtitle: l10n.settings_contactSettingsSubtitle, builder: _messagesContactsPane, ), + SettingsCategory( + icon: Icons.sms_outlined, + title: l10n.settings_messageSettings, + subtitle: l10n.settings_messageSettingsSubtitle, + builder: _messageSettingsPane, + ), SettingsCategory( icon: Icons.info_outline, title: l10n.settings_deviceInfo, @@ -273,12 +280,10 @@ class _SettingsScreenState extends State { ); } - Widget _appPane(BuildContext context) { - return ListView( - padding: const EdgeInsets.all(16), - children: [_buildAppSettingsCard(context)], - ); - } + Widget _appPane(BuildContext context) => const AppSettingsView(); + + Widget _messageSettingsPane(BuildContext context) => + const MessageSettingsView(); Widget _actionsPane(BuildContext context) { final connector = context.watch(); @@ -444,24 +449,6 @@ class _SettingsScreenState extends State { ); } - Widget _buildAppSettingsCard(BuildContext context) { - final l10n = context.l10n; - return Card( - child: ListTile( - leading: const Icon(Icons.settings_outlined), - title: Text(l10n.settings_appSettings), - subtitle: Text(l10n.settings_appSettingsSubtitle), - trailing: const Icon(Icons.chevron_right), - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => const AppSettingsScreen()), - ); - }, - ), - ); - } - Widget _buildActionsCard(BuildContext context, MeshCoreConnector connector) { final l10n = context.l10n; return Card( diff --git a/untranslated.json b/untranslated.json index 9e26dfe..1818f0c 100644 --- a/untranslated.json +++ b/untranslated.json @@ -1 +1,86 @@ -{} \ No newline at end of file +{ + "bg": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "de": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "es": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "fr": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "hu": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "it": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "ja": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "ko": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "nl": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "pl": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "pt": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "ru": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "sk": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "sl": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "sv": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "uk": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ], + + "zh": [ + "settings_messageSettings", + "settings_messageSettingsSubtitle" + ] +}