move share Gif to submenu and add actions to share current location and emoji.

This commit is contained in:
ZIER 2026-03-09 11:07:33 +01:00
parent a1b77bb29b
commit b3af828413
31 changed files with 269 additions and 3 deletions

View file

@ -453,6 +453,9 @@
}
},
"chat_sendGif": "Изпрати GIF",
"chat_insertEmoji": "Вмъкнете емоджи",
"chat_shareLocation": "Споделете местоположение",
"chat_locationUnavailable": "Местоположението не е налично",
"chat_reply": "Отговори",
"chat_addReaction": "Добави Реакция",
"chat_me": "Аз",

View file

@ -453,6 +453,9 @@
}
},
"chat_sendGif": "GIF senden",
"chat_insertEmoji": "Emoji einfügen",
"chat_shareLocation": "Standort teilen",
"chat_locationUnavailable": "Standort nicht verfügbar",
"chat_reply": "Beantworten",
"chat_addReaction": "Reaktion hinzufügen",
"chat_me": "Ich",

View file

@ -577,6 +577,9 @@
}
},
"chat_sendGif": "Send GIF",
"chat_insertEmoji": "Insert emoji",
"chat_shareLocation": "Share location",
"chat_locationUnavailable": "Location not available",
"chat_reply": "Reply",
"chat_addReaction": "Add Reaction",
"chat_me": "Me",
@ -810,6 +813,7 @@
"map_guessedLocation": "Guessed location",
"map_lastSeenTime": "Last Seen Time",
"map_sharedPin": "Shared pin",
"map_sharedAt": "Shared",
"map_joinRoom": "Join Room",
"map_manageRepeater": "Manage Repeater",
"map_tapToAdd": "Tap on nodes to add them to the path.",

View file

@ -453,6 +453,9 @@
}
},
"chat_sendGif": "Enviar GIF",
"chat_insertEmoji": "Insertar emoji",
"chat_shareLocation": "Compartir ubicación",
"chat_locationUnavailable": "Ubicación no disponible",
"chat_reply": "Responder",
"chat_addReaction": "Añadir Reacción",
"chat_me": "Yo",

View file

@ -453,6 +453,9 @@
}
},
"chat_sendGif": "Envoyer GIF",
"chat_insertEmoji": "Insérer un emoji",
"chat_shareLocation": "Partager la localisation",
"chat_locationUnavailable": "Localisation non disponible",
"chat_reply": "Répondre",
"chat_addReaction": "Ajouter une Réaction",
"chat_me": "Moi",

View file

@ -453,6 +453,9 @@
}
},
"chat_sendGif": "Invia GIF",
"chat_insertEmoji": "Inserisci emoji",
"chat_shareLocation": "Condividi posizione",
"chat_locationUnavailable": "Posizione non disponibile",
"chat_reply": "Rispondi",
"chat_addReaction": "Aggiungi Reazione",
"chat_me": "Me",

View file

