Merge pull request #384 from zjs81/clear_toast

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