fix: Update import path for AppLocalizations in CompassSarList widget

This commit is contained in:
Janez T
2025-10-16 16:07:22 +02:00
parent 01a1bbec44
commit f95edcb477
21 changed files with 2055 additions and 91 deletions

View File

@@ -2,6 +2,7 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:geolocator/geolocator.dart';
import '../l10n/app_localizations.dart';
import '../providers/contacts_provider.dart';
import '../providers/app_provider.dart';
import '../widgets/contacts/contact_tile.dart';
@@ -85,6 +86,7 @@ class _ContactsTabState extends State<ContactsTab> {
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Consumer<ContactsProvider>(
builder: (context, contactsProvider, child) {
final chatContacts = contactsProvider.chatContacts;
@@ -103,12 +105,12 @@ class _ContactsTabState extends State<ContactsTab> {
),
const SizedBox(height: 16),
Text(
'No contacts yet',
l10n.noContactsYet,
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
Text(
'Connect to a device to load contacts',
l10n.connectToDeviceToLoadContacts,
style: Theme.of(context).textTheme.bodyMedium,
textAlign: TextAlign.center,
),
@@ -125,7 +127,7 @@ class _ContactsTabState extends State<ContactsTab> {
// Team Members (Chat contacts)
if (chatContacts.isNotEmpty) ...[
_SectionHeader(
title: 'Team Members',
title: l10n.teamMembers,
count: chatContacts.length,
icon: Icons.people,
),
@@ -143,7 +145,7 @@ class _ContactsTabState extends State<ContactsTab> {
// Repeaters
if (repeaters.isNotEmpty) ...[
_SectionHeader(
title: 'Repeaters',
title: l10n.repeaters,
count: repeaters.length,
icon: Icons.router,
),
@@ -161,7 +163,7 @@ class _ContactsTabState extends State<ContactsTab> {
// Rooms/Channels
if (rooms.isNotEmpty) ...[
_SectionHeader(
title: 'Rooms',
title: l10n.rooms,
count: rooms.length,
icon: Icons.tag,
),

View File

@@ -101,7 +101,7 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
} catch (e) {
if (!mounted) return;
setState(() {
_statusMessage = 'Error loading stats: $e';
_statusMessage = AppLocalizations.of(context)!.errorLoadingStats(e.toString());
_isLoading = false;
});
}
@@ -133,18 +133,18 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
// Validate zoom levels
final minZoomResult = validator.validateZoomLevel(_minZoom);
if (!minZoomResult.isValid) {
_showError('Min zoom: ${minZoomResult.errorMessage}');
_showError(AppLocalizations.of(context)!.minZoomError(minZoomResult.errorMessage!));
return;
}
final maxZoomResult = validator.validateZoomLevel(_maxZoom);
if (!maxZoomResult.isValid) {
_showError('Max zoom: ${maxZoomResult.errorMessage}');
_showError(AppLocalizations.of(context)!.maxZoomError(maxZoomResult.errorMessage!));
return;
}
if (_minZoom > _maxZoom) {
_showError('Minimum zoom must be less than or equal to maximum zoom');
_showError(AppLocalizations.of(context)!.minZoomGreaterThanMax);
return;
}
@@ -157,7 +157,7 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
setState(() {
_isDownloading = true;
_downloadProgress = 0.0;
_statusMessage = 'Starting download...';
_statusMessage = AppLocalizations.of(context)!.startingDownload;
});
await widget.tileCacheService.downloadRegion(
@@ -170,7 +170,7 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
if (!mounted) return;
setState(() {
_downloadProgress = progress;
_statusMessage = 'Downloading map tiles...';
_statusMessage = AppLocalizations.of(context)!.downloadingMapTiles;
});
},
);
@@ -178,15 +178,15 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
if (!mounted) return;
setState(() {
_isDownloading = false;
_statusMessage = 'Download completed successfully!';
_statusMessage = AppLocalizations.of(context)!.downloadCompletedSuccessfully;
});
await _loadCacheStats();
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Map download completed!'),
SnackBar(
content: Text(AppLocalizations.of(context)!.mapDownloadCompleted),
backgroundColor: Colors.green,
),
);
@@ -195,23 +195,23 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
if (!mounted) return;
setState(() {
_isDownloading = false;
_statusMessage = 'Download failed: $e';
_statusMessage = AppLocalizations.of(context)!.downloadFailed(e.toString());
});
_showError('Download failed: $e');
_showError(AppLocalizations.of(context)!.downloadFailed(e.toString()));
}
}
Future<void> _cancelDownload() async {
try {
if (!mounted) return;
setState(() => _statusMessage = 'Cancelling download...');
setState(() => _statusMessage = AppLocalizations.of(context)!.cancellingDownload);
await widget.tileCacheService.cancelDownload();
if (!mounted) return;
setState(() {
_isDownloading = false;
_statusMessage = 'Download cancelled';
_statusMessage = AppLocalizations.of(context)!.downloadCancelled;
});
await _loadCacheStats();
@@ -228,9 +228,9 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
if (!mounted) return;
setState(() {
_isDownloading = false;
_statusMessage = 'Cancel failed: $e';
_statusMessage = AppLocalizations.of(context)!.cancelFailed(e.toString());
});
_showError('Cancel failed: $e');
_showError(AppLocalizations.of(context)!.cancelFailed(e.toString()));
}
}
@@ -238,9 +238,9 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
final confirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text(AppLocalizations.of(context)!.clear),
content: const Text(
'Are you sure you want to delete all downloaded maps? This action cannot be undone.',
title: Text(AppLocalizations.of(context)!.clearMapsConfirmTitle),
content: Text(
AppLocalizations.of(context)!.clearMapsConfirmMessage,
),
actions: [
TextButton(
@@ -268,15 +268,15 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Cache cleared successfully!'),
SnackBar(
content: Text(AppLocalizations.of(context)!.cacheClearedSuccessfully),
backgroundColor: Colors.green,
),
);
}
} catch (e) {
setState(() => _isLoading = false);
_showError('Clear cache failed: $e');
_showError(AppLocalizations.of(context)!.clearCacheFailed(e.toString()));
}
}
@@ -332,7 +332,7 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Cache Statistics',
AppLocalizations.of(context)!.cacheStatistics,
style: Theme.of(context).textTheme.titleLarge,
),
IconButton(
@@ -344,22 +344,22 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
const SizedBox(height: 16),
if (_cacheStats != null) ...[
_buildStatRow(
'Total Tiles',
AppLocalizations.of(context)!.totalTiles,
'${_cacheStats!['tileCount'] ?? 0}',
Icons.grid_on,
),
_buildStatRow(
'Cache Size',
AppLocalizations.of(context)!.cacheSize,
'${(_cacheStats!['sizeMB'] ?? 0.0).toStringAsFixed(2)} MB',
Icons.storage,
),
_buildStatRow(
'Store Name',
AppLocalizations.of(context)!.storeName,
_cacheStats!['storeName'] ?? 'Unknown',
Icons.folder,
),
] else
const Text('No cache statistics available'),
Text(AppLocalizations.of(context)!.noCacheStatistics),
],
),
),
@@ -390,7 +390,7 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Download Region',
AppLocalizations.of(context)!.downloadRegion,
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 16),
@@ -398,14 +398,14 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
// Map Layer Selection
DropdownButtonFormField<MapLayer>(
value: _selectedLayer,
decoration: const InputDecoration(
labelText: 'Map Layer',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context)!.mapLayer,
border: const OutlineInputBorder(),
),
items: MapLayer.allLayers.map((layer) {
return DropdownMenuItem(
value: layer,
child: Text(layer.name),
child: Text(layer.getLocalizedName(context)),
);
}).toList(),
onChanged: _isDownloading ? null : (layer) {
@@ -418,7 +418,7 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
// Coordinates
Text(
'Region Bounds',
AppLocalizations.of(context)!.regionBounds,
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
@@ -427,9 +427,9 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
Expanded(
child: TextField(
controller: _northController,
decoration: const InputDecoration(
labelText: 'North',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context)!.north,
border: const OutlineInputBorder(),
hintText: '46.1',
),
keyboardType: const TextInputType.numberWithOptions(decimal: true),
@@ -440,9 +440,9 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
Expanded(
child: TextField(
controller: _southController,
decoration: const InputDecoration(
labelText: 'South',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context)!.south,
border: const OutlineInputBorder(),
hintText: '46.0',
),
keyboardType: const TextInputType.numberWithOptions(decimal: true),
@@ -457,9 +457,9 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
Expanded(
child: TextField(
controller: _eastController,
decoration: const InputDecoration(
labelText: 'East',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context)!.east,
border: const OutlineInputBorder(),
hintText: '14.6',
),
keyboardType: const TextInputType.numberWithOptions(decimal: true),
@@ -470,9 +470,9 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
Expanded(
child: TextField(
controller: _westController,
decoration: const InputDecoration(
labelText: 'West',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context)!.west,
border: const OutlineInputBorder(),
hintText: '14.4',
),
keyboardType: const TextInputType.numberWithOptions(decimal: true),
@@ -485,7 +485,7 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
// Zoom Levels
Text(
'Zoom Levels',
AppLocalizations.of(context)!.zoomLevels,
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
@@ -495,7 +495,7 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Min: $_minZoom'),
Text(AppLocalizations.of(context)!.minZoom(_minZoom)),
Slider(
value: _minZoom.toDouble(),
min: 1,
@@ -519,7 +519,7 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Max: $_maxZoom'),
Text(AppLocalizations.of(context)!.maxZoom(_maxZoom)),
Slider(
value: _maxZoom.toDouble(),
min: 1,
@@ -560,7 +560,7 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
_statusMessage ?? 'Downloading...',
_statusMessage ?? AppLocalizations.of(context)!.downloadingDots,
style: TextStyle(
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.onPrimaryContainer,
@@ -600,7 +600,7 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
ElevatedButton.icon(
onPressed: _cancelDownload,
icon: const Icon(Icons.cancel),
label: const Text('Cancel Download'),
label: Text(AppLocalizations.of(context)!.cancelDownload),
style: ElevatedButton.styleFrom(
minimumSize: const Size.fromHeight(48),
backgroundColor: Colors.red,
@@ -611,7 +611,7 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
ElevatedButton.icon(
onPressed: _downloadRegion,
icon: const Icon(Icons.download),
label: const Text('Download Region'),
label: Text(AppLocalizations.of(context)!.downloadRegionButton),
style: ElevatedButton.styleFrom(
minimumSize: const Size.fromHeight(48),
),
@@ -619,7 +619,7 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
const SizedBox(height: 8),
Text(
'Note: Large regions or high zoom levels may take significant time and storage.',
AppLocalizations.of(context)!.downloadNote,
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
),
],
@@ -636,7 +636,7 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Cache Management',
AppLocalizations.of(context)!.cacheManagement,
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 16),
@@ -645,7 +645,7 @@ class _MapManagementScreenState extends State<MapManagementScreen> {
OutlinedButton.icon(
onPressed: _isDownloading ? null : _clearCache,
icon: const Icon(Icons.delete_forever),
label: const Text('Clear All Maps'),
label: Text(AppLocalizations.of(context)!.clearAllMaps),
style: OutlinedButton.styleFrom(
foregroundColor: Colors.red,
minimumSize: const Size.fromHeight(48),

View File

@@ -360,7 +360,7 @@ class _MapTabState extends State<MapTab> with AutomaticKeepAliveClientMixin {
const SizedBox(width: 12),
Expanded(
child: Text(
'Select Map Layer',
AppLocalizations.of(context)!.selectMapLayer,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
@@ -368,7 +368,7 @@ class _MapTabState extends State<MapTab> with AutomaticKeepAliveClientMixin {
),
IconButton(
icon: const Icon(Icons.download),
tooltip: 'Download visible area',
tooltip: AppLocalizations.of(context)!.downloadVisibleArea,
onPressed: () {
Navigator.pop(context);
_navigateToDownload(context);
@@ -382,7 +382,7 @@ class _MapTabState extends State<MapTab> with AutomaticKeepAliveClientMixin {
leading: _currentLayer.type == layer.type
? const Icon(Icons.check_circle, color: Colors.green)
: const Icon(Icons.radio_button_unchecked),
title: Text(layer.name),
title: Text(layer.getLocalizedName(context)),
subtitle: Text(layer.attribution),
onTap: () {
setState(() {
@@ -442,7 +442,7 @@ class _MapTabState extends State<MapTab> with AutomaticKeepAliveClientMixin {
const Icon(Icons.settings),
const SizedBox(width: 12),
Text(
'Map Options',
AppLocalizations.of(context)!.mapOptions,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
@@ -454,8 +454,8 @@ class _MapTabState extends State<MapTab> with AutomaticKeepAliveClientMixin {
// Legend toggle
SwitchListTile(
secondary: const Icon(Icons.info_outline),
title: const Text('Show Legend'),
subtitle: const Text('Display marker type counts'),
title: Text(AppLocalizations.of(context)!.showLegend),
subtitle: Text(AppLocalizations.of(context)!.displayMarkerTypeCounts),
value: _showLegend,
onChanged: (value) {
setState(() {
@@ -469,8 +469,8 @@ class _MapTabState extends State<MapTab> with AutomaticKeepAliveClientMixin {
// Compass rotation toggle
SwitchListTile(
secondary: const Icon(Icons.explore),
title: const Text('Rotate Map with Heading'),
subtitle: const Text('Map follows your direction when moving'),
title: Text(AppLocalizations.of(context)!.rotateMapWithHeading),
subtitle: Text(AppLocalizations.of(context)!.mapFollowsDirection),
value: _rotateMarkerWithHeading,
onChanged: (value) {
setState(() {
@@ -502,8 +502,8 @@ class _MapTabState extends State<MapTab> with AutomaticKeepAliveClientMixin {
// Map Debug Info toggle
SwitchListTile(
secondary: const Icon(Icons.developer_mode),
title: const Text('Show Map Debug Info'),
subtitle: const Text('Display zoom level and bounds'),
title: Text(AppLocalizations.of(context)!.showMapDebugInfo),
subtitle: Text(AppLocalizations.of(context)!.displayZoomLevelBounds),
value: _showMapDebugInfo,
onChanged: (value) {
setState(() {
@@ -517,8 +517,8 @@ class _MapTabState extends State<MapTab> with AutomaticKeepAliveClientMixin {
// Fullscreen mode toggle
SwitchListTile(
secondary: const Icon(Icons.fullscreen),
title: const Text('Fullscreen Mode'),
subtitle: const Text('Hide all UI controls for full map view'),
title: Text(AppLocalizations.of(context)!.fullscreenMode),
subtitle: Text(AppLocalizations.of(context)!.hideUiFullMapView),
value: _isFullscreen,
onChanged: (value) {
setState(() {
@@ -1062,7 +1062,7 @@ class _MapTabState extends State<MapTab> with AutomaticKeepAliveClientMixin {
],
),
child: Text(
_isDraggingPin ? 'Drag to Position' : 'Create SAR Marker',
_isDraggingPin ? AppLocalizations.of(context)!.dragToPosition : AppLocalizations.of(context)!.createSarMarker,
style: const TextStyle(
color: Colors.white,
fontSize: 12,
@@ -1109,7 +1109,7 @@ class _MapTabState extends State<MapTab> with AutomaticKeepAliveClientMixin {
const CircularProgressIndicator(),
const SizedBox(height: 16),
Text(
'Initializing map...',
AppLocalizations.of(context)!.initializingMap,
style: Theme.of(context).textTheme.bodyMedium,
),
],

View File

@@ -13,6 +13,7 @@ import '../widgets/messages/sar_update_sheet.dart';
import '../widgets/contacts/direct_message_sheet.dart';
import '../utils/toast_logger.dart';
import '../l10n/app_localizations.dart';
import '../utils/sar_marker_extensions.dart';
class MessagesTab extends StatefulWidget {
final VoidCallback onNavigateToMap;
@@ -179,7 +180,7 @@ class _MessagesTabState extends State<MessagesTab> {
if (!mounted) return;
ToastLogger.warning(
context,
'${sarType.displayName} marker broadcast to public channel',
'${sarType.getLocalizedName(context)} marker broadcast to public channel',
);
} else {
// Create message ID
@@ -231,7 +232,7 @@ class _MessagesTabState extends State<MessagesTab> {
if (!mounted) return;
ToastLogger.success(
context,
'${sarType.displayName} marker sent to room',
'${sarType.getLocalizedName(context)} marker sent to room',
);
}
} catch (e) {
@@ -397,7 +398,7 @@ class _MessagesTabState extends State<MessagesTab> {
maxLengthEnforcement: MaxLengthEnforcement.enforced,
style: const TextStyle(fontSize: 14),
decoration: InputDecoration(
hintText: 'Type a message...',
hintText: AppLocalizations.of(context)!.typeYourMessage,
hintStyle: const TextStyle(fontSize: 14),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(24),
@@ -860,7 +861,7 @@ class _MessageBubble extends StatelessWidget {
),
const SizedBox(width: 4),
Text(
'SAR ALERT',
AppLocalizations.of(context)!.sarAlert,
style: Theme.of(context).textTheme.labelSmall
?.copyWith(
color: Colors.white,
@@ -943,7 +944,7 @@ class _MessageBubble extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
message.sarMarkerType!.displayName,
message.sarMarkerType!.getLocalizedName(context),
style: Theme.of(context).textTheme.titleSmall
?.copyWith(fontWeight: FontWeight.bold),
),