@ -2074,6 +2074,18 @@ abstract class AppLocalizations {
/// **'Send GIF'**
String get chat_sendGif;
/// No description provided for @chat_shareLocation.
///
/// In en, this message translates to:
/// **'Share location'**
String get chat_shareLocation;
/// No description provided for @chat_locationUnavailable.
///
/// In en, this message translates to:
/// **'Location not available'**
String get chat_locationUnavailable;
/// No description provided for @chat_reply.
///
/// In en, this message translates to:
@ -2806,6 +2818,12 @@ abstract class AppLocalizations {
/// **'Shared pin'**
String get map_sharedPin;
/// No description provided for @map_sharedAt.
///
/// In en, this message translates to:
/// **'Shared'**
String get map_sharedAt;
/// No description provided for @map_joinRoom.
///
/// In en, this message translates to:

View file

@ -1116,6 +1116,12 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get chat_sendGif => 'GIF senden';
@override
String get chat_shareLocation => 'Standort teilen';
@override
String get chat_locationUnavailable => 'Standort nicht verfügbar';
@override
String get chat_reply => 'Beantworten';
@ -1540,6 +1546,9 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get map_sharedPin => 'Gemeinsames Passwort';
@override
String get map_sharedAt => 'Gemeinsam';
@override
String get map_joinRoom => 'Beitreten Sie dem Raum';

View file

@ -1097,6 +1097,12 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get chat_sendGif => 'Send GIF';
@override
String get chat_shareLocation => 'Share location';
@override
String get chat_locationUnavailable => 'Location not available';
@override
String get chat_reply => 'Reply';
@ -1515,6 +1521,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get map_sharedPin => 'Shared pin';
@override
String get map_sharedAt => 'Shared';
@override
String get map_joinRoom => 'Join Room';

View file

@ -1115,6 +1115,12 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get chat_sendGif => 'Enviar GIF';
@override
String get chat_shareLocation => 'Compartir ubicación';
@override
String get chat_locationUnavailable => 'Ubicación no disponible';
@override
String get chat_reply => 'Responder';
@ -1538,6 +1544,9 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get map_sharedPin => 'Pin compartido';
@override
String get map_sharedAt => 'Compartido';
@override
String get map_joinRoom => 'Únete a la sala';

View file

@ -1117,6 +1117,12 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get chat_sendGif => 'Envoyer GIF';
@override
String get chat_shareLocation => 'Partager la localisation';
@override
String get chat_locationUnavailable => 'Localisation non disponible';
@override
String get chat_reply => 'Répondre';
@ -1545,6 +1551,9 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get map_sharedPin => 'Clé partagée';
@override
String get map_sharedAt => 'Partagé';
@override
String get map_joinRoom => 'Rejoindre la salle';

View file

@ -1114,6 +1114,12 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get chat_sendGif => 'Invia GIF';
@override
String get chat_shareLocation => 'Condividi posizione';
@override
String get chat_locationUnavailable => 'Posizione non disponibile';
@override
String get chat_reply => 'Rispondi';
@ -1537,6 +1543,9 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get map_sharedPin => 'Condividi PIN';
@override
String get map_sharedAt => 'Condiviso';
@override
String get map_joinRoom => 'Unisciti alla stanza';

View file

@ -1530,6 +1530,9 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get map_sharedPin => 'Gedeelde pin';
@override
String get map_sharedAt => 'Gedeeld';
@override
String get map_joinRoom => 'Sluit Kamer';

View file

@ -1115,6 +1115,12 @@ class AppLocalizationsPl extends AppLocalizations {
@override
String get chat_sendGif => 'Wyślij GIF';
@override
String get chat_shareLocation => 'Udostępnij lokalizację';
@override
String get chat_locationUnavailable => 'Lokalizacja niedostępna';
@override
String get chat_reply => 'Odpowiedz';
@ -1539,6 +1545,9 @@ class AppLocalizationsPl extends AppLocalizations {
@override
String get map_sharedPin => 'Podzielony PIN';
@override
String get map_sharedAt => 'Udostępnione';
@override
String get map_joinRoom => 'Dołącz do pokoju';

View file

@ -1115,6 +1115,12 @@ class AppLocalizationsPt extends AppLocalizations {
@override
String get chat_sendGif => 'Enviar GIF';
@override
String get chat_shareLocation => 'Compartilhar local';
@override
String get chat_locationUnavailable => 'Localização indisponível';
@override
String get chat_reply => 'Responder';
@ -1539,6 +1545,9 @@ class AppLocalizationsPt extends AppLocalizations {
@override
String get map_sharedPin => 'Pin compartilhado';
@override
String get map_sharedAt => 'Compartilhado';
@override
String get map_joinRoom => 'Junte-se à Sala';

View file

@ -1114,6 +1114,12 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get chat_sendGif => 'Отправить GIF';
@override
String get chat_shareLocation => 'Поделиться местоположением';
@override
String get chat_locationUnavailable => 'Местоположение недоступно';
@override
String get chat_reply => 'Ответить';
@ -1541,6 +1547,9 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get map_sharedPin => 'Общая метка';
@override
String get map_sharedAt => 'Поделился';
@override
String get map_joinRoom => 'Присоединиться к комнате';

View file

@ -1108,6 +1108,12 @@ class AppLocalizationsSk extends AppLocalizations {
@override
String get chat_sendGif => 'Odoslať GIF';
@override
String get chat_shareLocation => 'Zdieľať polohu';
@override
String get chat_locationUnavailable => 'Poloha nie je k dispozícii';
@override
String get chat_reply => 'Odpovedať';
@ -1533,6 +1539,9 @@ class AppLocalizationsSk extends AppLocalizations {
@override
String get map_sharedPin => 'Zdieľaný PIN';
@override
String get map_sharedAt => 'Zdieľané';
@override
String get map_joinRoom => 'Pripojiť miestnosť';

View file

@ -1105,6 +1105,12 @@ class AppLocalizationsSl extends AppLocalizations {
@override
String get chat_sendGif => 'Pošlji GIF';
@override
String get chat_shareLocation => 'Deli lokacijo';
@override
String get chat_locationUnavailable => 'Lokacija ni na voljo';
@override
String get chat_reply => 'Odgovori';
@ -1526,6 +1532,9 @@ class AppLocalizationsSl extends AppLocalizations {
@override
String get map_sharedPin => 'Deljeno naslovno geslo';
@override
String get map_sharedAt => 'Deljeno';
@override
String get map_joinRoom => 'Pridružiti sobo';

View file

@ -1102,6 +1102,12 @@ class AppLocalizationsSv extends AppLocalizations {
@override
String get chat_sendGif => 'Skicka GIF';
@override
String get chat_shareLocation => 'Dela plats';
@override
String get chat_locationUnavailable => 'Plats inte tillgänglig';
@override
String get chat_reply => 'Svara';

View file

@ -1109,6 +1109,12 @@ class AppLocalizationsUk extends AppLocalizations {
@override
String get chat_sendGif => 'Надіслати GIF';
@override
String get chat_shareLocation => 'Поділитися місцезнаходженням';
@override
String get chat_locationUnavailable => 'Місцезнаходження недоступне';
@override
String get chat_reply => 'Відповісти';

View file

@ -1053,6 +1053,12 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get chat_sendGif => '发送 GIF';
@override
String get chat_shareLocation => '共享位置';
@override
String get chat_locationUnavailable => '位置不可用';
@override
String get chat_reply => '回复';

View file

@ -453,6 +453,9 @@
}
},
"chat_sendGif": "GIF verzenden",
"chat_insertEmoji": "Emoji invoegen",
"chat_shareLocation": "Locatie delen",
"chat_locationUnavailable": "Locatie niet beschikbaar",
"chat_reply": "Reageren",
"chat_addReaction": "Reactie toevoegen",
"chat_me": "Mijn",

View file

@ -453,6 +453,9 @@
}
},
"chat_sendGif": "Wyślij GIF",
"chat_insertEmoji": "Wstaw emoji",
"chat_shareLocation": "Udostępnij lokalizację",
"chat_locationUnavailable": "Lokalizacja niedostępna",
"chat_reply": "Odpowiedz",
"chat_addReaction": "Dodaj Reakcję",
"chat_me": "Ja",

View file

@ -453,6 +453,9 @@
}
},
"chat_sendGif": "Enviar GIF",
"chat_insertEmoji": "Inserir emoji",
"chat_shareLocation": "Compartilhar local",
"chat_locationUnavailable": "Localização indisponível",
"chat_reply": "Responder",
"chat_addReaction": "Adicionar Reação",
"chat_me": "Eu",

View file

@ -284,6 +284,9 @@
"chat_retryingMessage": "Повтор отправки сообщения",
"chat_retryCount": "Попытка {current}/{max}",
"chat_sendGif": "Отправить GIF",
"chat_insertEmoji": "Вставить эмодзи",
"chat_shareLocation": "Поделиться местоположением",
"chat_locationUnavailable": "Местоположение недоступно",
"chat_reply": "Ответить",
"chat_addReaction": "Добавить реакцию",
"chat_me": "Я",

View file

@ -453,6 +453,9 @@
}
},
"chat_sendGif": "Odoslať GIF",
"chat_insertEmoji": "Vložiť emoji",
"chat_shareLocation": "Zdieľať polohu",
"chat_locationUnavailable": "Poloha nie je k dispozícii",
"chat_reply": "Odpovedať",
"chat_addReaction": "Pridať Reakciu",
"chat_me": "Mne",

View file

@ -453,6 +453,9 @@
}
},
"chat_sendGif": "Pošlji GIF",
"chat_insertEmoji": "Vstavi emoji",
"chat_shareLocation": "Deli lokacijo",
"chat_locationUnavailable": "Lokacija ni na voljo",
"chat_reply": "Odgovori",
"chat_addReaction": "Dodaj reakcijo",
"chat_me": "jaz",

View file

@ -453,6 +453,9 @@
}
},
"chat_sendGif": "Skicka GIF",
"chat_insertEmoji": "Infoga emoji",
"chat_shareLocation": "Dela plats",
"chat_locationUnavailable": "Plats inte tillgänglig",
"chat_reply": "Svara",
"chat_addReaction": "Lägg till reaktion",
"chat_me": "Mig",

