diff --git a/lib/l10n/app_hr.arb b/lib/l10n/app_hr.arb index 5603021..6e4024a 100644 --- a/lib/l10n/app_hr.arb +++ b/lib/l10n/app_hr.arb @@ -535,5 +535,37 @@ "deliveredWithTime": "Dostavljeno ({time}ms)", - "failed": "Neuspjelo" + "failed": "Neuspjelo", + + "messageSentToPublicChannel": "Poruka poslana na javni kanal", + + "pleaseSelectRoomToSendSar": "Molimo odaberite sobu za slanje SAR markera", + + "failedToSendSarMarker": "Neuspjelo slanje SAR markera: {error}", + + "sarMarkerSentTo": "SAR marker poslan u {roomName}", + + "notConnectedCannotSync": "Nije povezano - ne može se sinkronizirati poruke", + + "syncedMessageCount": "Sinkronizirano {count} poruka", + + "noNewMessages": "Nema novih poruka", + + "syncFailed": "Sinkronizacija nije uspjela: {error}", + + "failedToResendMessage": "Neuspjelo ponovno slanje poruke", + + "retryingMessage": "Ponovni pokušaj slanja poruke...", + + "retryFailed": "Ponovni pokušaj nije uspio: {error}", + + "textCopiedToClipboard": "Tekst kopiran u međuspremnik", + + "cannotReplySenderMissing": "Ne mogu odgovoriti: informacije o pošiljatelju nedostaju", + + "cannotReplyContactNotFound": "Ne mogu odgovoriti: kontakt nije pronađen", + + "messageDeleted": "Poruka izbrisana", + + "refreshedContacts": "Kontakti osvježeni" } diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 8aff634..9ecdb22 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -1652,6 +1652,162 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'SAR ALERT'** String get sarAlert; + + /// Success message when message is sent to public channel + /// + /// In en, this message translates to: + /// **'Message sent to public channel'** + String get messageSentToPublicChannel; + + /// Error when no room is selected for SAR marker + /// + /// In en, this message translates to: + /// **'Please select a room to send SAR marker'** + String get pleaseSelectRoomToSendSar; + + /// Error message when SAR marker fails to send + /// + /// In en, this message translates to: + /// **'Failed to send SAR marker: {error}'** + String failedToSendSarMarker(String error); + + /// Success message when SAR marker is sent to room + /// + /// In en, this message translates to: + /// **'SAR marker sent to {roomName}'** + String sarMarkerSentTo(String roomName); + + /// Warning when trying to sync messages while not connected + /// + /// In en, this message translates to: + /// **'Not connected - cannot sync messages'** + String get notConnectedCannotSync; + + /// Success message showing number of synced messages + /// + /// In en, this message translates to: + /// **'Synced {count} message(s)'** + String syncedMessageCount(int count); + + /// Info message when no new messages to sync + /// + /// In en, this message translates to: + /// **'No new messages'** + String get noNewMessages; + + /// Error message when sync fails + /// + /// In en, this message translates to: + /// **'Sync failed: {error}'** + String syncFailed(String error); + + /// Error when message retry fails + /// + /// In en, this message translates to: + /// **'Failed to resend message'** + String get failedToResendMessage; + + /// Info message when retrying a failed message + /// + /// In en, this message translates to: + /// **'Retrying message...'** + String get retryingMessage; + + /// Error message when retry fails + /// + /// In en, this message translates to: + /// **'Retry failed: {error}'** + String retryFailed(String error); + + /// Success message when text is copied + /// + /// In en, this message translates to: + /// **'Text copied to clipboard'** + String get textCopiedToClipboard; + + /// Error when sender info is missing for reply + /// + /// In en, this message translates to: + /// **'Cannot reply: sender information missing'** + String get cannotReplySenderMissing; + + /// Error when contact not found for reply + /// + /// In en, this message translates to: + /// **'Cannot reply: contact not found'** + String get cannotReplyContactNotFound; + + /// Info message when message is deleted + /// + /// In en, this message translates to: + /// **'Message deleted'** + String get messageDeleted; + + /// Success message when contacts are refreshed + /// + /// In en, this message translates to: + /// **'Refreshed contacts'** + String get refreshedContacts; + + /// Time indicator for very recent activity + /// + /// In en, this message translates to: + /// **'Just now'** + String get justNow; + + /// Time indicator for minutes ago + /// + /// In en, this message translates to: + /// **'{minutes}m ago'** + String minutesAgo(int minutes); + + /// Time indicator for hours ago + /// + /// In en, this message translates to: + /// **'{hours}h ago'** + String hoursAgo(int hours); + + /// Time indicator for days ago + /// + /// In en, this message translates to: + /// **'{days}d ago'** + String daysAgo(int days); + + /// Time indicator for seconds ago + /// + /// In en, this message translates to: + /// **'{seconds}s ago'** + String secondsAgo(int seconds); + + /// Delivery status: sending + /// + /// In en, this message translates to: + /// **'Sending...'** + String get sending; + + /// Delivery status: sent + /// + /// In en, this message translates to: + /// **'Sent'** + String get sent; + + /// Delivery status: delivered + /// + /// In en, this message translates to: + /// **'Delivered'** + String get delivered; + + /// Delivery status with round-trip time + /// + /// In en, this message translates to: + /// **'Delivered ({time}ms)'** + String deliveredWithTime(int time); + + /// Delivery status: failed + /// + /// In en, this message translates to: + /// **'Failed'** + String get failed; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index ffb98f6..a336d27 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -888,4 +888,104 @@ class AppLocalizationsEn extends AppLocalizations { @override String get sarAlert => 'SAR ALERT'; + + @override + String get messageSentToPublicChannel => 'Message sent to public channel'; + + @override + String get pleaseSelectRoomToSendSar => + 'Please select a room to send SAR marker'; + + @override + String failedToSendSarMarker(String error) { + return 'Failed to send SAR marker: $error'; + } + + @override + String sarMarkerSentTo(String roomName) { + return 'SAR marker sent to $roomName'; + } + + @override + String get notConnectedCannotSync => 'Not connected - cannot sync messages'; + + @override + String syncedMessageCount(int count) { + return 'Synced $count message(s)'; + } + + @override + String get noNewMessages => 'No new messages'; + + @override + String syncFailed(String error) { + return 'Sync failed: $error'; + } + + @override + String get failedToResendMessage => 'Failed to resend message'; + + @override + String get retryingMessage => 'Retrying message...'; + + @override + String retryFailed(String error) { + return 'Retry failed: $error'; + } + + @override + String get textCopiedToClipboard => 'Text copied to clipboard'; + + @override + String get cannotReplySenderMissing => + 'Cannot reply: sender information missing'; + + @override + String get cannotReplyContactNotFound => 'Cannot reply: contact not found'; + + @override + String get messageDeleted => 'Message deleted'; + + @override + String get refreshedContacts => 'Refreshed contacts'; + + @override + String get justNow => 'Just now'; + + @override + String minutesAgo(int minutes) { + return '${minutes}m ago'; + } + + @override + String hoursAgo(int hours) { + return '${hours}h ago'; + } + + @override + String daysAgo(int days) { + return '${days}d ago'; + } + + @override + String secondsAgo(int seconds) { + return '${seconds}s ago'; + } + + @override + String get sending => 'Sending...'; + + @override + String get sent => 'Sent'; + + @override + String get delivered => 'Delivered'; + + @override + String deliveredWithTime(int time) { + return 'Delivered (${time}ms)'; + } + + @override + String get failed => 'Failed'; } diff --git a/lib/l10n/app_localizations_hr.dart b/lib/l10n/app_localizations_hr.dart index 36ff036..47f310a 100644 --- a/lib/l10n/app_localizations_hr.dart +++ b/lib/l10n/app_localizations_hr.dart @@ -888,4 +888,106 @@ class AppLocalizationsHr extends AppLocalizations { @override String get sarAlert => 'SAR UZBUNA'; + + @override + String get messageSentToPublicChannel => 'Poruka poslana na javni kanal'; + + @override + String get pleaseSelectRoomToSendSar => + 'Molimo odaberite sobu za slanje SAR markera'; + + @override + String failedToSendSarMarker(String error) { + return 'Neuspjelo slanje SAR markera: $error'; + } + + @override + String sarMarkerSentTo(String roomName) { + return 'SAR marker poslan u $roomName'; + } + + @override + String get notConnectedCannotSync => + 'Nije povezano - ne može se sinkronizirati poruke'; + + @override + String syncedMessageCount(int count) { + return 'Sinkronizirano $count poruka'; + } + + @override + String get noNewMessages => 'Nema novih poruka'; + + @override + String syncFailed(String error) { + return 'Sinkronizacija nije uspjela: $error'; + } + + @override + String get failedToResendMessage => 'Neuspjelo ponovno slanje poruke'; + + @override + String get retryingMessage => 'Ponovni pokušaj slanja poruke...'; + + @override + String retryFailed(String error) { + return 'Ponovni pokušaj nije uspio: $error'; + } + + @override + String get textCopiedToClipboard => 'Tekst kopiran u međuspremnik'; + + @override + String get cannotReplySenderMissing => + 'Ne mogu odgovoriti: informacije o pošiljatelju nedostaju'; + + @override + String get cannotReplyContactNotFound => + 'Ne mogu odgovoriti: kontakt nije pronađen'; + + @override + String get messageDeleted => 'Poruka izbrisana'; + + @override + String get refreshedContacts => 'Kontakti osvježeni'; + + @override + String get justNow => 'Upravo sada'; + + @override + String minutesAgo(int minutes) { + return 'prije ${minutes}m'; + } + + @override + String hoursAgo(int hours) { + return 'prije ${hours}h'; + } + + @override + String daysAgo(int days) { + return 'prije ${days}d'; + } + + @override + String secondsAgo(int seconds) { + return 'prije ${seconds}s'; + } + + @override + String get sending => 'Slanje...'; + + @override + String get sent => 'Poslano'; + + @override + String get delivered => 'Dostavljeno'; + + @override + String deliveredWithTime(int time) { + return 'Dostavljeno (${time}ms)'; + } + + @override + String get failed => 'Neuspjelo'; } diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index 2c78dc8..c5dee63 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -888,4 +888,106 @@ class AppLocalizationsSl extends AppLocalizations { @override String get sarAlert => 'SAR ALARM'; + + @override + String get messageSentToPublicChannel => 'Sporočilo poslano na javni kanal'; + + @override + String get pleaseSelectRoomToSendSar => + 'Prosimo, izberite sobo za pošiljanje SAR označevalca'; + + @override + String failedToSendSarMarker(String error) { + return 'Pošiljanje SAR označevalca ni uspelo: $error'; + } + + @override + String sarMarkerSentTo(String roomName) { + return 'SAR označevalec poslan v $roomName'; + } + + @override + String get notConnectedCannotSync => + 'Ni povezano - sporočil ni mogoče sinhronizirati'; + + @override + String syncedMessageCount(int count) { + return 'Sinhronizirano $count sporočil'; + } + + @override + String get noNewMessages => 'Ni novih sporočil'; + + @override + String syncFailed(String error) { + return 'Sinhronizacija ni uspela: $error'; + } + + @override + String get failedToResendMessage => 'Ponovno pošiljanje sporočila ni uspelo'; + + @override + String get retryingMessage => 'Ponovni poskus pošiljanja sporočila...'; + + @override + String retryFailed(String error) { + return 'Ponovni poskus ni uspel: $error'; + } + + @override + String get textCopiedToClipboard => 'Besedilo kopirano v odložišče'; + + @override + String get cannotReplySenderMissing => + 'Ni mogoče odgovoriti: informacije o pošiljatelju manjkajo'; + + @override + String get cannotReplyContactNotFound => + 'Ni mogoče odgovoriti: stik ni najden'; + + @override + String get messageDeleted => 'Sporočilo izbrisano'; + + @override + String get refreshedContacts => 'Stiki osveženi'; + + @override + String get justNow => 'Pravkar'; + + @override + String minutesAgo(int minutes) { + return 'pred ${minutes}m'; + } + + @override + String hoursAgo(int hours) { + return 'pred ${hours}h'; + } + + @override + String daysAgo(int days) { + return 'pred ${days}d'; + } + + @override + String secondsAgo(int seconds) { + return 'pred ${seconds}s'; + } + + @override + String get sending => 'Pošiljanje...'; + + @override + String get sent => 'Poslano'; + + @override + String get delivered => 'Dostavljeno'; + + @override + String deliveredWithTime(int time) { + return 'Dostavljeno (${time}ms)'; + } + + @override + String get failed => 'Neuspešno'; } diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index 896600f..ea4ae9e 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -535,5 +535,37 @@ "deliveredWithTime": "Dostavljeno ({time}ms)", - "failed": "Neuspešno" + "failed": "Neuspešno", + + "messageSentToPublicChannel": "Sporočilo poslano na javni kanal", + + "pleaseSelectRoomToSendSar": "Prosimo, izberite sobo za pošiljanje SAR označevalca", + + "failedToSendSarMarker": "Pošiljanje SAR označevalca ni uspelo: {error}", + + "sarMarkerSentTo": "SAR označevalec poslan v {roomName}", + + "notConnectedCannotSync": "Ni povezano - sporočil ni mogoče sinhronizirati", + + "syncedMessageCount": "Sinhronizirano {count} sporočil", + + "noNewMessages": "Ni novih sporočil", + + "syncFailed": "Sinhronizacija ni uspela: {error}", + + "failedToResendMessage": "Ponovno pošiljanje sporočila ni uspelo", + + "retryingMessage": "Ponovni poskus pošiljanja sporočila...", + + "retryFailed": "Ponovni poskus ni uspel: {error}", + + "textCopiedToClipboard": "Besedilo kopirano v odložišče", + + "cannotReplySenderMissing": "Ni mogoče odgovoriti: informacije o pošiljatelju manjkajo", + + "cannotReplyContactNotFound": "Ni mogoče odgovoriti: stik ni najden", + + "messageDeleted": "Sporočilo izbrisano", + + "refreshedContacts": "Stiki osveženi" } diff --git a/lib/screens/messages_tab.dart b/lib/screens/messages_tab.dart index 13e18ba..8ab9962 100644 --- a/lib/screens/messages_tab.dart +++ b/lib/screens/messages_tab.dart @@ -14,6 +14,7 @@ import '../widgets/contacts/direct_message_sheet.dart'; import '../utils/toast_logger.dart'; import '../l10n/app_localizations.dart'; import '../utils/sar_marker_extensions.dart'; +import '../utils/message_extensions.dart'; class MessagesTab extends StatefulWidget { final VoidCallback onNavigateToMap; @@ -919,7 +920,7 @@ class _MessageBubble extends StatelessWidget { ], const Spacer(), Text( - message.timeAgo, + message.getLocalizedTimeAgo(context), style: Theme.of(context).textTheme.labelSmall?.copyWith( fontWeight: isSarMarker ? FontWeight.w600 @@ -997,7 +998,7 @@ class _MessageBubble extends StatelessWidget { ), const SizedBox(width: 3), Text( - message.deliveryStatusText, + message.getLocalizedDeliveryStatus(context), style: Theme.of(context).textTheme.labelSmall?.copyWith( color: _getDeliveryStatusColor(message.deliveryStatus), fontStyle: FontStyle.italic, @@ -1239,7 +1240,7 @@ class _SystemMessageBubble extends StatelessWidget { Icon(_getLevelIcon(level), size: 14, color: levelColor), const SizedBox(width: 6), Text( - message.timeAgo, + message.getLocalizedTimeAgo(context), style: Theme.of(context).textTheme.labelSmall?.copyWith( color: Theme.of( context, diff --git a/lib/utils/message_extensions.dart b/lib/utils/message_extensions.dart new file mode 100644 index 0000000..0fd7df8 --- /dev/null +++ b/lib/utils/message_extensions.dart @@ -0,0 +1,38 @@ +import 'package:flutter/widgets.dart'; +import '../models/message.dart'; +import '../l10n/app_localizations.dart'; + +/// Extension for Message to provide localized delivery status +extension MessageLocalization on Message { + /// Get localized delivery status text + String getLocalizedDeliveryStatus(BuildContext context) { + final l10n = AppLocalizations.of(context)!; + + switch (deliveryStatus) { + case MessageDeliveryStatus.sending: + return l10n.sending; + case MessageDeliveryStatus.sent: + return l10n.sent; + case MessageDeliveryStatus.delivered: + if (roundTripTimeMs != null) { + return l10n.deliveredWithTime(roundTripTimeMs!); + } + return l10n.delivered; + case MessageDeliveryStatus.failed: + return l10n.failed; + case MessageDeliveryStatus.received: + return ''; + } + } + + /// Get localized time ago string + String getLocalizedTimeAgo(BuildContext context) { + final diff = DateTime.now().difference(sentAt); + final l10n = AppLocalizations.of(context)!; + + if (diff.inMinutes < 1) return l10n.justNow; + if (diff.inMinutes < 60) return l10n.minutesAgo(diff.inMinutes); + if (diff.inHours < 24) return l10n.hoursAgo(diff.inHours); + return l10n.daysAgo(diff.inDays); + } +}