From cd9b8e88eb644bd9f788efe9eb57b93c358e3c3f Mon Sep 17 00:00:00 2001 From: Strycher Date: Tue, 14 Jul 2026 12:57:11 -0400 Subject: [PATCH] feat(#234): make own device pubkey full, selectable, and one-tap copyable Settings showed the self public key truncated to 16 hex chars + "..." as plain Text (settings_screen:262/:410), so it couldn't be shared. Show the full key, make it selectable, and add a copy button beside it. - _buildInfoRow gains an optional copyValue: renders the value as SelectableText + a copy IconButton that copies the full key and shows a "Public key copied" snackbar. Both self-pubkey rows pass the full key. - New l10n string settings_publicKeyCopied (regenerated localizations + untranslated.json). Part of #234. Co-Authored-By: Claude Opus 4.8 --- lib/l10n/app_en.arb | 1 + lib/l10n/app_localizations.dart | 6 ++++ lib/l10n/app_localizations_bg.dart | 3 ++ lib/l10n/app_localizations_de.dart | 3 ++ lib/l10n/app_localizations_en.dart | 3 ++ lib/l10n/app_localizations_es.dart | 3 ++ lib/l10n/app_localizations_fr.dart | 3 ++ lib/l10n/app_localizations_hu.dart | 3 ++ lib/l10n/app_localizations_it.dart | 3 ++ lib/l10n/app_localizations_ja.dart | 3 ++ lib/l10n/app_localizations_ko.dart | 3 ++ lib/l10n/app_localizations_nl.dart | 3 ++ lib/l10n/app_localizations_pl.dart | 3 ++ lib/l10n/app_localizations_pt.dart | 3 ++ lib/l10n/app_localizations_ru.dart | 3 ++ lib/l10n/app_localizations_sk.dart | 3 ++ lib/l10n/app_localizations_sl.dart | 3 ++ lib/l10n/app_localizations_sv.dart | 3 ++ lib/l10n/app_localizations_uk.dart | 3 ++ lib/l10n/app_localizations_zh.dart | 3 ++ lib/screens/settings_screen.dart | 50 +++++++++++++++++++++++++----- untranslated.json | 17 ++++++++++ 22 files changed, 120 insertions(+), 8 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f6e4575..6297c90 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -238,6 +238,7 @@ "settings_infoModel": "Model", "settings_infoBattery": "Battery", "settings_infoPublicKey": "Public Key", + "settings_publicKeyCopied": "Public key copied", "settings_infoContactsCount": "Contacts Count", "settings_infoChannelCount": "Channel Count", "settings_presets": "Presets", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 0b4982e..009b545 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -1186,6 +1186,12 @@ abstract class AppLocalizations { /// **'Public Key'** String get settings_infoPublicKey; + /// No description provided for @settings_publicKeyCopied. + /// + /// In en, this message translates to: + /// **'Public key copied'** + String get settings_publicKeyCopied; + /// No description provided for @settings_infoContactsCount. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index 425fb8f..ba2168b 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -596,6 +596,9 @@ class AppLocalizationsBg extends AppLocalizations { @override String get settings_infoPublicKey => 'Общ публичен ключ'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => 'Брой контакти'; diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 5f700a9..7809b58 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -591,6 +591,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get settings_infoPublicKey => 'Öffentlicher Schlüssel'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => 'Anzahl Kontakte'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 764304b..269ecc8 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -581,6 +581,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get settings_infoPublicKey => 'Public Key'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => 'Contacts Count'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index a9fb07f..3d55e51 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -592,6 +592,9 @@ class AppLocalizationsEs extends AppLocalizations { @override String get settings_infoPublicKey => 'Clave Pública'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => 'Número de contactos'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index 525014c..8e660fd 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -596,6 +596,9 @@ class AppLocalizationsFr extends AppLocalizations { @override String get settings_infoPublicKey => 'Clé Publique'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => 'Nombre de contacts'; diff --git a/lib/l10n/app_localizations_hu.dart b/lib/l10n/app_localizations_hu.dart index e980304..e46ea06 100644 --- a/lib/l10n/app_localizations_hu.dart +++ b/lib/l10n/app_localizations_hu.dart @@ -594,6 +594,9 @@ class AppLocalizationsHu extends AppLocalizations { @override String get settings_infoPublicKey => 'Nyelvkönyv'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => 'Kapcsolatok száma'; diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index 7be06e7..b9d938c 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -594,6 +594,9 @@ class AppLocalizationsIt extends AppLocalizations { @override String get settings_infoPublicKey => 'Chiave Pubblica'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => 'Numero contatti'; diff --git a/lib/l10n/app_localizations_ja.dart b/lib/l10n/app_localizations_ja.dart index 7e38e10..d141bc3 100644 --- a/lib/l10n/app_localizations_ja.dart +++ b/lib/l10n/app_localizations_ja.dart @@ -567,6 +567,9 @@ class AppLocalizationsJa extends AppLocalizations { @override String get settings_infoPublicKey => '公開鍵'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => '連絡先数'; diff --git a/lib/l10n/app_localizations_ko.dart b/lib/l10n/app_localizations_ko.dart index 6d4e381..9e7ab48 100644 --- a/lib/l10n/app_localizations_ko.dart +++ b/lib/l10n/app_localizations_ko.dart @@ -567,6 +567,9 @@ class AppLocalizationsKo extends AppLocalizations { @override String get settings_infoPublicKey => '공개 키'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => '연락처 수'; diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index 558412b..22e965e 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -588,6 +588,9 @@ class AppLocalizationsNl extends AppLocalizations { @override String get settings_infoPublicKey => 'Openbare Sleutel'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => 'Aantal Contacten'; diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index 2c0ed90..6b6a168 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -596,6 +596,9 @@ class AppLocalizationsPl extends AppLocalizations { @override String get settings_infoPublicKey => 'Klucz Publiczny'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => 'Liczba kontaktów'; diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index 730bd81..84e8866 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -594,6 +594,9 @@ class AppLocalizationsPt extends AppLocalizations { @override String get settings_infoPublicKey => 'Chave Pública'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => 'Número de Contatos'; diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 8e4b6af..81b7558 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -593,6 +593,9 @@ class AppLocalizationsRu extends AppLocalizations { @override String get settings_infoPublicKey => 'Публичный ключ'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => 'Количество контактов'; diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index 53b8341..5fb717d 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -588,6 +588,9 @@ class AppLocalizationsSk extends AppLocalizations { @override String get settings_infoPublicKey => 'Verejný kľúč'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => 'Počet kontaktov'; diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index 5940652..1b2fae8 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -585,6 +585,9 @@ class AppLocalizationsSl extends AppLocalizations { @override String get settings_infoPublicKey => 'Javni ključ'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => 'Število stikov'; diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index d0cdf67..2ad010a 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -583,6 +583,9 @@ class AppLocalizationsSv extends AppLocalizations { @override String get settings_infoPublicKey => 'Allmänt nyckel'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => 'Kontakterantal'; diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index 178cc09..4e43be4 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -591,6 +591,9 @@ class AppLocalizationsUk extends AppLocalizations { @override String get settings_infoPublicKey => 'Відкритий ключ'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => 'Кількість контактів'; diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index 8ebdcd3..6fe8981 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -559,6 +559,9 @@ class AppLocalizationsZh extends AppLocalizations { @override String get settings_infoPublicKey => '公钥'; + @override + String get settings_publicKeyCopied => 'Public key copied'; + @override String get settings_infoContactsCount => '联系人数量'; diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index d8fc905..819687f 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:meshcore_open/utils/gpx_export.dart'; import 'package:meshcore_open/widgets/elements_ui.dart'; import 'package:provider/provider.dart'; @@ -259,7 +260,8 @@ class _SettingsScreenState extends State { padding: const EdgeInsets.fromLTRB(16, 8, 16, 12), child: _buildInfoRow( l10n.settings_infoPublicKey, - '${pubKeyToHex(connector.selfPublicKey!).substring(0, 16)}...', + pubKeyToHex(connector.selfPublicKey!), + copyValue: pubKeyToHex(connector.selfPublicKey!), ), ), ], @@ -407,7 +409,8 @@ class _SettingsScreenState extends State { if (connector.selfPublicKey != null) _buildInfoRow( l10n.settings_infoPublicKey, - '${pubKeyToHex(connector.selfPublicKey!).substring(0, 16)}...', + pubKeyToHex(connector.selfPublicKey!), + copyValue: pubKeyToHex(connector.selfPublicKey!), ), _buildInfoRow( l10n.settings_infoContactsCount, @@ -643,6 +646,7 @@ class _SettingsScreenState extends State { Widget? leading, Color? valueColor, VoidCallback? onTap, + String? copyValue, }) { final theme = Theme.of(context); @@ -666,13 +670,43 @@ class _SettingsScreenState extends State { ], ), const SizedBox(height: 4), - Text( - value, - style: theme.textTheme.bodyLarge?.copyWith( - color: valueColor, - fontWeight: FontWeight.w500, + if (copyValue == null) + Text( + value, + style: theme.textTheme.bodyLarge?.copyWith( + color: valueColor, + fontWeight: FontWeight.w500, + ), + ) + else + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: SelectableText( + value, + style: theme.textTheme.bodyLarge?.copyWith( + color: valueColor, + fontWeight: FontWeight.w500, + ), + ), + ), + IconButton( + icon: const Icon(Icons.copy, size: 18), + tooltip: context.l10n.common_copy, + visualDensity: VisualDensity.compact, + onPressed: () async { + await Clipboard.setData(ClipboardData(text: copyValue)); + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(context.l10n.settings_publicKeyCopied), + ), + ); + }, + ), + ], ), - ), ], ), ); diff --git a/untranslated.json b/untranslated.json index daf67ec..269eb2b 100644 --- a/untranslated.json +++ b/untranslated.json @@ -14,6 +14,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -66,6 +67,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -118,6 +120,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -170,6 +173,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -222,6 +226,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -274,6 +279,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -326,6 +332,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -378,6 +385,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -430,6 +438,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -482,6 +491,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -534,6 +544,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -586,6 +597,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -638,6 +650,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -690,6 +703,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -742,6 +756,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -794,6 +809,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h", @@ -846,6 +862,7 @@ "settings_gpsStatusNoResponse", "settings_infoFirmware", "settings_infoModel", + "settings_publicKeyCopied", "appSettings_clock", "appSettings_clockSystem", "appSettings_clock12h",