View file

@ -454,6 +454,9 @@
}
},
"chat_sendGif": "Надіслати GIF",
"chat_insertEmoji": "Вставити емодзі",
"chat_shareLocation": "Поділитися місцезнаходженням",
"chat_locationUnavailable": "Місцезнаходження недоступне",
"chat_reply": "Відповісти",
"chat_addReaction": "Додати реакцію",
"chat_me": "Я",

View file

@ -37,6 +37,8 @@ import '../widgets/path_selection_dialog.dart';
import '../utils/app_logger.dart';
import '../l10n/l10n.dart';
enum _ChatInputAction { sendGif, insertEmoji, shareLocation }
class ChatScreen extends StatefulWidget {
final Contact contact;
@ -343,10 +345,51 @@ class _ChatScreenState extends State<ChatScreen> {
child: SafeArea(
child: Row(
children: [
IconButton(
icon: const Icon(Icons.gif_box),
onPressed: () => _showGifPicker(context),
PopupMenuButton<_ChatInputAction>(
icon: const Icon(Icons.add),
tooltip: context.l10n.chat_sendGif,
offset: const Offset(0, -8),
onSelected: (action) {
if (action == _ChatInputAction.sendGif) {
_showGifPicker(context);
} else if (action == _ChatInputAction.insertEmoji) {
_showEmojiPicker(context);
} else if (action == _ChatInputAction.shareLocation) {
_shareLocation(context.read<MeshCoreConnector>());
}
},
itemBuilder: (context) => [
PopupMenuItem(
value: _ChatInputAction.sendGif,
child: Row(
children: [
const Icon(Icons.gif_box, size: 20),
const SizedBox(width: 8),
Text(context.l10n.chat_sendGif),
],
),
),
PopupMenuItem(
value: _ChatInputAction.insertEmoji,
child: Row(
children: [
const Icon(Icons.emoji_emotions, size: 20),
const SizedBox(width: 8),
Text(context.l10n.chat_insertEmoji),
],
),
),
PopupMenuItem(
value: _ChatInputAction.shareLocation,
child: Row(
children: [
const Icon(Icons.my_location, size: 20),
const SizedBox(width: 8),
Text(context.l10n.chat_shareLocation),
],
),
),
],
),
Expanded(
child: ValueListenableBuilder<TextEditingValue>(
@ -433,6 +476,52 @@ class _ChatScreenState extends State<ChatScreen> {
return match?.group(1);
}
void _insertTextAtCursor(String text) {
final currentValue = _textController.value;
final selection = currentValue.selection;
final newText = selection.isValid
? currentValue.text.replaceRange(
selection.start, selection.end, text)
: currentValue.text + text;
final caret = (selection.isValid ? selection.start : currentValue.text.length) +
text.length;
_textController.value = currentValue.copyWith(
text: newText,
selection: TextSelection.collapsed(offset: caret),
);
}
void _showEmojiPicker(BuildContext context) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => EmojiPicker(
onEmojiSelected: (emoji) {
_insertTextAtCursor(emoji);
_textFieldFocusNode.requestFocus();
},
),
);
}
void _shareLocation(MeshCoreConnector connector) async {
final lat = connector.selfLatitude;
final lon = connector.selfLongitude;
if (lat == null || lon == null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.chat_locationUnavailable)),
);
return;
}
// Use the contact name + ISO timestamp as the marker label so the recipient
// can see when the location was shared.
final label = '${widget.contact.name}: ${DateTime.now().toUtc().toIso8601String()}';
final markerText = 'm:${lat.toStringAsFixed(6)},${lon.toStringAsFixed(6)}|$label|loc';
connector.sendMessage(widget.contact, markerText);
}
void _showGifPicker(BuildContext context) {
showModalBottomSheet(
context: context,

View file

@ -1061,6 +1061,7 @@ class _MapScreenState extends State<MapScreen> {
flags: payload.flags,
fromName: fromName,
sourceLabel: contact.name,
timestamp: message.timestamp,
isChannel: false,
isPublicChannel: false,
),
@ -1089,6 +1090,7 @@ class _MapScreenState extends State<MapScreen> {
sourceLabel: channel.name.isEmpty
? 'Channel ${channel.index}'
: channel.name,
timestamp: message.timestamp,
isChannel: true,
isPublicChannel: isPublic,
),
@ -1335,6 +1337,7 @@ class _MapScreenState extends State<MapScreen> {
children: [
_buildInfoRow(context.l10n.map_from, marker.fromName),
_buildInfoRow(context.l10n.map_source, marker.sourceLabel),
_buildInfoRow(context.l10n.map_sharedAt, _formatLastSeen(marker.timestamp)),
_buildInfoRow(
'Location',
'${marker.position.latitude.toStringAsFixed(6)}, ${marker.position.longitude.toStringAsFixed(6)}',
@ -2039,6 +2042,7 @@ class _SharedMarker {
final String flags;
final String fromName;
final String sourceLabel;
final DateTime timestamp;
final bool isChannel;
final bool isPublicChannel;
@ -2049,6 +2053,7 @@ class _SharedMarker {
required this.flags,
required this.fromName,
required this.sourceLabel,
required this.timestamp,
required this.isChannel,
required this.isPublicChannel,
});