mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-11 16:30:28 +00:00
fix: Update import path for AppLocalizations in CompassSarList widget
This commit is contained in:
@@ -1168,5 +1168,535 @@
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"noContactsYet": "No contacts yet",
|
||||
"@noContactsYet": {
|
||||
"description": "Empty state message when there are no contacts"
|
||||
},
|
||||
|
||||
"connectToDeviceToLoadContacts": "Connect to a device to load contacts",
|
||||
"@connectToDeviceToLoadContacts": {
|
||||
"description": "Instruction to connect device to load contacts"
|
||||
},
|
||||
|
||||
"teamMembers": "Team Members",
|
||||
"@teamMembers": {
|
||||
"description": "Section header for team members (chat contacts)"
|
||||
},
|
||||
|
||||
"repeaters": "Repeaters",
|
||||
"@repeaters": {
|
||||
"description": "Section header for repeater nodes"
|
||||
},
|
||||
|
||||
"rooms": "Rooms",
|
||||
"@rooms": {
|
||||
"description": "Section header for rooms/channels"
|
||||
},
|
||||
|
||||
"cacheStatistics": "Cache Statistics",
|
||||
"@cacheStatistics": {
|
||||
"description": "Title for cache statistics section"
|
||||
},
|
||||
|
||||
"totalTiles": "Total Tiles",
|
||||
"@totalTiles": {
|
||||
"description": "Label for total number of cached tiles"
|
||||
},
|
||||
|
||||
"cacheSize": "Cache Size",
|
||||
"@cacheSize": {
|
||||
"description": "Label for cache size in MB"
|
||||
},
|
||||
|
||||
"storeName": "Store Name",
|
||||
"@storeName": {
|
||||
"description": "Label for cache store name"
|
||||
},
|
||||
|
||||
"noCacheStatistics": "No cache statistics available",
|
||||
"@noCacheStatistics": {
|
||||
"description": "Message when cache statistics are unavailable"
|
||||
},
|
||||
|
||||
"downloadRegion": "Download Region",
|
||||
"@downloadRegion": {
|
||||
"description": "Title for download region section"
|
||||
},
|
||||
|
||||
"mapLayer": "Map Layer",
|
||||
"@mapLayer": {
|
||||
"description": "Label for map layer selection"
|
||||
},
|
||||
|
||||
"regionBounds": "Region Bounds",
|
||||
"@regionBounds": {
|
||||
"description": "Title for region bounds input section"
|
||||
},
|
||||
|
||||
"north": "North",
|
||||
"@north": {
|
||||
"description": "Label for north coordinate"
|
||||
},
|
||||
|
||||
"south": "South",
|
||||
"@south": {
|
||||
"description": "Label for south coordinate"
|
||||
},
|
||||
|
||||
"east": "East",
|
||||
"@east": {
|
||||
"description": "Label for east coordinate"
|
||||
},
|
||||
|
||||
"west": "West",
|
||||
"@west": {
|
||||
"description": "Label for west coordinate"
|
||||
},
|
||||
|
||||
"zoomLevels": "Zoom Levels",
|
||||
"@zoomLevels": {
|
||||
"description": "Title for zoom levels section"
|
||||
},
|
||||
|
||||
"minZoom": "Min: {zoom}",
|
||||
"@minZoom": {
|
||||
"description": "Label for minimum zoom level",
|
||||
"placeholders": {
|
||||
"zoom": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"maxZoom": "Max: {zoom}",
|
||||
"@maxZoom": {
|
||||
"description": "Label for maximum zoom level",
|
||||
"placeholders": {
|
||||
"zoom": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"downloadingDots": "Downloading...",
|
||||
"@downloadingDots": {
|
||||
"description": "Status message during download"
|
||||
},
|
||||
|
||||
"cancelDownload": "Cancel Download",
|
||||
"@cancelDownload": {
|
||||
"description": "Button to cancel download"
|
||||
},
|
||||
|
||||
"downloadRegionButton": "Download Region",
|
||||
"@downloadRegionButton": {
|
||||
"description": "Button to start region download"
|
||||
},
|
||||
|
||||
"downloadNote": "Note: Large regions or high zoom levels may take significant time and storage.",
|
||||
"@downloadNote": {
|
||||
"description": "Warning about download size and time"
|
||||
},
|
||||
|
||||
"cacheManagement": "Cache Management",
|
||||
"@cacheManagement": {
|
||||
"description": "Title for cache management section"
|
||||
},
|
||||
|
||||
"clearAllMaps": "Clear All Maps",
|
||||
"@clearAllMaps": {
|
||||
"description": "Button to clear all cached maps"
|
||||
},
|
||||
|
||||
"clearMapsConfirmTitle": "Clear All Maps",
|
||||
"@clearMapsConfirmTitle": {
|
||||
"description": "Title for clear maps confirmation dialog"
|
||||
},
|
||||
|
||||
"clearMapsConfirmMessage": "Are you sure you want to delete all downloaded maps? This action cannot be undone.",
|
||||
"@clearMapsConfirmMessage": {
|
||||
"description": "Confirmation message for clearing maps"
|
||||
},
|
||||
|
||||
"mapDownloadCompleted": "Map download completed!",
|
||||
"@mapDownloadCompleted": {
|
||||
"description": "Success message after map download"
|
||||
},
|
||||
|
||||
"cacheClearedSuccessfully": "Cache cleared successfully!",
|
||||
"@cacheClearedSuccessfully": {
|
||||
"description": "Success message after clearing cache"
|
||||
},
|
||||
|
||||
"downloadCancelled": "Download cancelled",
|
||||
"@downloadCancelled": {
|
||||
"description": "Message when download is cancelled"
|
||||
},
|
||||
|
||||
"startingDownload": "Starting download...",
|
||||
"@startingDownload": {
|
||||
"description": "Initial status when download begins"
|
||||
},
|
||||
|
||||
"downloadingMapTiles": "Downloading map tiles...",
|
||||
"@downloadingMapTiles": {
|
||||
"description": "Status during tile download"
|
||||
},
|
||||
|
||||
"downloadCompletedSuccessfully": "Download completed successfully!",
|
||||
"@downloadCompletedSuccessfully": {
|
||||
"description": "Status after successful download"
|
||||
},
|
||||
|
||||
"cancellingDownload": "Cancelling download...",
|
||||
"@cancellingDownload": {
|
||||
"description": "Status while cancelling download"
|
||||
},
|
||||
|
||||
"errorLoadingStats": "Error loading stats: {error}",
|
||||
"@errorLoadingStats": {
|
||||
"description": "Error message when loading cache stats fails",
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"downloadFailed": "Download failed: {error}",
|
||||
"@downloadFailed": {
|
||||
"description": "Error message when download fails",
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"cancelFailed": "Cancel failed: {error}",
|
||||
"@cancelFailed": {
|
||||
"description": "Error message when cancel fails",
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"clearCacheFailed": "Clear cache failed: {error}",
|
||||
"@clearCacheFailed": {
|
||||
"description": "Error message when clearing cache fails",
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"minZoomError": "Min zoom: {error}",
|
||||
"@minZoomError": {
|
||||
"description": "Validation error for minimum zoom",
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"maxZoomError": "Max zoom: {error}",
|
||||
"@maxZoomError": {
|
||||
"description": "Validation error for maximum zoom",
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"minZoomGreaterThanMax": "Minimum zoom must be less than or equal to maximum zoom",
|
||||
"@minZoomGreaterThanMax": {
|
||||
"description": "Validation error when min zoom > max zoom"
|
||||
},
|
||||
|
||||
"selectMapLayer": "Select Map Layer",
|
||||
"@selectMapLayer": {
|
||||
"description": "Title for map layer selection dialog"
|
||||
},
|
||||
|
||||
"mapOptions": "Map Options",
|
||||
"@mapOptions": {
|
||||
"description": "Title for map options dialog"
|
||||
},
|
||||
|
||||
"showLegend": "Show Legend",
|
||||
"@showLegend": {
|
||||
"description": "Toggle for showing map legend"
|
||||
},
|
||||
|
||||
"displayMarkerTypeCounts": "Display marker type counts",
|
||||
"@displayMarkerTypeCounts": {
|
||||
"description": "Description for show legend toggle"
|
||||
},
|
||||
|
||||
"rotateMapWithHeading": "Rotate Map with Heading",
|
||||
"@rotateMapWithHeading": {
|
||||
"description": "Toggle for rotating map with compass heading"
|
||||
},
|
||||
|
||||
"mapFollowsDirection": "Map follows your direction when moving",
|
||||
"@mapFollowsDirection": {
|
||||
"description": "Description for rotate map toggle"
|
||||
},
|
||||
|
||||
"showMapDebugInfo": "Show Map Debug Info",
|
||||
"@showMapDebugInfo": {
|
||||
"description": "Toggle for showing map debug information"
|
||||
},
|
||||
|
||||
"displayZoomLevelBounds": "Display zoom level and bounds",
|
||||
"@displayZoomLevelBounds": {
|
||||
"description": "Description for debug info toggle"
|
||||
},
|
||||
|
||||
"fullscreenMode": "Fullscreen Mode",
|
||||
"@fullscreenMode": {
|
||||
"description": "Toggle for fullscreen map mode"
|
||||
},
|
||||
|
||||
"hideUiFullMapView": "Hide all UI controls for full map view",
|
||||
"@hideUiFullMapView": {
|
||||
"description": "Description for fullscreen mode toggle"
|
||||
},
|
||||
|
||||
"openStreetMap": "OpenStreetMap",
|
||||
"@openStreetMap": {
|
||||
"description": "OpenStreetMap layer name"
|
||||
},
|
||||
|
||||
"openTopoMap": "OpenTopoMap",
|
||||
"@openTopoMap": {
|
||||
"description": "OpenTopoMap layer name"
|
||||
},
|
||||
|
||||
"esriSatellite": "ESRI Satellite",
|
||||
"@esriSatellite": {
|
||||
"description": "ESRI Satellite imagery layer name"
|
||||
},
|
||||
|
||||
"downloadVisibleArea": "Download visible area",
|
||||
"@downloadVisibleArea": {
|
||||
"description": "Tooltip for download visible area button"
|
||||
},
|
||||
|
||||
"initializingMap": "Initializing map...",
|
||||
"@initializingMap": {
|
||||
"description": "Loading message for map initialization"
|
||||
},
|
||||
|
||||
"dragToPosition": "Drag to Position",
|
||||
"@dragToPosition": {
|
||||
"description": "Label when dragging a pin on map"
|
||||
},
|
||||
|
||||
"createSarMarker": "Create SAR Marker",
|
||||
"@createSarMarker": {
|
||||
"description": "Label for creating SAR marker from pin"
|
||||
},
|
||||
|
||||
"compass": "Compass",
|
||||
"@compass": {
|
||||
"description": "Compass title in detailed compass dialog"
|
||||
},
|
||||
|
||||
"navigationAndContacts": "Navigation & Contacts",
|
||||
"@navigationAndContacts": {
|
||||
"description": "Subtitle for compass dialog"
|
||||
},
|
||||
|
||||
"sarAlert": "SAR ALERT",
|
||||
"@sarAlert": {
|
||||
"description": "Label for SAR alert badge on messages"
|
||||
},
|
||||
|
||||
"messageSentToPublicChannel": "Message sent to public channel",
|
||||
"@messageSentToPublicChannel": {
|
||||
"description": "Success message when message is sent to public channel"
|
||||
},
|
||||
|
||||
"pleaseSelectRoomToSendSar": "Please select a room to send SAR marker",
|
||||
"@pleaseSelectRoomToSendSar": {
|
||||
"description": "Error when no room is selected for SAR marker"
|
||||
},
|
||||
|
||||
"failedToSendSarMarker": "Failed to send SAR marker: {error}",
|
||||
"@failedToSendSarMarker": {
|
||||
"description": "Error message when SAR marker fails to send",
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"sarMarkerSentTo": "SAR marker sent to {roomName}",
|
||||
"@sarMarkerSentTo": {
|
||||
"description": "Success message when SAR marker is sent to room",
|
||||
"placeholders": {
|
||||
"roomName": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"notConnectedCannotSync": "Not connected - cannot sync messages",
|
||||
"@notConnectedCannotSync": {
|
||||
"description": "Warning when trying to sync messages while not connected"
|
||||
},
|
||||
|
||||
"syncedMessageCount": "Synced {count} message(s)",
|
||||
"@syncedMessageCount": {
|
||||
"description": "Success message showing number of synced messages",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"noNewMessages": "No new messages",
|
||||
"@noNewMessages": {
|
||||
"description": "Info message when no new messages to sync"
|
||||
},
|
||||
|
||||
"syncFailed": "Sync failed: {error}",
|
||||
"@syncFailed": {
|
||||
"description": "Error message when sync fails",
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"failedToResendMessage": "Failed to resend message",
|
||||
"@failedToResendMessage": {
|
||||
"description": "Error when message retry fails"
|
||||
},
|
||||
|
||||
"retryingMessage": "Retrying message...",
|
||||
"@retryingMessage": {
|
||||
"description": "Info message when retrying a failed message"
|
||||
},
|
||||
|
||||
"retryFailed": "Retry failed: {error}",
|
||||
"@retryFailed": {
|
||||
"description": "Error message when retry fails",
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"textCopiedToClipboard": "Text copied to clipboard",
|
||||
"@textCopiedToClipboard": {
|
||||
"description": "Success message when text is copied"
|
||||
},
|
||||
|
||||
"cannotReplySenderMissing": "Cannot reply: sender information missing",
|
||||
"@cannotReplySenderMissing": {
|
||||
"description": "Error when sender info is missing for reply"
|
||||
},
|
||||
|
||||
"cannotReplyContactNotFound": "Cannot reply: contact not found",
|
||||
"@cannotReplyContactNotFound": {
|
||||
"description": "Error when contact not found for reply"
|
||||
},
|
||||
|
||||
"messageDeleted": "Message deleted",
|
||||
"@messageDeleted": {
|
||||
"description": "Info message when message is deleted"
|
||||
},
|
||||
|
||||
"refreshedContacts": "Refreshed contacts",
|
||||
"@refreshedContacts": {
|
||||
"description": "Success message when contacts are refreshed"
|
||||
},
|
||||
|
||||
"justNow": "Just now",
|
||||
"@justNow": {
|
||||
"description": "Time indicator for very recent activity"
|
||||
},
|
||||
|
||||
"minutesAgo": "{minutes}m ago",
|
||||
"@minutesAgo": {
|
||||
"description": "Time indicator for minutes ago",
|
||||
"placeholders": {
|
||||
"minutes": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"hoursAgo": "{hours}h ago",
|
||||
"@hoursAgo": {
|
||||
"description": "Time indicator for hours ago",
|
||||
"placeholders": {
|
||||
"hours": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"daysAgo": "{days}d ago",
|
||||
"@daysAgo": {
|
||||
"description": "Time indicator for days ago",
|
||||
"placeholders": {
|
||||
"days": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"secondsAgo": "{seconds}s ago",
|
||||
"@secondsAgo": {
|
||||
"description": "Time indicator for seconds ago",
|
||||
"placeholders": {
|
||||
"seconds": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"sending": "Sending...",
|
||||
"@sending": {
|
||||
"description": "Delivery status: sending"
|
||||
},
|
||||
|
||||
"sent": "Sent",
|
||||
"@sent": {
|
||||
"description": "Delivery status: sent"
|
||||
},
|
||||
|
||||
"delivered": "Delivered",
|
||||
"@delivered": {
|
||||
"description": "Delivery status: delivered"
|
||||
},
|
||||
|
||||
"deliveredWithTime": "Delivered ({time}ms)",
|
||||
"@deliveredWithTime": {
|
||||
"description": "Delivery status with round-trip time",
|
||||
"placeholders": {
|
||||
"time": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"failed": "Failed",
|
||||
"@failed": {
|
||||
"description": "Delivery status: failed"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,5 +391,149 @@
|
||||
|
||||
"degreesLeft": "{degrees}° lijevo",
|
||||
|
||||
"latLonFormat": "Ššir: {latitude} Dužina: {longitude}"
|
||||
"latLonFormat": "Ššir: {latitude} Dužina: {longitude}",
|
||||
|
||||
"noContactsYet": "Još nema kontakata",
|
||||
|
||||
"connectToDeviceToLoadContacts": "Povežite se s uređajem da učitate kontakte",
|
||||
|
||||
"teamMembers": "Članovi tima",
|
||||
|
||||
"repeaters": "Repetitori",
|
||||
|
||||
"rooms": "Sobe",
|
||||
|
||||
"cacheStatistics": "Statistika predmemorije",
|
||||
|
||||
"totalTiles": "Ukupno pločica",
|
||||
|
||||
"cacheSize": "Veličina predmemorije",
|
||||
|
||||
"storeName": "Ime pohrane",
|
||||
|
||||
"noCacheStatistics": "Statistika predmemorije nije dostupna",
|
||||
|
||||
"downloadRegion": "Preuzmi regiju",
|
||||
|
||||
"mapLayer": "Sloj karte",
|
||||
|
||||
"regionBounds": "Granice regije",
|
||||
|
||||
"north": "Sjever",
|
||||
|
||||
"south": "Jug",
|
||||
|
||||
"east": "Istok",
|
||||
|
||||
"west": "Zapad",
|
||||
|
||||
"zoomLevels": "Razine zumiranja",
|
||||
|
||||
"minZoom": "Min: {zoom}",
|
||||
|
||||
"maxZoom": "Maks: {zoom}",
|
||||
|
||||
"downloadingDots": "Preuzimanje...",
|
||||
|
||||
"cancelDownload": "Otkaži preuzimanje",
|
||||
|
||||
"downloadRegionButton": "Preuzmi regiju",
|
||||
|
||||
"downloadNote": "Napomena: Velike regije ili visoke razine zumiranja mogu zahtijevati značajno vrijeme i prostor za pohranu.",
|
||||
|
||||
"cacheManagement": "Upravljanje predmemorijom",
|
||||
|
||||
"clearAllMaps": "Očisti sve karte",
|
||||
|
||||
"clearMapsConfirmTitle": "Očisti sve karte",
|
||||
|
||||
"clearMapsConfirmMessage": "Jeste li sigurni da želite izbrisati sve preuzete karte? Ova radnja se ne može poništiti.",
|
||||
|
||||
"mapDownloadCompleted": "Preuzimanje karte završeno!",
|
||||
|
||||
"cacheClearedSuccessfully": "Predmemorija uspješno očišćena!",
|
||||
|
||||
"downloadCancelled": "Preuzimanje otkazano",
|
||||
|
||||
"startingDownload": "Pokretanje preuzimanja...",
|
||||
|
||||
"downloadingMapTiles": "Preuzimanje pločica karte...",
|
||||
|
||||
"downloadCompletedSuccessfully": "Preuzimanje uspješno završeno!",
|
||||
|
||||
"cancellingDownload": "Otkazivanje preuzimanja...",
|
||||
|
||||
"errorLoadingStats": "Greška pri učitavanju statistike: {error}",
|
||||
|
||||
"downloadFailed": "Preuzimanje nije uspjelo: {error}",
|
||||
|
||||
"cancelFailed": "Otkazivanje nije uspjelo: {error}",
|
||||
|
||||
"clearCacheFailed": "Čišćenje predmemorije nije uspjelo: {error}",
|
||||
|
||||
"minZoomError": "Min zumiranje: {error}",
|
||||
|
||||
"maxZoomError": "Maks zumiranje: {error}",
|
||||
|
||||
"minZoomGreaterThanMax": "Minimalno zumiranje mora biti manje ili jednako maksimalnom zumiranju",
|
||||
|
||||
"selectMapLayer": "Odaberite sloj karte",
|
||||
|
||||
"mapOptions": "Opcije karte",
|
||||
|
||||
"showLegend": "Prikaži legendu",
|
||||
|
||||
"displayMarkerTypeCounts": "Prikaži broj vrsta markera",
|
||||
|
||||
"rotateMapWithHeading": "Rotiraj kartu sa smjerom",
|
||||
|
||||
"mapFollowsDirection": "Karta slijedi vaš smjer pri kretanju",
|
||||
|
||||
"showMapDebugInfo": "Prikaži debug informacije karte",
|
||||
|
||||
"displayZoomLevelBounds": "Prikaži razinu zumiranja i granice",
|
||||
|
||||
"fullscreenMode": "Način cijelog zaslona",
|
||||
|
||||
"hideUiFullMapView": "Sakrij sve UI kontrole za prikaz cijele karte",
|
||||
|
||||
"openStreetMap": "OpenStreetMap",
|
||||
|
||||
"openTopoMap": "OpenTopoMap",
|
||||
|
||||
"esriSatellite": "ESRI satelit",
|
||||
|
||||
"downloadVisibleArea": "Preuzmi vidljivo područje",
|
||||
|
||||
"initializingMap": "Inicijalizacija karte...",
|
||||
|
||||
"dragToPosition": "Povuci na poziciju",
|
||||
|
||||
"createSarMarker": "Kreiraj SAR marker",
|
||||
|
||||
"compass": "Kompas",
|
||||
|
||||
"navigationAndContacts": "Navigacija i kontakti",
|
||||
|
||||
"sarAlert": "SAR UZBUNA",
|
||||
|
||||
"justNow": "Upravo sada",
|
||||
|
||||
"minutesAgo": "prije {minutes}m",
|
||||
|
||||
"hoursAgo": "prije {hours}h",
|
||||
|
||||
"daysAgo": "prije {days}d",
|
||||
|
||||
"secondsAgo": "prije {seconds}s",
|
||||
|
||||
"sending": "Slanje...",
|
||||
|
||||
"sent": "Poslano",
|
||||
|
||||
"delivered": "Dostavljeno",
|
||||
|
||||
"deliveredWithTime": "Dostavljeno ({time}ms)",
|
||||
|
||||
"failed": "Neuspjelo"
|
||||
}
|
||||
|
||||
@@ -1280,6 +1280,378 @@ abstract class AppLocalizations {
|
||||
/// In en, this message translates to:
|
||||
/// **'Lat: {latitude} Lon: {longitude}'**
|
||||
String latLonFormat(String latitude, String longitude);
|
||||
|
||||
/// Empty state message when there are no contacts
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'No contacts yet'**
|
||||
String get noContactsYet;
|
||||
|
||||
/// Instruction to connect device to load contacts
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Connect to a device to load contacts'**
|
||||
String get connectToDeviceToLoadContacts;
|
||||
|
||||
/// Section header for team members (chat contacts)
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Team Members'**
|
||||
String get teamMembers;
|
||||
|
||||
/// Section header for repeater nodes
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Repeaters'**
|
||||
String get repeaters;
|
||||
|
||||
/// Section header for rooms/channels
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Rooms'**
|
||||
String get rooms;
|
||||
|
||||
/// Title for cache statistics section
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Cache Statistics'**
|
||||
String get cacheStatistics;
|
||||
|
||||
/// Label for total number of cached tiles
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Total Tiles'**
|
||||
String get totalTiles;
|
||||
|
||||
/// Label for cache size in MB
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Cache Size'**
|
||||
String get cacheSize;
|
||||
|
||||
/// Label for cache store name
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Store Name'**
|
||||
String get storeName;
|
||||
|
||||
/// Message when cache statistics are unavailable
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'No cache statistics available'**
|
||||
String get noCacheStatistics;
|
||||
|
||||
/// Title for download region section
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Download Region'**
|
||||
String get downloadRegion;
|
||||
|
||||
/// Label for map layer selection
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Map Layer'**
|
||||
String get mapLayer;
|
||||
|
||||
/// Title for region bounds input section
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Region Bounds'**
|
||||
String get regionBounds;
|
||||
|
||||
/// Label for north coordinate
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'North'**
|
||||
String get north;
|
||||
|
||||
/// Label for south coordinate
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'South'**
|
||||
String get south;
|
||||
|
||||
/// Label for east coordinate
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'East'**
|
||||
String get east;
|
||||
|
||||
/// Label for west coordinate
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'West'**
|
||||
String get west;
|
||||
|
||||
/// Title for zoom levels section
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Zoom Levels'**
|
||||
String get zoomLevels;
|
||||
|
||||
/// Label for minimum zoom level
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Min: {zoom}'**
|
||||
String minZoom(int zoom);
|
||||
|
||||
/// Label for maximum zoom level
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Max: {zoom}'**
|
||||
String maxZoom(int zoom);
|
||||
|
||||
/// Status message during download
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Downloading...'**
|
||||
String get downloadingDots;
|
||||
|
||||
/// Button to cancel download
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Cancel Download'**
|
||||
String get cancelDownload;
|
||||
|
||||
/// Button to start region download
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Download Region'**
|
||||
String get downloadRegionButton;
|
||||
|
||||
/// Warning about download size and time
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Note: Large regions or high zoom levels may take significant time and storage.'**
|
||||
String get downloadNote;
|
||||
|
||||
/// Title for cache management section
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Cache Management'**
|
||||
String get cacheManagement;
|
||||
|
||||
/// Button to clear all cached maps
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Clear All Maps'**
|
||||
String get clearAllMaps;
|
||||
|
||||
/// Title for clear maps confirmation dialog
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Clear All Maps'**
|
||||
String get clearMapsConfirmTitle;
|
||||
|
||||
/// Confirmation message for clearing maps
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Are you sure you want to delete all downloaded maps? This action cannot be undone.'**
|
||||
String get clearMapsConfirmMessage;
|
||||
|
||||
/// Success message after map download
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Map download completed!'**
|
||||
String get mapDownloadCompleted;
|
||||
|
||||
/// Success message after clearing cache
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Cache cleared successfully!'**
|
||||
String get cacheClearedSuccessfully;
|
||||
|
||||
/// Message when download is cancelled
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Download cancelled'**
|
||||
String get downloadCancelled;
|
||||
|
||||
/// Initial status when download begins
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Starting download...'**
|
||||
String get startingDownload;
|
||||
|
||||
/// Status during tile download
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Downloading map tiles...'**
|
||||
String get downloadingMapTiles;
|
||||
|
||||
/// Status after successful download
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Download completed successfully!'**
|
||||
String get downloadCompletedSuccessfully;
|
||||
|
||||
/// Status while cancelling download
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Cancelling download...'**
|
||||
String get cancellingDownload;
|
||||
|
||||
/// Error message when loading cache stats fails
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Error loading stats: {error}'**
|
||||
String errorLoadingStats(String error);
|
||||
|
||||
/// Error message when download fails
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Download failed: {error}'**
|
||||
String downloadFailed(String error);
|
||||
|
||||
/// Error message when cancel fails
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Cancel failed: {error}'**
|
||||
String cancelFailed(String error);
|
||||
|
||||
/// Error message when clearing cache fails
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Clear cache failed: {error}'**
|
||||
String clearCacheFailed(String error);
|
||||
|
||||
/// Validation error for minimum zoom
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Min zoom: {error}'**
|
||||
String minZoomError(String error);
|
||||
|
||||
/// Validation error for maximum zoom
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Max zoom: {error}'**
|
||||
String maxZoomError(String error);
|
||||
|
||||
/// Validation error when min zoom > max zoom
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Minimum zoom must be less than or equal to maximum zoom'**
|
||||
String get minZoomGreaterThanMax;
|
||||
|
||||
/// Title for map layer selection dialog
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Select Map Layer'**
|
||||
String get selectMapLayer;
|
||||
|
||||
/// Title for map options dialog
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Map Options'**
|
||||
String get mapOptions;
|
||||
|
||||
/// Toggle for showing map legend
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Show Legend'**
|
||||
String get showLegend;
|
||||
|
||||
/// Description for show legend toggle
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Display marker type counts'**
|
||||
String get displayMarkerTypeCounts;
|
||||
|
||||
/// Toggle for rotating map with compass heading
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Rotate Map with Heading'**
|
||||
String get rotateMapWithHeading;
|
||||
|
||||
/// Description for rotate map toggle
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Map follows your direction when moving'**
|
||||
String get mapFollowsDirection;
|
||||
|
||||
/// Toggle for showing map debug information
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Show Map Debug Info'**
|
||||
String get showMapDebugInfo;
|
||||
|
||||
/// Description for debug info toggle
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Display zoom level and bounds'**
|
||||
String get displayZoomLevelBounds;
|
||||
|
||||
/// Toggle for fullscreen map mode
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Fullscreen Mode'**
|
||||
String get fullscreenMode;
|
||||
|
||||
/// Description for fullscreen mode toggle
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Hide all UI controls for full map view'**
|
||||
String get hideUiFullMapView;
|
||||
|
||||
/// OpenStreetMap layer name
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'OpenStreetMap'**
|
||||
String get openStreetMap;
|
||||
|
||||
/// OpenTopoMap layer name
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'OpenTopoMap'**
|
||||
String get openTopoMap;
|
||||
|
||||
/// ESRI Satellite imagery layer name
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'ESRI Satellite'**
|
||||
String get esriSatellite;
|
||||
|
||||
/// Tooltip for download visible area button
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Download visible area'**
|
||||
String get downloadVisibleArea;
|
||||
|
||||
/// Loading message for map initialization
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Initializing map...'**
|
||||
String get initializingMap;
|
||||
|
||||
/// Label when dragging a pin on map
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Drag to Position'**
|
||||
String get dragToPosition;
|
||||
|
||||
/// Label for creating SAR marker from pin
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Create SAR Marker'**
|
||||
String get createSarMarker;
|
||||
|
||||
/// Compass title in detailed compass dialog
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Compass'**
|
||||
String get compass;
|
||||
|
||||
/// Subtitle for compass dialog
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Navigation & Contacts'**
|
||||
String get navigationAndContacts;
|
||||
|
||||
/// Label for SAR alert badge on messages
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'SAR ALERT'**
|
||||
String get sarAlert;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
||||
@@ -681,4 +681,211 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
String latLonFormat(String latitude, String longitude) {
|
||||
return 'Lat: $latitude Lon: $longitude';
|
||||
}
|
||||
|
||||
@override
|
||||
String get noContactsYet => 'No contacts yet';
|
||||
|
||||
@override
|
||||
String get connectToDeviceToLoadContacts =>
|
||||
'Connect to a device to load contacts';
|
||||
|
||||
@override
|
||||
String get teamMembers => 'Team Members';
|
||||
|
||||
@override
|
||||
String get repeaters => 'Repeaters';
|
||||
|
||||
@override
|
||||
String get rooms => 'Rooms';
|
||||
|
||||
@override
|
||||
String get cacheStatistics => 'Cache Statistics';
|
||||
|
||||
@override
|
||||
String get totalTiles => 'Total Tiles';
|
||||
|
||||
@override
|
||||
String get cacheSize => 'Cache Size';
|
||||
|
||||
@override
|
||||
String get storeName => 'Store Name';
|
||||
|
||||
@override
|
||||
String get noCacheStatistics => 'No cache statistics available';
|
||||
|
||||
@override
|
||||
String get downloadRegion => 'Download Region';
|
||||
|
||||
@override
|
||||
String get mapLayer => 'Map Layer';
|
||||
|
||||
@override
|
||||
String get regionBounds => 'Region Bounds';
|
||||
|
||||
@override
|
||||
String get north => 'North';
|
||||
|
||||
@override
|
||||
String get south => 'South';
|
||||
|
||||
@override
|
||||
String get east => 'East';
|
||||
|
||||
@override
|
||||
String get west => 'West';
|
||||
|
||||
@override
|
||||
String get zoomLevels => 'Zoom Levels';
|
||||
|
||||
@override
|
||||
String minZoom(int zoom) {
|
||||
return 'Min: $zoom';
|
||||
}
|
||||
|
||||
@override
|
||||
String maxZoom(int zoom) {
|
||||
return 'Max: $zoom';
|
||||
}
|
||||
|
||||
@override
|
||||
String get downloadingDots => 'Downloading...';
|
||||
|
||||
@override
|
||||
String get cancelDownload => 'Cancel Download';
|
||||
|
||||
@override
|
||||
String get downloadRegionButton => 'Download Region';
|
||||
|
||||
@override
|
||||
String get downloadNote =>
|
||||
'Note: Large regions or high zoom levels may take significant time and storage.';
|
||||
|
||||
@override
|
||||
String get cacheManagement => 'Cache Management';
|
||||
|
||||
@override
|
||||
String get clearAllMaps => 'Clear All Maps';
|
||||
|
||||
@override
|
||||
String get clearMapsConfirmTitle => 'Clear All Maps';
|
||||
|
||||
@override
|
||||
String get clearMapsConfirmMessage =>
|
||||
'Are you sure you want to delete all downloaded maps? This action cannot be undone.';
|
||||
|
||||
@override
|
||||
String get mapDownloadCompleted => 'Map download completed!';
|
||||
|
||||
@override
|
||||
String get cacheClearedSuccessfully => 'Cache cleared successfully!';
|
||||
|
||||
@override
|
||||
String get downloadCancelled => 'Download cancelled';
|
||||
|
||||
@override
|
||||
String get startingDownload => 'Starting download...';
|
||||
|
||||
@override
|
||||
String get downloadingMapTiles => 'Downloading map tiles...';
|
||||
|
||||
@override
|
||||
String get downloadCompletedSuccessfully =>
|
||||
'Download completed successfully!';
|
||||
|
||||
@override
|
||||
String get cancellingDownload => 'Cancelling download...';
|
||||
|
||||
@override
|
||||
String errorLoadingStats(String error) {
|
||||
return 'Error loading stats: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String downloadFailed(String error) {
|
||||
return 'Download failed: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String cancelFailed(String error) {
|
||||
return 'Cancel failed: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String clearCacheFailed(String error) {
|
||||
return 'Clear cache failed: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String minZoomError(String error) {
|
||||
return 'Min zoom: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String maxZoomError(String error) {
|
||||
return 'Max zoom: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String get minZoomGreaterThanMax =>
|
||||
'Minimum zoom must be less than or equal to maximum zoom';
|
||||
|
||||
@override
|
||||
String get selectMapLayer => 'Select Map Layer';
|
||||
|
||||
@override
|
||||
String get mapOptions => 'Map Options';
|
||||
|
||||
@override
|
||||
String get showLegend => 'Show Legend';
|
||||
|
||||
@override
|
||||
String get displayMarkerTypeCounts => 'Display marker type counts';
|
||||
|
||||
@override
|
||||
String get rotateMapWithHeading => 'Rotate Map with Heading';
|
||||
|
||||
@override
|
||||
String get mapFollowsDirection => 'Map follows your direction when moving';
|
||||
|
||||
@override
|
||||
String get showMapDebugInfo => 'Show Map Debug Info';
|
||||
|
||||
@override
|
||||
String get displayZoomLevelBounds => 'Display zoom level and bounds';
|
||||
|
||||
@override
|
||||
String get fullscreenMode => 'Fullscreen Mode';
|
||||
|
||||
@override
|
||||
String get hideUiFullMapView => 'Hide all UI controls for full map view';
|
||||
|
||||
@override
|
||||
String get openStreetMap => 'OpenStreetMap';
|
||||
|
||||
@override
|
||||
String get openTopoMap => 'OpenTopoMap';
|
||||
|
||||
@override
|
||||
String get esriSatellite => 'ESRI Satellite';
|
||||
|
||||
@override
|
||||
String get downloadVisibleArea => 'Download visible area';
|
||||
|
||||
@override
|
||||
String get initializingMap => 'Initializing map...';
|
||||
|
||||
@override
|
||||
String get dragToPosition => 'Drag to Position';
|
||||
|
||||
@override
|
||||
String get createSarMarker => 'Create SAR Marker';
|
||||
|
||||
@override
|
||||
String get compass => 'Compass';
|
||||
|
||||
@override
|
||||
String get navigationAndContacts => 'Navigation & Contacts';
|
||||
|
||||
@override
|
||||
String get sarAlert => 'SAR ALERT';
|
||||
}
|
||||
|
||||
@@ -681,4 +681,211 @@ class AppLocalizationsHr extends AppLocalizations {
|
||||
String latLonFormat(String latitude, String longitude) {
|
||||
return 'Ššir: $latitude Dužina: $longitude';
|
||||
}
|
||||
|
||||
@override
|
||||
String get noContactsYet => 'Još nema kontakata';
|
||||
|
||||
@override
|
||||
String get connectToDeviceToLoadContacts =>
|
||||
'Povežite se s uređajem da učitate kontakte';
|
||||
|
||||
@override
|
||||
String get teamMembers => 'Članovi tima';
|
||||
|
||||
@override
|
||||
String get repeaters => 'Repetitori';
|
||||
|
||||
@override
|
||||
String get rooms => 'Sobe';
|
||||
|
||||
@override
|
||||
String get cacheStatistics => 'Statistika predmemorije';
|
||||
|
||||
@override
|
||||
String get totalTiles => 'Ukupno pločica';
|
||||
|
||||
@override
|
||||
String get cacheSize => 'Veličina predmemorije';
|
||||
|
||||
@override
|
||||
String get storeName => 'Ime pohrane';
|
||||
|
||||
@override
|
||||
String get noCacheStatistics => 'Statistika predmemorije nije dostupna';
|
||||
|
||||
@override
|
||||
String get downloadRegion => 'Preuzmi regiju';
|
||||
|
||||
@override
|
||||
String get mapLayer => 'Sloj karte';
|
||||
|
||||
@override
|
||||
String get regionBounds => 'Granice regije';
|
||||
|
||||
@override
|
||||
String get north => 'Sjever';
|
||||
|
||||
@override
|
||||
String get south => 'Jug';
|
||||
|
||||
@override
|
||||
String get east => 'Istok';
|
||||
|
||||
@override
|
||||
String get west => 'Zapad';
|
||||
|
||||
@override
|
||||
String get zoomLevels => 'Razine zumiranja';
|
||||
|
||||
@override
|
||||
String minZoom(int zoom) {
|
||||
return 'Min: $zoom';
|
||||
}
|
||||
|
||||
@override
|
||||
String maxZoom(int zoom) {
|
||||
return 'Maks: $zoom';
|
||||
}
|
||||
|
||||
@override
|
||||
String get downloadingDots => 'Preuzimanje...';
|
||||
|
||||
@override
|
||||
String get cancelDownload => 'Otkaži preuzimanje';
|
||||
|
||||
@override
|
||||
String get downloadRegionButton => 'Preuzmi regiju';
|
||||
|
||||
@override
|
||||
String get downloadNote =>
|
||||
'Napomena: Velike regije ili visoke razine zumiranja mogu zahtijevati značajno vrijeme i prostor za pohranu.';
|
||||
|
||||
@override
|
||||
String get cacheManagement => 'Upravljanje predmemorijom';
|
||||
|
||||
@override
|
||||
String get clearAllMaps => 'Očisti sve karte';
|
||||
|
||||
@override
|
||||
String get clearMapsConfirmTitle => 'Očisti sve karte';
|
||||
|
||||
@override
|
||||
String get clearMapsConfirmMessage =>
|
||||
'Jeste li sigurni da želite izbrisati sve preuzete karte? Ova radnja se ne može poništiti.';
|
||||
|
||||
@override
|
||||
String get mapDownloadCompleted => 'Preuzimanje karte završeno!';
|
||||
|
||||
@override
|
||||
String get cacheClearedSuccessfully => 'Predmemorija uspješno očišćena!';
|
||||
|
||||
@override
|
||||
String get downloadCancelled => 'Preuzimanje otkazano';
|
||||
|
||||
@override
|
||||
String get startingDownload => 'Pokretanje preuzimanja...';
|
||||
|
||||
@override
|
||||
String get downloadingMapTiles => 'Preuzimanje pločica karte...';
|
||||
|
||||
@override
|
||||
String get downloadCompletedSuccessfully => 'Preuzimanje uspješno završeno!';
|
||||
|
||||
@override
|
||||
String get cancellingDownload => 'Otkazivanje preuzimanja...';
|
||||
|
||||
@override
|
||||
String errorLoadingStats(String error) {
|
||||
return 'Greška pri učitavanju statistike: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String downloadFailed(String error) {
|
||||
return 'Preuzimanje nije uspjelo: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String cancelFailed(String error) {
|
||||
return 'Otkazivanje nije uspjelo: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String clearCacheFailed(String error) {
|
||||
return 'Čišćenje predmemorije nije uspjelo: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String minZoomError(String error) {
|
||||
return 'Min zumiranje: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String maxZoomError(String error) {
|
||||
return 'Maks zumiranje: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String get minZoomGreaterThanMax =>
|
||||
'Minimalno zumiranje mora biti manje ili jednako maksimalnom zumiranju';
|
||||
|
||||
@override
|
||||
String get selectMapLayer => 'Odaberite sloj karte';
|
||||
|
||||
@override
|
||||
String get mapOptions => 'Opcije karte';
|
||||
|
||||
@override
|
||||
String get showLegend => 'Prikaži legendu';
|
||||
|
||||
@override
|
||||
String get displayMarkerTypeCounts => 'Prikaži broj vrsta markera';
|
||||
|
||||
@override
|
||||
String get rotateMapWithHeading => 'Rotiraj kartu sa smjerom';
|
||||
|
||||
@override
|
||||
String get mapFollowsDirection => 'Karta slijedi vaš smjer pri kretanju';
|
||||
|
||||
@override
|
||||
String get showMapDebugInfo => 'Prikaži debug informacije karte';
|
||||
|
||||
@override
|
||||
String get displayZoomLevelBounds => 'Prikaži razinu zumiranja i granice';
|
||||
|
||||
@override
|
||||
String get fullscreenMode => 'Način cijelog zaslona';
|
||||
|
||||
@override
|
||||
String get hideUiFullMapView =>
|
||||
'Sakrij sve UI kontrole za prikaz cijele karte';
|
||||
|
||||
@override
|
||||
String get openStreetMap => 'OpenStreetMap';
|
||||
|
||||
@override
|
||||
String get openTopoMap => 'OpenTopoMap';
|
||||
|
||||
@override
|
||||
String get esriSatellite => 'ESRI satelit';
|
||||
|
||||
@override
|
||||
String get downloadVisibleArea => 'Preuzmi vidljivo područje';
|
||||
|
||||
@override
|
||||
String get initializingMap => 'Inicijalizacija karte...';
|
||||
|
||||
@override
|
||||
String get dragToPosition => 'Povuci na poziciju';
|
||||
|
||||
@override
|
||||
String get createSarMarker => 'Kreiraj SAR marker';
|
||||
|
||||
@override
|
||||
String get compass => 'Kompas';
|
||||
|
||||
@override
|
||||
String get navigationAndContacts => 'Navigacija i kontakti';
|
||||
|
||||
@override
|
||||
String get sarAlert => 'SAR UZBUNA';
|
||||
}
|
||||
|
||||
@@ -681,4 +681,211 @@ class AppLocalizationsSl extends AppLocalizations {
|
||||
String latLonFormat(String latitude, String longitude) {
|
||||
return 'Šir: $latitude Dolž: $longitude';
|
||||
}
|
||||
|
||||
@override
|
||||
String get noContactsYet => 'Še ni stikov';
|
||||
|
||||
@override
|
||||
String get connectToDeviceToLoadContacts =>
|
||||
'Povežite se z napravo za nalaganje stikov';
|
||||
|
||||
@override
|
||||
String get teamMembers => 'Člani ekipe';
|
||||
|
||||
@override
|
||||
String get repeaters => 'Repetitorji';
|
||||
|
||||
@override
|
||||
String get rooms => 'Sobe';
|
||||
|
||||
@override
|
||||
String get cacheStatistics => 'Statistika predpomnilnika';
|
||||
|
||||
@override
|
||||
String get totalTiles => 'Skupaj ploščic';
|
||||
|
||||
@override
|
||||
String get cacheSize => 'Velikost predpomnilnika';
|
||||
|
||||
@override
|
||||
String get storeName => 'Ime skladišča';
|
||||
|
||||
@override
|
||||
String get noCacheStatistics => 'Statistika predpomnilnika ni na voljo';
|
||||
|
||||
@override
|
||||
String get downloadRegion => 'Prenesi regijo';
|
||||
|
||||
@override
|
||||
String get mapLayer => 'Sloj zemljevida';
|
||||
|
||||
@override
|
||||
String get regionBounds => 'Meje regije';
|
||||
|
||||
@override
|
||||
String get north => 'Sever';
|
||||
|
||||
@override
|
||||
String get south => 'Jug';
|
||||
|
||||
@override
|
||||
String get east => 'Vzhod';
|
||||
|
||||
@override
|
||||
String get west => 'Zahod';
|
||||
|
||||
@override
|
||||
String get zoomLevels => 'Nivoji povečave';
|
||||
|
||||
@override
|
||||
String minZoom(int zoom) {
|
||||
return 'Min: $zoom';
|
||||
}
|
||||
|
||||
@override
|
||||
String maxZoom(int zoom) {
|
||||
return 'Maks: $zoom';
|
||||
}
|
||||
|
||||
@override
|
||||
String get downloadingDots => 'Prenašanje...';
|
||||
|
||||
@override
|
||||
String get cancelDownload => 'Prekliči prenos';
|
||||
|
||||
@override
|
||||
String get downloadRegionButton => 'Prenesi regijo';
|
||||
|
||||
@override
|
||||
String get downloadNote =>
|
||||
'Opomba: Velike regije ali visoki nivoji povečave lahko zahtevajo veliko časa in prostora za shranjevanje.';
|
||||
|
||||
@override
|
||||
String get cacheManagement => 'Upravljanje predpomnilnika';
|
||||
|
||||
@override
|
||||
String get clearAllMaps => 'Počisti vse zemljevide';
|
||||
|
||||
@override
|
||||
String get clearMapsConfirmTitle => 'Počisti vse zemljevide';
|
||||
|
||||
@override
|
||||
String get clearMapsConfirmMessage =>
|
||||
'Ste prepričani, da želite izbrisati vse prenesene zemljevide? Tega dejanja ni mogoče razveljaviti.';
|
||||
|
||||
@override
|
||||
String get mapDownloadCompleted => 'Prenos zemljevida končan!';
|
||||
|
||||
@override
|
||||
String get cacheClearedSuccessfully => 'Predpomnilnik uspešno počiščen!';
|
||||
|
||||
@override
|
||||
String get downloadCancelled => 'Prenos preklican';
|
||||
|
||||
@override
|
||||
String get startingDownload => 'Začetek prenosa...';
|
||||
|
||||
@override
|
||||
String get downloadingMapTiles => 'Prenašanje ploščic zemljevida...';
|
||||
|
||||
@override
|
||||
String get downloadCompletedSuccessfully => 'Prenos uspešno končan!';
|
||||
|
||||
@override
|
||||
String get cancellingDownload => 'Preklic prenosa...';
|
||||
|
||||
@override
|
||||
String errorLoadingStats(String error) {
|
||||
return 'Napaka pri nalaganju statistike: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String downloadFailed(String error) {
|
||||
return 'Prenos ni uspel: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String cancelFailed(String error) {
|
||||
return 'Preklic ni uspel: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String clearCacheFailed(String error) {
|
||||
return 'Čiščenje predpomnilnika ni uspelo: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String minZoomError(String error) {
|
||||
return 'Min povečava: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String maxZoomError(String error) {
|
||||
return 'Maks povečava: $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String get minZoomGreaterThanMax =>
|
||||
'Minimalna povečava mora biti manjša ali enaka maksimalni povečavi';
|
||||
|
||||
@override
|
||||
String get selectMapLayer => 'Izberite sloj zemljevida';
|
||||
|
||||
@override
|
||||
String get mapOptions => 'Možnosti zemljevida';
|
||||
|
||||
@override
|
||||
String get showLegend => 'Prikaži legendo';
|
||||
|
||||
@override
|
||||
String get displayMarkerTypeCounts => 'Prikaži število vrst označevalcev';
|
||||
|
||||
@override
|
||||
String get rotateMapWithHeading => 'Rotiraj zemljevid s smerjo';
|
||||
|
||||
@override
|
||||
String get mapFollowsDirection => 'Zemljevid sledi vaši smeri pri gibanju';
|
||||
|
||||
@override
|
||||
String get showMapDebugInfo => 'Prikaži debug informacije zemljevida';
|
||||
|
||||
@override
|
||||
String get displayZoomLevelBounds => 'Prikaži nivo povečave in meje';
|
||||
|
||||
@override
|
||||
String get fullscreenMode => 'Način celozaslonskega prikaza';
|
||||
|
||||
@override
|
||||
String get hideUiFullMapView =>
|
||||
'Skrij vse UI kontrole za poln prikaz zemljevida';
|
||||
|
||||
@override
|
||||
String get openStreetMap => 'OpenStreetMap';
|
||||
|
||||
@override
|
||||
String get openTopoMap => 'OpenTopoMap';
|
||||
|
||||
@override
|
||||
String get esriSatellite => 'ESRI satelit';
|
||||
|
||||
@override
|
||||
String get downloadVisibleArea => 'Prenesi vidno območje';
|
||||
|
||||
@override
|
||||
String get initializingMap => 'Inicializacija zemljevida...';
|
||||
|
||||
@override
|
||||
String get dragToPosition => 'Povleci na položaj';
|
||||
|
||||
@override
|
||||
String get createSarMarker => 'Ustvari SAR označevalec';
|
||||
|
||||
@override
|
||||
String get compass => 'Kompas';
|
||||
|
||||
@override
|
||||
String get navigationAndContacts => 'Navigacija in stiki';
|
||||
|
||||
@override
|
||||
String get sarAlert => 'SAR ALARM';
|
||||
}
|
||||
|
||||
@@ -391,5 +391,149 @@
|
||||
|
||||
"degreesLeft": "{degrees}° levo",
|
||||
|
||||
"latLonFormat": "Šir: {latitude} Dolž: {longitude}"
|
||||
"latLonFormat": "Šir: {latitude} Dolž: {longitude}",
|
||||
|
||||
"noContactsYet": "Še ni stikov",
|
||||
|
||||
"connectToDeviceToLoadContacts": "Povežite se z napravo za nalaganje stikov",
|
||||
|
||||
"teamMembers": "Člani ekipe",
|
||||
|
||||
"repeaters": "Repetitorji",
|
||||
|
||||
"rooms": "Sobe",
|
||||
|
||||
"cacheStatistics": "Statistika predpomnilnika",
|
||||
|
||||
"totalTiles": "Skupaj ploščic",
|
||||
|
||||
"cacheSize": "Velikost predpomnilnika",
|
||||
|
||||
"storeName": "Ime skladišča",
|
||||
|
||||
"noCacheStatistics": "Statistika predpomnilnika ni na voljo",
|
||||
|
||||
"downloadRegion": "Prenesi regijo",
|
||||
|
||||
"mapLayer": "Sloj zemljevida",
|
||||
|
||||
"regionBounds": "Meje regije",
|
||||
|
||||
"north": "Sever",
|
||||
|
||||
"south": "Jug",
|
||||
|
||||
"east": "Vzhod",
|
||||
|
||||
"west": "Zahod",
|
||||
|
||||
"zoomLevels": "Nivoji povečave",
|
||||
|
||||
"minZoom": "Min: {zoom}",
|
||||
|
||||
"maxZoom": "Maks: {zoom}",
|
||||
|
||||
"downloadingDots": "Prenašanje...",
|
||||
|
||||
"cancelDownload": "Prekliči prenos",
|
||||
|
||||
"downloadRegionButton": "Prenesi regijo",
|
||||
|
||||
"downloadNote": "Opomba: Velike regije ali visoki nivoji povečave lahko zahtevajo veliko časa in prostora za shranjevanje.",
|
||||
|
||||
"cacheManagement": "Upravljanje predpomnilnika",
|
||||
|
||||
"clearAllMaps": "Počisti vse zemljevide",
|
||||
|
||||
"clearMapsConfirmTitle": "Počisti vse zemljevide",
|
||||
|
||||
"clearMapsConfirmMessage": "Ste prepričani, da želite izbrisati vse prenesene zemljevide? Tega dejanja ni mogoče razveljaviti.",
|
||||
|
||||
"mapDownloadCompleted": "Prenos zemljevida končan!",
|
||||
|
||||
"cacheClearedSuccessfully": "Predpomnilnik uspešno počiščen!",
|
||||
|
||||
"downloadCancelled": "Prenos preklican",
|
||||
|
||||
"startingDownload": "Začetek prenosa...",
|
||||
|
||||
"downloadingMapTiles": "Prenašanje ploščic zemljevida...",
|
||||
|
||||
"downloadCompletedSuccessfully": "Prenos uspešno končan!",
|
||||
|
||||
"cancellingDownload": "Preklic prenosa...",
|
||||
|
||||
"errorLoadingStats": "Napaka pri nalaganju statistike: {error}",
|
||||
|
||||
"downloadFailed": "Prenos ni uspel: {error}",
|
||||
|
||||
"cancelFailed": "Preklic ni uspel: {error}",
|
||||
|
||||
"clearCacheFailed": "Čiščenje predpomnilnika ni uspelo: {error}",
|
||||
|
||||
"minZoomError": "Min povečava: {error}",
|
||||
|
||||
"maxZoomError": "Maks povečava: {error}",
|
||||
|
||||
"minZoomGreaterThanMax": "Minimalna povečava mora biti manjša ali enaka maksimalni povečavi",
|
||||
|
||||
"selectMapLayer": "Izberite sloj zemljevida",
|
||||
|
||||
"mapOptions": "Možnosti zemljevida",
|
||||
|
||||
"showLegend": "Prikaži legendo",
|
||||
|
||||
"displayMarkerTypeCounts": "Prikaži število vrst označevalcev",
|
||||
|
||||
"rotateMapWithHeading": "Rotiraj zemljevid s smerjo",
|
||||
|
||||
"mapFollowsDirection": "Zemljevid sledi vaši smeri pri gibanju",
|
||||
|
||||
"showMapDebugInfo": "Prikaži debug informacije zemljevida",
|
||||
|
||||
"displayZoomLevelBounds": "Prikaži nivo povečave in meje",
|
||||
|
||||
"fullscreenMode": "Način celozaslonskega prikaza",
|
||||
|
||||
"hideUiFullMapView": "Skrij vse UI kontrole za poln prikaz zemljevida",
|
||||
|
||||
"openStreetMap": "OpenStreetMap",
|
||||
|
||||
"openTopoMap": "OpenTopoMap",
|
||||
|
||||
"esriSatellite": "ESRI satelit",
|
||||
|
||||
"downloadVisibleArea": "Prenesi vidno območje",
|
||||
|
||||
"initializingMap": "Inicializacija zemljevida...",
|
||||
|
||||
"dragToPosition": "Povleci na položaj",
|
||||
|
||||
"createSarMarker": "Ustvari SAR označevalec",
|
||||
|
||||
"compass": "Kompas",
|
||||
|
||||
"navigationAndContacts": "Navigacija in stiki",
|
||||
|
||||
"sarAlert": "SAR ALARM",
|
||||
|
||||
"justNow": "Pravkar",
|
||||
|
||||
"minutesAgo": "pred {minutes}m",
|
||||
|
||||
"hoursAgo": "pred {hours}h",
|
||||
|
||||
"daysAgo": "pred {days}d",
|
||||
|
||||
"secondsAgo": "pred {seconds}s",
|
||||
|
||||
"sending": "Pošiljanje...",
|
||||
|
||||
"sent": "Poslano",
|
||||
|
||||
"delivered": "Dostavljeno",
|
||||
|
||||
"deliveredWithTime": "Dostavljeno ({time}ms)",
|
||||
|
||||
"failed": "Neuspešno"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../l10n/app_localizations.dart';
|
||||
|
||||
enum MapLayerType {
|
||||
openStreetMap,
|
||||
openTopoMap,
|
||||
@@ -19,6 +22,19 @@ class MapLayer {
|
||||
required this.maxZoom,
|
||||
});
|
||||
|
||||
/// Get localized name for the layer
|
||||
String getLocalizedName(BuildContext context) {
|
||||
final localizations = AppLocalizations.of(context)!;
|
||||
switch (type) {
|
||||
case MapLayerType.openStreetMap:
|
||||
return localizations.openStreetMap;
|
||||
case MapLayerType.openTopoMap:
|
||||
return localizations.openTopoMap;
|
||||
case MapLayerType.esriWorldImagery:
|
||||
return localizations.esriSatellite;
|
||||
}
|
||||
}
|
||||
|
||||
static const openStreetMap = MapLayer(
|
||||
type: MapLayerType.openStreetMap,
|
||||
name: 'OpenStreetMap',
|
||||
|
||||
@@ -179,8 +179,8 @@ class AppProvider with ChangeNotifier {
|
||||
);
|
||||
}
|
||||
|
||||
// Sync device time
|
||||
await connectionProvider.syncDeviceTime();
|
||||
// Note: Device clock is automatically synced during connection in MeshCoreBleService
|
||||
// No need to sync it again here
|
||||
|
||||
// Get battery and storage information
|
||||
await connectionProvider.getBatteryAndStorage();
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
],
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
|
||||
@@ -199,8 +199,17 @@ class MeshCoreBleService {
|
||||
await _connectionManager.disconnect();
|
||||
}
|
||||
|
||||
/// Send initial device query
|
||||
/// Send initial device query and sync clock
|
||||
Future<void> _sendDeviceQuery() async {
|
||||
// CRITICAL: Set device clock FIRST, before any other commands
|
||||
// This ensures the device has correct timestamps for all operations
|
||||
print('⏰ [Service] Setting device clock before device query');
|
||||
await _commandSender.writeData(FrameBuilder.buildSetDeviceTime());
|
||||
|
||||
// Small delay to ensure clock is set before proceeding
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
// Now send device query and app start
|
||||
await _commandSender.writeData(FrameBuilder.buildDeviceQuery());
|
||||
await _commandSender.writeData(FrameBuilder.buildAppStart());
|
||||
}
|
||||
|
||||
24
lib/utils/sar_marker_extensions.dart
Normal file
24
lib/utils/sar_marker_extensions.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import '../models/sar_marker.dart';
|
||||
import '../l10n/app_localizations.dart';
|
||||
|
||||
/// Extension for SarMarkerType to provide localized display names
|
||||
extension SarMarkerTypeLocalization on SarMarkerType {
|
||||
/// Get localized display name for this SAR marker type
|
||||
String getLocalizedName(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
switch (this) {
|
||||
case SarMarkerType.foundPerson:
|
||||
return l10n.foundPerson;
|
||||
case SarMarkerType.fire:
|
||||
return l10n.fire;
|
||||
case SarMarkerType.stagingArea:
|
||||
return l10n.stagingArea;
|
||||
case SarMarkerType.object:
|
||||
return 'Object'; // Not commonly used, keeping English for now
|
||||
case SarMarkerType.unknown:
|
||||
return 'Unknown'; // Not commonly used, keeping English for now
|
||||
}
|
||||
}
|
||||
}
|
||||
25
lib/utils/time_ago_extensions.dart
Normal file
25
lib/utils/time_ago_extensions.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import '../l10n/app_localizations.dart';
|
||||
|
||||
/// Extension to provide localized "time ago" formatting
|
||||
extension TimeAgoExtension on Duration {
|
||||
/// Get localized time ago string
|
||||
String toLocalizedTimeAgo(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
if (inMinutes < 1) return l10n.justNow;
|
||||
if (inMinutes < 60) return l10n.minutesAgo(inMinutes);
|
||||
if (inHours < 24) return l10n.hoursAgo(inHours);
|
||||
return l10n.daysAgo(inDays);
|
||||
}
|
||||
|
||||
/// Get localized time ago string with seconds support
|
||||
String toLocalizedTimeAgoWithSeconds(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
if (inSeconds < 60) return l10n.secondsAgo(inSeconds);
|
||||
if (inMinutes < 60) return l10n.minutesAgo(inMinutes);
|
||||
if (inHours < 24) return l10n.hoursAgo(inHours);
|
||||
return l10n.daysAgo(inDays);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'dart:math';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
import '../../../models/contact.dart';
|
||||
|
||||
/// Contact list section for the compass dialog.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'dart:math';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
import '../../../models/sar_marker.dart';
|
||||
|
||||
/// SAR marker list section for the compass dialog.
|
||||
|
||||
@@ -13,6 +13,7 @@ import 'compass/compass_header.dart';
|
||||
import 'compass/compass_filters.dart';
|
||||
import 'compass/compass_sar_list.dart';
|
||||
import 'compass/compass_contact_list.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
|
||||
enum HeadingAccuracySeverity { low, medium, high }
|
||||
|
||||
@@ -285,19 +286,19 @@ class _DetailedCompassDialogState extends State<DetailedCompassDialog> {
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
const Expanded(
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'Compass',
|
||||
style: TextStyle(
|
||||
AppLocalizations.of(context)!.compass,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'Navigation & Contacts',
|
||||
style: TextStyle(
|
||||
AppLocalizations.of(context)!.navigationAndContacts,
|
||||
style: const TextStyle(
|
||||
color: Colors.grey,
|
||||
fontSize: 14,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user