clear toast on tap

this adds a generator showDismissibleSnackBar which by default allows
tapping to clear snack bar toasts. all SnackBar properties are still
available and the

all callers should now use showDismissibleSnackBar() instead of calling
ScaffoldMessenger.of(context).showSnackBar(SnackBar())
This commit is contained in:
Enot (ded) Skelly
2026-04-14 11:59:18 -07:00
parent 0757c8e53a
commit aa2d0f1927
25 changed files with 526 additions and 494 deletions
+4 -2
View File
@@ -5,6 +5,7 @@ import 'package:provider/provider.dart';
import '../l10n/l10n.dart';
import '../services/app_debug_log_service.dart';
import '../widgets/adaptive_app_bar_title.dart';
import '../helpers/snack_bar_builder.dart';
class AppDebugLogScreen extends StatelessWidget {
const AppDebugLogScreen({super.key});
@@ -34,8 +35,9 @@ class AppDebugLogScreen extends StatelessWidget {
.join('\n');
await Clipboard.setData(ClipboardData(text: text));
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.debugLog_copied)),
showDismissibleSnackBar(
context,
content: Text(context.l10n.debugLog_copied),
);
}
: null,
+54 -56
View File
@@ -10,6 +10,7 @@ import '../services/app_settings_service.dart';
import '../services/notification_service.dart';
import '../services/translation_service.dart';
import '../widgets/adaptive_app_bar_title.dart';
import '../helpers/snack_bar_builder.dart';
import 'map_cache_screen.dart';
class AppSettingsScreen extends StatelessWidget {
@@ -151,13 +152,12 @@ class AppSettingsScreen extends StatelessWidget {
.requestPermissions();
if (!granted) {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context.l10n.appSettings_notificationPermissionDenied,
),
duration: const Duration(seconds: 2),
showDismissibleSnackBar(
context,
content: Text(
context.l10n.appSettings_notificationPermissionDenied,
),
duration: const Duration(seconds: 2),
);
}
return;
@@ -166,15 +166,14 @@ class AppSettingsScreen extends StatelessWidget {
await settingsService.setNotificationsEnabled(value);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
value
? context.l10n.appSettings_notificationsEnabled
: context.l10n.appSettings_notificationsDisabled,
),
duration: const Duration(seconds: 2),
showDismissibleSnackBar(
context,
content: Text(
value
? context.l10n.appSettings_notificationsEnabled
: context.l10n.appSettings_notificationsDisabled,
),
duration: const Duration(seconds: 2),
);
}
},
@@ -301,15 +300,14 @@ class AppSettingsScreen extends StatelessWidget {
value: settingsService.settings.clearPathOnMaxRetry,
onChanged: (value) {
settingsService.setClearPathOnMaxRetry(value);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
value
? context.l10n.appSettings_pathsWillBeCleared
: context.l10n.appSettings_pathsWillNotBeCleared,
),
duration: const Duration(seconds: 2),
showDismissibleSnackBar(
context,
content: Text(
value
? context.l10n.appSettings_pathsWillBeCleared
: context.l10n.appSettings_pathsWillNotBeCleared,
),
duration: const Duration(seconds: 2),
);
},
),
@@ -329,15 +327,14 @@ class AppSettingsScreen extends StatelessWidget {
value: settingsService.settings.autoRouteRotationEnabled,
onChanged: (value) {
settingsService.setAutoRouteRotationEnabled(value);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
value
? context.l10n.appSettings_autoRouteRotationEnabled
: context.l10n.appSettings_autoRouteRotationDisabled,
),
duration: const Duration(seconds: 2),
showDismissibleSnackBar(
context,
content: Text(
value
? context.l10n.appSettings_autoRouteRotationEnabled
: context.l10n.appSettings_autoRouteRotationDisabled,
),
duration: const Duration(seconds: 2),
);
},
),
@@ -1164,8 +1161,9 @@ class AppSettingsScreen extends StatelessWidget {
String? id,
}) async {
if (sourceUrl.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.translation_enterUrlFirst)),
showDismissibleSnackBar(
context,
content: Text(context.l10n.translation_enterUrlFirst),
);
return;
}
@@ -1176,22 +1174,23 @@ class AppSettingsScreen extends StatelessWidget {
id: id,
);
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.translation_modelDownloaded)),
showDismissibleSnackBar(
context,
content: Text(context.l10n.translation_modelDownloaded),
);
await settingsService.setTranslationEnabled(true);
} on TranslationDownloadCancelled {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.translation_downloadStopped)),
showDismissibleSnackBar(
context,
content: Text(context.l10n.translation_downloadStopped),
);
} catch (error) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context.l10n.translation_downloadFailed(error.toString()),
),
showDismissibleSnackBar(
context,
content: Text(
context.l10n.translation_downloadFailed(error.toString()),
),
);
}
@@ -1236,16 +1235,16 @@ class AppSettingsScreen extends StatelessWidget {
try {
await translationService.removeModel(model);
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
// TODO: l10n
content: Text('Deleted ${translationModelFriendlyName(model)}.'),
),
showDismissibleSnackBar(
context,
// TODO: l10n
content: Text('Deleted ${translationModelFriendlyName(model)}.'),
);
} catch (error) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Delete failed: $error')),
showDismissibleSnackBar(
context,
content: Text('Delete failed: $error'),
); // TODO: l10n
}
}
@@ -1279,15 +1278,14 @@ class AppSettingsScreen extends StatelessWidget {
onChanged: (value) async {
await settingsService.setAppDebugLogEnabled(value);
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
value
? context.l10n.appSettings_appDebugLoggingEnabled
: context.l10n.appSettings_appDebugLoggingDisabled,
),
duration: const Duration(seconds: 2),
showDismissibleSnackBar(
context,
content: Text(
value
? context.l10n.appSettings_appDebugLoggingEnabled
: context.l10n.appSettings_appDebugLoggingDisabled,
),
duration: const Duration(seconds: 2),
);
},
),
+4 -4
View File
@@ -5,6 +5,7 @@ import '../l10n/l10n.dart';
import '../services/ble_debug_log_service.dart';
import '../connector/meshcore_protocol.dart';
import '../widgets/adaptive_app_bar_title.dart';
import '../helpers/snack_bar_builder.dart';
enum _BleLogView { frames, rawLogRx }
@@ -52,10 +53,9 @@ class _BleDebugLogScreenState extends State<BleDebugLogScreen> {
.join('\n');
await Clipboard.setData(ClipboardData(text: text));
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.debugLog_bleCopied),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.debugLog_bleCopied),
);
}
: null,
+17 -13
View File
@@ -14,6 +14,7 @@ import '../connector/meshcore_protocol.dart';
import '../helpers/gif_helper.dart';
import '../helpers/reaction_helper.dart';
import '../helpers/utf8_length_limiter.dart';
import '../helpers/snack_bar_builder.dart';
import '../l10n/l10n.dart';
import '../models/channel.dart';
import '../models/channel_message.dart';
@@ -144,11 +145,10 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
Future<void> _scrollToMessage(String messageId) async {
final key = _messageKeys[messageId];
if (key == null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.chat_originalMessageNotFound),
duration: const Duration(seconds: 2),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.chat_originalMessageNotFound),
duration: const Duration(seconds: 2),
);
return;
}
@@ -1151,9 +1151,10 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
final now = DateTime.now();
if (_lastChannelSendAt != null &&
now.difference(_lastChannelSendAt!) < const Duration(seconds: 1)) {
ScaffoldMessenger.of(
showDismissibleSnackBar(
context,
).showSnackBar(SnackBar(content: Text(context.l10n.chat_sendCooldown)));
content: Text(context.l10n.chat_sendCooldown),
);
return;
}
_lastChannelSendAt = now;
@@ -1195,8 +1196,9 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
final maxBytes = maxChannelMessageBytes(connector.selfName);
if (utf8.encode(messageText).length > maxBytes) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.chat_messageTooLong(maxBytes))),
showDismissibleSnackBar(
context,
content: Text(context.l10n.chat_messageTooLong(maxBytes)),
);
return;
}
@@ -1323,17 +1325,19 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
void _copyMessageText(String text) {
Clipboard.setData(ClipboardData(text: text));
ScaffoldMessenger.of(
showDismissibleSnackBar(
context,
).showSnackBar(SnackBar(content: Text(context.l10n.chat_messageCopied)));
content: Text(context.l10n.chat_messageCopied),
);
}
Future<void> _deleteMessage(ChannelMessage message) async {
await context.read<MeshCoreConnector>().deleteChannelMessage(message);
if (!mounted) return;
ScaffoldMessenger.of(
showDismissibleSnackBar(
context,
).showSnackBar(SnackBar(content: Text(context.l10n.chat_messageDeleted)));
content: Text(context.l10n.chat_messageDeleted),
);
}
String _formatPathPrefixes(Uint8List pathBytes) {
+78 -109
View File
@@ -24,6 +24,7 @@ import '../widgets/empty_state.dart';
import '../widgets/qr_code_display.dart';
import '../widgets/quick_switch_bar.dart';
import '../widgets/unread_badge.dart';
import '../helpers/snack_bar_builder.dart';
import 'channel_chat_screen.dart';
import 'community_qr_scanner_screen.dart';
import 'contacts_screen.dart';
@@ -809,15 +810,12 @@ class _ChannelsScreenState extends State<ChannelsScreen>
onPressed: () async {
final name = nameController.text.trim();
if (name.isEmpty) {
ScaffoldMessenger.of(
dialogContext,
).showSnackBar(
SnackBar(
content: Text(
dialogContext
.l10n
.channels_enterChannelName,
),
showDismissibleSnackBar(
context,
content: Text(
dialogContext
.l10n
.channels_enterChannelName,
),
);
return;
@@ -837,13 +835,10 @@ class _ChannelsScreenState extends State<ChannelsScreen>
nextIndex,
);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context.l10n.channels_channelAdded(
name,
),
),
showDismissibleSnackBar(
context,
content: Text(
context.l10n.channels_channelAdded(name),
),
);
}
@@ -897,15 +892,12 @@ class _ChannelsScreenState extends State<ChannelsScreen>
final name = nameController.text.trim();
final pskHex = pskController.text.trim();
if (name.isEmpty) {
ScaffoldMessenger.of(
dialogContext,
).showSnackBar(
SnackBar(
content: Text(
dialogContext
.l10n
.channels_enterChannelName,
),
showDismissibleSnackBar(
context,
content: Text(
dialogContext
.l10n
.channels_enterChannelName,
),
);
return;
@@ -914,15 +906,12 @@ class _ChannelsScreenState extends State<ChannelsScreen>
try {
psk = Channel.parsePskHex(pskHex);
} on FormatException {
ScaffoldMessenger.of(
dialogContext,
).showSnackBar(
SnackBar(
content: Text(
dialogContext
.l10n
.channels_pskMustBe32Hex,
),
showDismissibleSnackBar(
context,
content: Text(
dialogContext
.l10n
.channels_pskMustBe32Hex,
),
);
return;
@@ -930,13 +919,10 @@ class _ChannelsScreenState extends State<ChannelsScreen>
Navigator.pop(dialogContext);
connector.setChannel(nextIndex, name, psk);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context.l10n.channels_channelAdded(
name,
),
),
showDismissibleSnackBar(
context,
content: Text(
context.l10n.channels_channelAdded(name),
),
);
}
@@ -967,11 +953,10 @@ class _ChannelsScreenState extends State<ChannelsScreen>
Navigator.pop(dialogContext);
connector.setChannel(nextIndex, 'Public', psk);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context.l10n.channels_publicChannelAdded,
),
showDismissibleSnackBar(
context,
content: Text(
context.l10n.channels_publicChannelAdded,
),
);
}
@@ -1097,15 +1082,12 @@ class _ChannelsScreenState extends State<ChannelsScreen>
onPressed: () async {
var hashtag = hashtagController.text.trim();
if (hashtag.isEmpty) {
ScaffoldMessenger.of(
dialogContext,
).showSnackBar(
SnackBar(
content: Text(
dialogContext
.l10n
.channels_enterChannelName,
),
showDismissibleSnackBar(
context,
content: Text(
dialogContext
.l10n
.channels_enterChannelName,
),
);
return;
@@ -1125,15 +1107,12 @@ class _ChannelsScreenState extends State<ChannelsScreen>
} else {
// Community hashtag - HMAC derivation from community secret
if (selectedCommunity == null) {
ScaffoldMessenger.of(
showDismissibleSnackBar(
dialogContext,
).showSnackBar(
SnackBar(
content: Text(
dialogContext
.l10n
.community_selectCommunity,
),
content: Text(
dialogContext
.l10n
.community_selectCommunity,
),
);
return;
@@ -1159,12 +1138,11 @@ class _ChannelsScreenState extends State<ChannelsScreen>
psk,
);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context.l10n.channels_channelAdded(
channelName,
),
showDismissibleSnackBar(
context,
content: Text(
context.l10n.channels_channelAdded(
channelName,
),
),
);
@@ -1259,13 +1237,10 @@ class _ChannelsScreenState extends State<ChannelsScreen>
onPressed: () async {
final name = nameController.text.trim();
if (name.isEmpty) {
ScaffoldMessenger.of(
dialogContext,
).showSnackBar(
SnackBar(
content: Text(
dialogContext.l10n.community_enterName,
),
showDismissibleSnackBar(
context,
content: Text(
dialogContext.l10n.community_enterName,
),
);
return;
@@ -1301,11 +1276,10 @@ class _ChannelsScreenState extends State<ChannelsScreen>
_loadCommunities();
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context.l10n.community_created(name),
),
showDismissibleSnackBar(
context,
content: Text(
context.l10n.community_created(name),
),
);
@@ -1494,10 +1468,9 @@ class _ChannelsScreenState extends State<ChannelsScreen>
try {
psk = Channel.parsePskHex(pskHex);
} on FormatException {
ScaffoldMessenger.of(dialogContext).showSnackBar(
SnackBar(
content: Text(dialogContext.l10n.channels_pskMustBe32Hex),
),
showDismissibleSnackBar(
dialogContext,
content: Text(dialogContext.l10n.channels_pskMustBe32Hex),
);
return;
}
@@ -1510,16 +1483,16 @@ class _ChannelsScreenState extends State<ChannelsScreen>
smazEnabled,
);
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.channels_channelUpdated(name)),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.channels_channelUpdated(name)),
);
} catch (e, st) {
debugPrint(st.toString());
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to update channel: $e')),
showDismissibleSnackBar(
context,
content: Text('Failed to update channel: $e'),
);
}
},
@@ -1559,21 +1532,19 @@ class _ChannelsScreenState extends State<ChannelsScreen>
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context.l10n.channels_channelDeleted(channel.name),
),
showDismissibleSnackBar(
context,
content: Text(
context.l10n.channels_channelDeleted(channel.name),
),
);
} catch (e, st) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context.l10n.channels_channelDeleteFailed(channel.name),
),
showDismissibleSnackBar(
context,
content: Text(
context.l10n.channels_channelDeleteFailed(channel.name),
),
);
@@ -1594,8 +1565,9 @@ class _ChannelsScreenState extends State<ChannelsScreen>
void _addPublicChannel(BuildContext context, MeshCoreConnector connector) {
final psk = Channel.parsePskHex(Channel.publicChannelPsk);
connector.setChannel(0, 'Public', psk);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.channels_publicChannelAdded)),
showDismissibleSnackBar(
context,
content: Text(context.l10n.channels_publicChannelAdded),
);
}
@@ -1810,12 +1782,9 @@ class _ChannelsScreenState extends State<ChannelsScreen>
_loadCommunities();
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context.l10n.community_deleted(community.name),
),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.community_deleted(community.name)),
);
}
},
+37 -38
View File
@@ -43,6 +43,7 @@ import '../widgets/radio_stats_entry.dart';
import '../widgets/translated_message_content.dart';
import '../utils/app_logger.dart';
import '../l10n/l10n.dart';
import '../helpers/snack_bar_builder.dart';
import 'telemetry_screen.dart';
class ChatScreen extends StatefulWidget {
@@ -633,9 +634,10 @@ class _ChatScreenState extends State<ChatScreen> {
final now = DateTime.now();
if (_lastTextSendAt != null &&
now.difference(_lastTextSendAt!) < const Duration(seconds: 1)) {
ScaffoldMessenger.of(
showDismissibleSnackBar(
context,
).showSnackBar(SnackBar(content: Text(context.l10n.chat_sendCooldown)));
content: Text(context.l10n.chat_sendCooldown),
);
return;
}
_lastTextSendAt = now;
@@ -671,8 +673,9 @@ class _ChatScreenState extends State<ChatScreen> {
}
final maxBytes = maxContactMessageBytes();
if (utf8.encode(outgoingText).length > maxBytes) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.chat_messageTooLong(maxBytes))),
showDismissibleSnackBar(
context,
content: Text(context.l10n.chat_messageTooLong(maxBytes)),
);
return;
}
@@ -860,15 +863,12 @@ class _ChatScreenState extends State<ChatScreen> {
_showFullPathDialog(context, path.pathBytes),
onTap: () async {
if (path.pathBytes.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context
.l10n
.chat_pathDetailsNotAvailable,
),
duration: const Duration(seconds: 2),
showDismissibleSnackBar(
context,
content: Text(
context.l10n.chat_pathDetailsNotAvailable,
),
duration: const Duration(seconds: 2),
);
return;
}
@@ -952,11 +952,10 @@ class _ChatScreenState extends State<ChatScreen> {
_resolveContact(connector),
);
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.chat_pathCleared),
duration: const Duration(seconds: 2),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.chat_pathCleared),
duration: const Duration(seconds: 2),
);
Navigator.pop(context);
},
@@ -982,11 +981,10 @@ class _ChatScreenState extends State<ChatScreen> {
pathLen: -1,
);
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.chat_floodModeEnabled),
duration: const Duration(seconds: 2),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.chat_floodModeEnabled),
duration: const Duration(seconds: 2),
);
Navigator.pop(context);
},
@@ -1020,11 +1018,10 @@ class _ChatScreenState extends State<ChatScreen> {
void _showFullPathDialog(BuildContext context, List<int> pathBytes) {
if (pathBytes.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.chat_pathDetailsNotAvailable),
duration: const Duration(seconds: 2),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.chat_pathDetailsNotAvailable),
duration: const Duration(seconds: 2),
);
return;
}
@@ -1137,11 +1134,10 @@ class _ChatScreenState extends State<ChatScreen> {
: (verified
? context.l10n.chat_pathDeviceConfirmed
: context.l10n.chat_pathDeviceNotConfirmed);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.chat_pathSetHops(hopCount, status)),
duration: const Duration(seconds: 3),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.chat_pathSetHops(hopCount, status)),
duration: const Duration(seconds: 3),
);
}
@@ -1490,26 +1486,29 @@ class _ChatScreenState extends State<ChatScreen> {
void _copyMessageText(String text) {
Clipboard.setData(ClipboardData(text: text));
ScaffoldMessenger.of(
showDismissibleSnackBar(
context,
).showSnackBar(SnackBar(content: Text(context.l10n.chat_messageCopied)));
content: Text(context.l10n.chat_messageCopied),
);
}
Future<void> _deleteMessage(Message message) async {
await context.read<MeshCoreConnector>().deleteMessage(message);
if (!mounted) return;
ScaffoldMessenger.of(
showDismissibleSnackBar(
context,
).showSnackBar(SnackBar(content: Text(context.l10n.chat_messageDeleted)));
content: Text(context.l10n.chat_messageDeleted),
);
}
void _retryMessage(Message message) {
final connector = Provider.of<MeshCoreConnector>(context, listen: false);
// Retry using the contact's current path override setting
connector.sendMessage(_resolveContact(connector), message.text);
ScaffoldMessenger.of(
showDismissibleSnackBar(
context,
).showSnackBar(SnackBar(content: Text(context.l10n.chat_retryingMessage)));
content: Text(context.l10n.chat_retryingMessage),
);
}
void _showEmojiPicker(Message message, Contact senderContact) {
+14 -16
View File
@@ -8,6 +8,7 @@ import '../models/community.dart';
import '../storage/community_store.dart';
import '../widgets/adaptive_app_bar_title.dart';
import '../widgets/qr_scanner_widget.dart';
import '../helpers/snack_bar_builder.dart';
/// Screen for scanning community QR codes to join communities.
///
@@ -76,11 +77,10 @@ class _CommunityQrScannerScreenState extends State<CommunityQrScannerScreen> {
}
} catch (e) {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.community_invalidQrCode),
backgroundColor: Colors.red,
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.community_invalidQrCode),
backgroundColor: Colors.red,
);
}
} finally {
@@ -93,12 +93,11 @@ class _CommunityQrScannerScreenState extends State<CommunityQrScannerScreen> {
}
void _showInvalidQrError(BuildContext context) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.community_invalidQrCode),
backgroundColor: Colors.orange,
duration: const Duration(seconds: 2),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.community_invalidQrCode),
backgroundColor: Colors.orange,
duration: const Duration(seconds: 2),
);
}
@@ -229,11 +228,10 @@ class _CommunityQrScannerScreenState extends State<CommunityQrScannerScreen> {
}
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.community_joined(community.name)),
backgroundColor: Colors.green,
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.community_joined(community.name)),
backgroundColor: Colors.green,
);
// Return to previous screen
+50 -55
View File
@@ -27,6 +27,7 @@ import '../widgets/quick_switch_bar.dart';
import '../widgets/repeater_login_dialog.dart';
import '../widgets/room_login_dialog.dart';
import '../widgets/unread_badge.dart';
import '../helpers/snack_bar_builder.dart';
import 'channels_screen.dart';
import 'chat_screen.dart';
import 'discovery_screen.dart';
@@ -150,9 +151,10 @@ class _ContactsScreenState extends State<ContactsScreen>
}
void _showGroupsUnavailableMessage(BuildContext context) {
ScaffoldMessenger.of(
showDismissibleSnackBar(
context,
).showSnackBar(SnackBar(content: Text(context.l10n.common_loading)));
content: Text(context.l10n.common_loading),
);
}
void _setupFrameListener() {
@@ -169,10 +171,9 @@ class _ContactsScreenState extends State<ContactsScreen>
// Validate packet has expected minimum size (98+ bytes per protocol)
if (advertPacket.length < 98) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.contacts_invalidAdvertFormat),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.contacts_invalidAdvertFormat),
);
}
_pendingOperations.remove(ContactOperationType.export);
@@ -187,24 +188,23 @@ class _ContactsScreenState extends State<ContactsScreen>
if (!mounted) return;
if (_pendingOperations.contains(ContactOperationType.import)) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.contacts_contactImported)),
showDismissibleSnackBar(
context,
content: Text(context.l10n.contacts_contactImported),
);
}
if (_pendingOperations.contains(ContactOperationType.zeroHopShare)) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.contacts_zeroHopContactAdvertSent),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.contacts_zeroHopContactAdvertSent),
);
}
if (_pendingOperations.contains(ContactOperationType.export)) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.contacts_contactAdvertCopied),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.contacts_contactAdvertCopied),
);
}
@@ -216,25 +216,22 @@ class _ContactsScreenState extends State<ContactsScreen>
if (!mounted) return;
if (_pendingOperations.contains(ContactOperationType.import)) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.contacts_contactImportFailed),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.contacts_contactImportFailed),
);
}
if (_pendingOperations.contains(ContactOperationType.zeroHopShare)) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.contacts_zeroHopContactAdvertFailed),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.contacts_zeroHopContactAdvertFailed),
);
}
if (_pendingOperations.contains(ContactOperationType.export)) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.contacts_contactAdvertCopyFailed),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.contacts_contactAdvertCopyFailed),
);
}
@@ -271,8 +268,9 @@ class _ContactsScreenState extends State<ContactsScreen>
final clipboardData = await Clipboard.getData('text/plain');
if (clipboardData == null || clipboardData.text == null) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.contacts_clipboardEmpty)),
showDismissibleSnackBar(
context,
content: Text(context.l10n.contacts_clipboardEmpty),
);
}
return;
@@ -280,8 +278,9 @@ class _ContactsScreenState extends State<ContactsScreen>
final text = clipboardData.text!.trim();
if (!text.startsWith('meshcore://')) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.contacts_invalidAdvertFormat)),
showDismissibleSnackBar(
context,
content: Text(context.l10n.contacts_invalidAdvertFormat),
);
}
return;
@@ -294,8 +293,9 @@ class _ContactsScreenState extends State<ContactsScreen>
connector.importContact(importContactFrame);
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.contacts_invalidAdvertFormat)),
showDismissibleSnackBar(
context,
content: Text(context.l10n.contacts_invalidAdvertFormat),
);
}
}
@@ -330,10 +330,9 @@ class _ContactsScreenState extends State<ContactsScreen>
),
onTap: () => {
connector.sendSelfAdvert(flood: false),
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.settings_advertisementSent),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.settings_advertisementSent),
),
},
),
@@ -347,10 +346,9 @@ class _ContactsScreenState extends State<ContactsScreen>
),
onTap: () => {
connector.sendSelfAdvert(flood: true),
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.settings_advertisementSent),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.settings_advertisementSent),
),
},
),
@@ -1146,19 +1144,17 @@ class _ContactsScreenState extends State<ContactsScreen>
onPressed: () async {
final name = nameController.text.trim();
if (name.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.contacts_groupNameRequired),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.contacts_groupNameRequired),
);
return;
}
if (name.toLowerCase() ==
contactsAllGroupsValue.toLowerCase()) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.contacts_groupNameReserved),
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.contacts_groupNameReserved),
);
return;
}
@@ -1167,11 +1163,10 @@ class _ContactsScreenState extends State<ContactsScreen>
return g.name.toLowerCase() == name.toLowerCase();
});
if (exists) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context.l10n.contacts_groupAlreadyExists(name),
),
showDismissibleSnackBar(
context,
content: Text(
context.l10n.contacts_groupAlreadyExists(name),
),
);
return;
+4 -2
View File
@@ -12,6 +12,7 @@ import '../utils/contact_search.dart';
import '../utils/platform_info.dart';
import '../widgets/app_bar.dart';
import '../widgets/list_filter_widget.dart';
import '../helpers/snack_bar_builder.dart';
enum DiscoverySortOption { lastSeen, name, type }
@@ -234,8 +235,9 @@ class _DiscoveryScreenState extends State<DiscoveryScreen> {
final hexString = pubKeyToHex(contact.rawPacket!);
Clipboard.setData(ClipboardData(text: "meshcore://$hexString"));
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.contacts_contactAdvertCopied)),
showDismissibleSnackBar(
context,
content: Text(context.l10n.contacts_contactAdvertCopied),
);
break;
case 'delete_contact':
+11 -9
View File
@@ -8,6 +8,7 @@ import '../l10n/l10n.dart';
import '../services/app_settings_service.dart';
import '../services/map_tile_cache_service.dart';
import '../widgets/adaptive_app_bar_title.dart';
import '../helpers/snack_bar_builder.dart';
class MapCacheScreen extends StatefulWidget {
const MapCacheScreen({super.key});
@@ -112,15 +113,17 @@ class _MapCacheScreenState extends State<MapCacheScreen> {
Future<void> _startDownload() async {
final bounds = _selectedBounds;
if (bounds == null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.mapCache_selectAreaFirst)),
showDismissibleSnackBar(
context,
content: Text(context.l10n.mapCache_selectAreaFirst),
);
return;
}
if (_estimatedTiles == 0) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.mapCache_noTilesToDownload)),
showDismissibleSnackBar(
context,
content: Text(context.l10n.mapCache_noTilesToDownload),
);
return;
}
@@ -182,9 +185,7 @@ class _MapCacheScreenState extends State<MapCacheScreen> {
result.failed,
)
: context.l10n.mapCache_cachedTiles(result.downloaded);
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(message)));
showDismissibleSnackBar(context, content: Text(message));
}
Future<void> _clearCache() async {
@@ -210,8 +211,9 @@ class _MapCacheScreenState extends State<MapCacheScreen> {
final cacheService = context.read<MapTileCacheService>();
await cacheService.clearCache();
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.mapCache_offlineCacheCleared)),
showDismissibleSnackBar(
context,
content: Text(context.l10n.mapCache_offlineCacheCleared),
);
}
+11 -5
View File
@@ -29,6 +29,7 @@ import 'chat_screen.dart';
import 'contacts_screen.dart';
import '../widgets/repeater_login_dialog.dart';
import '../widgets/room_login_dialog.dart';
import '../helpers/snack_bar_builder.dart';
import 'repeater_hub_screen.dart';
import 'settings_screen.dart';
import 'line_of_sight_map_screen.dart';
@@ -1659,7 +1660,10 @@ class _MapScreenState extends State<MapScreen> {
);
await connector.refreshDeviceInfo();
if (!mounted) return;
messenger.showSnackBar(SnackBar(content: Text(successMsg)));
showDismissibleSnackBar(
messenger.context,
content: Text(successMsg),
);
},
),
ListTile(
@@ -1681,8 +1685,9 @@ class _MapScreenState extends State<MapScreen> {
required String flags,
}) async {
if (!connector.isConnected) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.map_connectToShareMarkers)),
showDismissibleSnackBar(
context,
content: Text(context.l10n.map_connectToShareMarkers),
);
return;
}
@@ -2271,8 +2276,9 @@ class _MapScreenState extends State<MapScreen> {
_points.clear();
_polylines.clear();
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.map_pathTraceCancelled)),
showDismissibleSnackBar(
context,
content: Text(l10n.map_pathTraceCancelled),
);
},
tooltip: l10n.common_cancel,
+13 -15
View File
@@ -11,6 +11,7 @@ import '../connector/meshcore_protocol.dart';
import '../services/repeater_command_service.dart';
import '../widgets/path_management_dialog.dart';
import '../widgets/snr_indicator.dart';
import '../helpers/snack_bar_builder.dart';
class NeighborsScreen extends StatefulWidget {
final Contact repeater;
@@ -163,11 +164,10 @@ class _NeighborsScreenState extends State<NeighborsScreen> {
_neighborCount = neighborCount;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.neighbors_receivedData),
backgroundColor: Colors.green,
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.neighbors_receivedData),
backgroundColor: Colors.green,
);
_statusTimeout?.cancel();
if (!mounted) return;
@@ -224,11 +224,10 @@ class _NeighborsScreenState extends State<NeighborsScreen> {
_isLoading = false;
_isLoaded = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.neighbors_requestTimedOut),
backgroundColor: Colors.red,
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.neighbors_requestTimedOut),
backgroundColor: Colors.red,
);
_recordStatusResult(false);
});
@@ -239,11 +238,10 @@ class _NeighborsScreenState extends State<NeighborsScreen> {
_isLoaded = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.neighbors_errorLoading(e.toString())),
backgroundColor: Colors.red,
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.neighbors_errorLoading(e.toString())),
backgroundColor: Colors.red,
);
}
}
+4 -2
View File
@@ -9,6 +9,7 @@ import '../connector/meshcore_protocol.dart';
import '../widgets/debug_frame_viewer.dart';
import '../services/repeater_command_service.dart';
import '../widgets/path_management_dialog.dart';
import '../helpers/snack_bar_builder.dart';
class RepeaterCliScreen extends StatefulWidget {
final Contact repeater;
@@ -336,8 +337,9 @@ class _RepeaterCliScreenState extends State<RepeaterCliScreen> {
if (_commandController.text.trim().isNotEmpty) {
_sendCommand(showDebug: true);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.repeater_enterCommandFirst)),
showDismissibleSnackBar(
context,
content: Text(l10n.repeater_enterCommandFirst),
);
}
},
+28 -30
View File
@@ -10,6 +10,7 @@ import '../services/app_debug_log_service.dart';
import '../services/repeater_command_service.dart';
import '../services/storage_service.dart';
import '../widgets/path_management_dialog.dart';
import '../helpers/snack_bar_builder.dart';
class RepeaterSettingsScreen extends StatefulWidget {
final Contact repeater;
@@ -468,18 +469,16 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
if (mounted) {
if (successCount > 0) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(l10n.repeater_refreshed(label)),
backgroundColor: Colors.green,
),
showDismissibleSnackBar(
context,
content: Text(l10n.repeater_refreshed(label)),
backgroundColor: Colors.green,
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(l10n.repeater_errorRefreshing(label)),
backgroundColor: Colors.red,
),
showDismissibleSnackBar(
context,
content: Text(l10n.repeater_errorRefreshing(label)),
backgroundColor: Colors.red,
);
}
@@ -666,11 +665,10 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
});
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.repeater_settingsSaved),
backgroundColor: Colors.green,
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.repeater_settingsSaved),
backgroundColor: Colors.green,
);
}
} catch (e) {
@@ -679,13 +677,12 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
});
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context.l10n.repeater_errorSavingSettings(e.toString()),
),
backgroundColor: Colors.red,
showDismissibleSnackBar(
context,
content: Text(
context.l10n.repeater_errorSavingSettings(e.toString()),
),
backgroundColor: Colors.red,
);
}
}
@@ -1429,9 +1426,10 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
if (command == 'erase') {
if (mounted) {
ScaffoldMessenger.of(
showDismissibleSnackBar(
context,
).showSnackBar(SnackBar(content: Text(l10n.repeater_eraseSerialOnly)));
content: Text(l10n.repeater_eraseSerialOnly),
);
}
return;
}
@@ -1453,17 +1451,17 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
await connector.sendFrame(frame);
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.repeater_commandSent(command))),
showDismissibleSnackBar(
context,
content: Text(l10n.repeater_commandSent(command)),
);
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(l10n.repeater_errorSendingCommand(e.toString())),
backgroundColor: Colors.red,
),
showDismissibleSnackBar(
context,
content: Text(l10n.repeater_errorSendingCommand(e.toString())),
backgroundColor: Colors.red,
);
}
}
+9 -12
View File
@@ -12,6 +12,7 @@ import '../services/app_settings_service.dart';
import '../services/repeater_command_service.dart';
import '../utils/battery_utils.dart';
import '../widgets/path_management_dialog.dart';
import '../helpers/snack_bar_builder.dart';
class RepeaterStatusScreen extends StatefulWidget {
final Contact repeater;
@@ -309,11 +310,10 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
setState(() {
_isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.repeater_statusRequestTimeout),
backgroundColor: Colors.red,
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.repeater_statusRequestTimeout),
backgroundColor: Colors.red,
);
_recordStatusResult(false);
});
@@ -323,13 +323,10 @@ class _RepeaterStatusScreenState extends State<RepeaterStatusScreen> {
_isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context.l10n.repeater_errorLoadingStatus(e.toString()),
),
backgroundColor: Colors.red,
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.repeater_errorLoadingStatus(e.toString())),
backgroundColor: Colors.red,
);
}
_recordStatusResult(false);
+5 -5
View File
@@ -10,6 +10,7 @@ import '../services/linux_ble_error_classifier.dart';
import '../utils/app_logger.dart';
import '../widgets/adaptive_app_bar_title.dart';
import '../widgets/device_tile.dart';
import '../helpers/snack_bar_builder.dart';
import 'contacts_screen.dart';
import 'tcp_screen.dart';
import 'usb_screen.dart';
@@ -317,11 +318,10 @@ class _ScannerScreenState extends State<ScannerScreen> {
return;
}
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.scanner_connectionFailed(e.toString())),
backgroundColor: Colors.red,
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.scanner_connectionFailed(e.toString())),
backgroundColor: Colors.red,
);
}
}
+52 -38
View File
@@ -11,6 +11,7 @@ import '../l10n/l10n.dart';
import '../models/radio_settings.dart';
import '../services/app_debug_log_service.dart';
import '../widgets/app_bar.dart';
import '../helpers/snack_bar_builder.dart';
import 'app_settings_screen.dart';
import 'app_debug_log_screen.dart';
import 'ble_debug_log_screen.dart';
@@ -513,8 +514,9 @@ class _SettingsScreenState extends State<SettingsScreen> {
await connector.setNodeName(controller.text);
await connector.refreshDeviceInfo();
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.settings_nodeNameUpdated)),
showDismissibleSnackBar(
context,
content: Text(l10n.settings_nodeNameUpdated),
);
},
child: Text(l10n.common_save),
@@ -628,10 +630,9 @@ class _SettingsScreenState extends State<SettingsScreen> {
final interval = int.tryParse(intervalText);
if (interval == null || interval < 60 || interval >= 86400) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(l10n.settings_locationIntervalInvalid),
),
showDismissibleSnackBar(
context,
content: Text(l10n.settings_locationIntervalInvalid),
);
return;
}
@@ -639,8 +640,9 @@ class _SettingsScreenState extends State<SettingsScreen> {
await connector.setCustomVar("gps_interval:$interval");
await connector.refreshDeviceInfo();
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.settings_locationUpdated)),
showDismissibleSnackBar(
context,
content: Text(l10n.settings_locationUpdated),
);
}
@@ -660,15 +662,17 @@ class _SettingsScreenState extends State<SettingsScreen> {
: currentLon;
if (lat == null || lon == null) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.settings_locationBothRequired)),
showDismissibleSnackBar(
context,
content: Text(l10n.settings_locationBothRequired),
);
return;
}
if (lat < -90 || lat > 90 || lon < -180 || lon > 180) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.settings_locationInvalid)),
showDismissibleSnackBar(
context,
content: Text(l10n.settings_locationInvalid),
);
return;
}
@@ -676,8 +680,9 @@ class _SettingsScreenState extends State<SettingsScreen> {
await connector.setNodeLocation(lat: lat, lon: lon);
await connector.refreshDeviceInfo();
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.settings_locationUpdated)),
showDismissibleSnackBar(
context,
content: Text(l10n.settings_locationUpdated),
);
},
child: Text(l10n.common_save),
@@ -691,9 +696,10 @@ class _SettingsScreenState extends State<SettingsScreen> {
void _syncTime(BuildContext context, MeshCoreConnector connector) {
final l10n = context.l10n;
connector.syncTime();
ScaffoldMessenger.of(
showDismissibleSnackBar(
context,
).showSnackBar(SnackBar(content: Text(l10n.settings_timeSynchronized)));
content: Text(l10n.settings_timeSynchronized),
);
}
void _confirmReboot(BuildContext context, MeshCoreConnector connector) {
@@ -758,23 +764,27 @@ class _SettingsScreenState extends State<SettingsScreen> {
if (!mounted) return;
switch (result) {
case gpxExportSuccess:
ScaffoldMessenger.of(
showDismissibleSnackBar(
context,
).showSnackBar(SnackBar(content: Text(l10n.settings_gpxExportSuccess)));
content: Text(l10n.settings_gpxExportSuccess),
);
case gpxExportNoContacts:
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.settings_gpxExportNoContacts)),
showDismissibleSnackBar(
context,
content: Text(l10n.settings_gpxExportNoContacts),
);
break;
case gpxExportNotAvailable:
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.settings_gpxExportNotAvailable)),
showDismissibleSnackBar(
context,
content: Text(l10n.settings_gpxExportNotAvailable),
);
break;
case gpxExportFailed:
ScaffoldMessenger.of(
showDismissibleSnackBar(
context,
).showSnackBar(SnackBar(content: Text(l10n.settings_gpxExportError)));
content: Text(l10n.settings_gpxExportError),
);
break;
}
}
@@ -1077,8 +1087,9 @@ void _privacySettings(BuildContext context, MeshCoreConnector connector) {
);
await connector.refreshDeviceInfo();
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.settings_telemetryModeUpdated)),
showDismissibleSnackBar(
context,
content: Text(l10n.settings_telemetryModeUpdated),
);
},
child: Text(l10n.common_save),
@@ -1410,18 +1421,18 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> {
final txPower = int.tryParse(_txPowerController.text);
if (freqMHz == null || freqMHz < 300 || freqMHz > 2500) {
ScaffoldMessenger.of(
showDismissibleSnackBar(
context,
).showSnackBar(SnackBar(content: Text(l10n.settings_frequencyInvalid)));
content: Text(l10n.settings_frequencyInvalid),
);
return;
}
final maxTxPower = widget.connector.maxTxPower ?? 22;
if (txPower == null || txPower < 0 || txPower > maxTxPower) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('${l10n.settings_txPowerInvalid} (0-$maxTxPower dBm)'),
),
showDismissibleSnackBar(
context,
content: Text('${l10n.settings_txPowerInvalid} (0-$maxTxPower dBm)'),
);
return;
}
@@ -1441,8 +1452,9 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> {
if (knownRepeat) {
const validRepeatFreqsKHz = {433000, 869000, 918000};
if (_clientRepeat && !validRepeatFreqsKHz.contains(freqHz)) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.settings_clientRepeatFreqWarning)),
showDismissibleSnackBar(
context,
content: Text(l10n.settings_clientRepeatFreqWarning),
);
return;
}
@@ -1472,14 +1484,16 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> {
if (!mounted) return;
_logRadioSettingsState('Radio settings saved successfully');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.settings_radioSettingsUpdated)),
showDismissibleSnackBar(
context,
content: Text(l10n.settings_radioSettingsUpdated),
);
} catch (e) {
_appLog.warn('Radio settings save failed: $e', tag: 'RadioSettings');
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.settings_error(e.toString()))),
showDismissibleSnackBar(
context,
content: Text(l10n.settings_error(e.toString())),
);
}
Navigator.pop(context);
+5 -2
View File
@@ -8,6 +8,7 @@ import '../l10n/l10n.dart';
import '../services/app_settings_service.dart';
import '../utils/platform_info.dart';
import '../widgets/adaptive_app_bar_title.dart';
import '../helpers/snack_bar_builder.dart';
import 'contacts_screen.dart';
import 'usb_screen.dart';
@@ -270,8 +271,10 @@ class _TcpScreenState extends State<TcpScreen> {
void _showError(String message) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message), backgroundColor: Colors.red),
showDismissibleSnackBar(
context,
content: Text(message),
backgroundColor: Colors.red,
);
}
+13 -15
View File
@@ -14,6 +14,7 @@ import '../utils/app_logger.dart';
import '../widgets/path_management_dialog.dart';
import '../helpers/cayenne_lpp.dart';
import '../utils/battery_utils.dart';
import '../helpers/snack_bar_builder.dart';
class TelemetryScreen extends StatefulWidget {
final Contact contact;
@@ -86,11 +87,10 @@ class _TelemetryScreenState extends State<TelemetryScreen> {
_isLoading = false;
_isLoaded = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.telemetry_requestTimeout),
backgroundColor: Colors.red,
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.telemetry_requestTimeout),
backgroundColor: Colors.red,
);
_recordTelemetryResult(false);
});
@@ -137,11 +137,10 @@ class _TelemetryScreenState extends State<TelemetryScreen> {
_parsedTelemetry = parsedTelemetry;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.telemetry_receivedData),
backgroundColor: Colors.green,
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.telemetry_receivedData),
backgroundColor: Colors.green,
);
_statusTimeout?.cancel();
if (!mounted) return;
@@ -182,11 +181,10 @@ class _TelemetryScreenState extends State<TelemetryScreen> {
_isLoaded = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.telemetry_errorLoading(e.toString())),
backgroundColor: Colors.red,
),
showDismissibleSnackBar(
context,
content: Text(context.l10n.telemetry_errorLoading(e.toString())),
backgroundColor: Colors.red,
);
}
}
+5 -5
View File
@@ -10,6 +10,7 @@ import '../utils/app_logger.dart';
import '../utils/platform_info.dart';
import '../utils/usb_port_labels.dart';
import '../widgets/adaptive_app_bar_title.dart';
import '../helpers/snack_bar_builder.dart';
import 'contacts_screen.dart';
import 'scanner_screen.dart';
import 'tcp_screen.dart';
@@ -383,11 +384,10 @@ class _UsbScreenState extends State<UsbScreen> {
void _showError(Object error) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(_friendlyErrorMessage(error)),
backgroundColor: Colors.red,
),
showDismissibleSnackBar(
context,
content: Text(_friendlyErrorMessage(error)),
backgroundColor: Colors.red,
);
}