diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 4ef40f6..248b112 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -2521,6 +2521,11 @@ "contacts_verifiedByMessage": "Key confirmed. A message with this contact went through, which only works with the matching key.", "contacts_verifiedKeyOnly": "Added from a key. Nothing has confirmed it on air yet.", "contacts_lastSeenNever": "Not heard yet", + "chat_attachTooltip": "Add to message", + "chat_attachGif": "GIF", + "chat_attachMyContact": "My contact card", + "chat_attachMyContactSubtitle": "Puts your public key in the message so anyone here can add you", + "chat_contactCardNeedsConnection": "Connect to a radio first, so the app knows your public key.", "contacts_ShareContact": "Copy contact to Clipboard", "contacts_ShareContactZeroHop": "Share contact by advert", "contacts_zeroHopContactAdvertSent": "Sent contact by advert.", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 8de8748..c886449 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -7576,6 +7576,36 @@ abstract class AppLocalizations { /// **'Not heard yet'** String get contacts_lastSeenNever; + /// No description provided for @chat_attachTooltip. + /// + /// In en, this message translates to: + /// **'Add to message'** + String get chat_attachTooltip; + + /// No description provided for @chat_attachGif. + /// + /// In en, this message translates to: + /// **'GIF'** + String get chat_attachGif; + + /// No description provided for @chat_attachMyContact. + /// + /// In en, this message translates to: + /// **'My contact card'** + String get chat_attachMyContact; + + /// No description provided for @chat_attachMyContactSubtitle. + /// + /// In en, this message translates to: + /// **'Puts your public key in the message so anyone here can add you'** + String get chat_attachMyContactSubtitle; + + /// No description provided for @chat_contactCardNeedsConnection. + /// + /// In en, this message translates to: + /// **'Connect to a radio first, so the app knows your public key.'** + String get chat_contactCardNeedsConnection; + /// No description provided for @contacts_ShareContact. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index afc947b..b0cf93b 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -4425,6 +4425,23 @@ class AppLocalizationsBg extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => 'Копирай контакт в клипборда'; diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 24b318c..a55a6ac 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -4437,6 +4437,23 @@ class AppLocalizationsDe extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => 'Kontakt in die Zwischenablage kopieren'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 80fa2cf..0415d17 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -4359,6 +4359,23 @@ class AppLocalizationsEn extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => 'Copy contact to Clipboard'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index c44095e..7bd6e11 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -4426,6 +4426,23 @@ class AppLocalizationsEs extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => 'Copiar contacto al Portapapeles'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index 33929a1..4d514b2 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -4448,6 +4448,23 @@ class AppLocalizationsFr extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => 'Copier le contact dans le presse-papiers'; diff --git a/lib/l10n/app_localizations_hu.dart b/lib/l10n/app_localizations_hu.dart index 92bd608..676dafb 100644 --- a/lib/l10n/app_localizations_hu.dart +++ b/lib/l10n/app_localizations_hu.dart @@ -4443,6 +4443,23 @@ class AppLocalizationsHu extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => 'Másolja a kapcsolatot a kiválasztóba'; diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index 3f6b2d7..5e9bb80 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -4431,6 +4431,23 @@ class AppLocalizationsIt extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => 'Copia contatto negli Appunti'; diff --git a/lib/l10n/app_localizations_ja.dart b/lib/l10n/app_localizations_ja.dart index 13d85ec..566fa32 100644 --- a/lib/l10n/app_localizations_ja.dart +++ b/lib/l10n/app_localizations_ja.dart @@ -4228,6 +4228,23 @@ class AppLocalizationsJa extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => '連絡先をクリップボードにコピー'; diff --git a/lib/l10n/app_localizations_ko.dart b/lib/l10n/app_localizations_ko.dart index ab428ae..0321b79 100644 --- a/lib/l10n/app_localizations_ko.dart +++ b/lib/l10n/app_localizations_ko.dart @@ -4230,6 +4230,23 @@ class AppLocalizationsKo extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => '연락처를 복사'; diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index 942c1b4..f6dd647 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -4411,6 +4411,23 @@ class AppLocalizationsNl extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => 'Contact naar Klembord kopiëren'; diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index 486a9ca..08c0a80 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -4441,6 +4441,23 @@ class AppLocalizationsPl extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => 'Kopiuj kontakt do schowka'; diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index 41f6820..e091edf 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -4423,6 +4423,23 @@ class AppLocalizationsPt extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => 'Copiar contato para Área de Transferência'; diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 42b8fad..3a543c3 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -4433,6 +4433,23 @@ class AppLocalizationsRu extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => 'Копировать контакт в буфер обмена'; diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index bcebfb7..0cba92f 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -4407,6 +4407,23 @@ class AppLocalizationsSk extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => 'Kopírovať kontakt do schránky'; diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index ac0cef7..b7bbd5a 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -4401,6 +4401,23 @@ class AppLocalizationsSl extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => 'Kopiraj stik v Odložišče'; diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index 8965079..b8e4588 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -4380,6 +4380,23 @@ class AppLocalizationsSv extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => 'Kopiera kontakt till Urklipp'; diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index d78ea3a..4c6569b 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -4432,6 +4432,23 @@ class AppLocalizationsUk extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => 'Копіювати контакт у буфер обміну'; diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index 8dcc0e2..39fff5d 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -4131,6 +4131,23 @@ class AppLocalizationsZh extends AppLocalizations { @override String get contacts_lastSeenNever => 'Not heard yet'; + @override + String get chat_attachTooltip => 'Add to message'; + + @override + String get chat_attachGif => 'GIF'; + + @override + String get chat_attachMyContact => 'My contact card'; + + @override + String get chat_attachMyContactSubtitle => + 'Puts your public key in the message so anyone here can add you'; + + @override + String get chat_contactCardNeedsConnection => + 'Connect to a radio first, so the app knows your public key.'; + @override String get contacts_ShareContact => '复制联系人信息到剪贴板'; diff --git a/lib/models/contact.dart b/lib/models/contact.dart index 07613e2..bbe3621 100644 --- a/lib/models/contact.dart +++ b/lib/models/contact.dart @@ -296,6 +296,35 @@ class Contact { '&public_key=$publicKeyHex' '&type=$type'; + /// Compact contact share for a CHANNEL message, ``. (#611) + /// + /// This is a second, different format from [toShareUri], and deliberately so. + /// It is what real clients put on the air, observed live in `#test` and + /// `#hamradio`, and it is far cheaper: about 75 bytes against 117 for the + /// equivalent URI. Channel text shares a 160-byte payload with the + /// `Sender: ` prefix, so that difference is airtime, not neatness. + /// + /// Use the URI form for a QR, a DM, or an out-of-band paste. Use this for a + /// channel. + String toChannelShare() => + buildChannelShare(publicKeyHex: publicKeyHex, name: name, type: type); + + /// Builds the compact channel share from raw parts, so this device can share + /// its OWN identity without constructing a [Contact]. (#611) + /// + /// Angle brackets are the delimiters, so any in [name] are dropped: a name + /// carrying one would truncate the payload for every parser reading it. A + /// colon is left alone, because the name is the final field and a correct + /// parser splits on the first two colons only. + static String buildChannelShare({ + required String publicKeyHex, + required String name, + int type = advTypeChat, + }) { + final safeName = name.replaceAll('<', '').replaceAll('>', ''); + return '<$publicKeyHex:$type:$safeName>'; + } + /// Parses a contact from the reference-app share URI, or null if malformed. /// /// `meshcore://contact/add?name=&public_key=<64 hex>&type=<1-4>` diff --git a/lib/screens/channel_chat_screen.dart b/lib/screens/channel_chat_screen.dart index 33ac603..09132f3 100644 --- a/lib/screens/channel_chat_screen.dart +++ b/lib/screens/channel_chat_screen.dart @@ -1243,6 +1243,76 @@ class _ChannelChatScreenState extends State { ); } + /// The composer `+` picker. (#611) + /// + /// Owner decision: one `+` beside the text entry, offering GIF and Contact + /// for now, rather than a dedicated button per thing you can attach. The + /// sendable set stays small because a channel message shares a 160-byte + /// payload with the `Sender: ` prefix. + void _showAttachPicker(BuildContext context) { + showModalBottomSheet( + context: context, + builder: (sheetContext) => SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: const Icon(Icons.gif_box), + title: Text(sheetContext.l10n.chat_attachGif), + onTap: () { + Navigator.pop(sheetContext); + _showGifPicker(context); + }, + ), + ListTile( + leading: const Icon(Icons.person_outline), + title: Text(sheetContext.l10n.chat_attachMyContact), + subtitle: Text(sheetContext.l10n.chat_attachMyContactSubtitle), + onTap: () { + Navigator.pop(sheetContext); + _insertMyContactCard(context); + }, + ), + ], + ), + ), + ); + } + + /// Puts this device's own contact card into the composer. (#611) + /// + /// Inserts rather than sends, matching the GIF picker, so the text can be + /// reviewed and captioned before it goes out. + /// + /// Emits the compact `` form observed on the live mesh, NOT + /// the `meshcore://` URI. The URI is ~117 bytes against ~75 here, and the + /// channel payload budget is 160 including the `Sender: ` prefix. + void _insertMyContactCard(BuildContext context) { + final connector = Provider.of(context, listen: false); + final keyHex = connector.selfPublicKeyHex; + if (keyHex.length != pubKeySize * 2) { + showDismissibleSnackBar( + context, + content: Text(context.l10n.chat_contactCardNeedsConnection), + ); + return; + } + + final card = Contact.buildChannelShare( + publicKeyHex: keyHex, + name: connector.selfName ?? '', + // This device is a companion. + type: advTypeChat, + ); + + // Append rather than replace, so a caption already typed is not lost. + final existing = _textController.text.trimRight(); + _textController.text = existing.isEmpty ? card : '$existing $card'; + _textController.selection = TextSelection.collapsed( + offset: _textController.text.length, + ); + } + Widget _buildAvatar(String senderName) { final initial = _getFirstCharacterOrEmoji(senderName); final color = _getColorForName(senderName); @@ -1382,9 +1452,9 @@ class _ChannelChatScreenState extends State { child: Row( children: [ IconButton( - icon: const Icon(Icons.gif_box), - onPressed: () => _showGifPicker(context), - tooltip: context.l10n.chat_sendGif, + icon: const Icon(Icons.add), + onPressed: () => _showAttachPicker(context), + tooltip: context.l10n.chat_attachTooltip, ), if (settings.translationEnabled) MessageTranslationButton( diff --git a/test/models/contact_share_uri_test.dart b/test/models/contact_share_uri_test.dart index 670a9f9..49fc2eb 100644 --- a/test/models/contact_share_uri_test.dart +++ b/test/models/contact_share_uri_test.dart @@ -228,4 +228,92 @@ void main() { ); }); }); + + group('Compact channel contact share (#611)', () { + Contact stub(String name, int type) => Contact( + publicKey: hex2Uint8List(_key), + name: name, + type: type, + pathLength: -1, + path: Uint8List(0), + lastSeen: DateTime.fromMillisecondsSinceEpoch(0), + ); + + test('matches the shape observed on the live mesh', () { + // Real traffic in #test and #hamradio carries , with the + // angle brackets as literal delimiters. Key is synthetic here; the repo + // is public. + expect( + Contact.buildChannelShare(publicKeyHex: _key, name: 'KE8AFF', type: 1), + '<$_key:1:KE8AFF>', + ); + }); + + test('a name with spaces is carried verbatim', () { + // One of the two observed samples was "Roger KY4RS". + expect( + Contact.buildChannelShare( + publicKeyHex: _key, + name: 'Roger KY4RS', + type: advTypeChat, + ), + '<$_key:1:Roger KY4RS>', + ); + }); + + test('angle brackets are stripped from the name', () { + // A bracket in the name would truncate the payload for every parser + // reading it, so the emitter must not produce one. + final out = Contact.buildChannelShare( + publicKeyHex: _key, + name: 'wename', + type: advTypeChat, + ); + expect(out, '<$_key:1:weirdname>'); + expect('>'.allMatches(out).length, 1); + expect('<'.allMatches(out).length, 1); + }); + + test('a colon in the name survives, since the name is the final field', () { + // A correct parser splits on the first two colons and takes the rest as + // the name, so this needs no escaping. + expect( + Contact.buildChannelShare( + publicKeyHex: _key, + name: 'a:b', + type: advTypeChat, + ), + '<$_key:1:a:b>', + ); + }); + + test('every documented type is emitted numerically', () { + for (final t in [ + advTypeChat, + advTypeRepeater, + advTypeRoom, + advTypeSensor, + ]) { + expect( + Contact.buildChannelShare(publicKeyHex: _key, name: 'N', type: t), + '<$_key:$t:N>', + ); + } + }); + + test('toChannelShare uses the contact own key, type and name', () { + expect(stub('Bob', advTypeRepeater).toChannelShare(), '<$_key:2:Bob>'); + }); + + test('the compact form is materially cheaper than the URI', () { + // This is the whole reason both formats exist. Channel text shares a + // 160-byte payload with the "Sender: " prefix, so the difference is + // airtime, not tidiness. + final c = stub('KE8AFF', advTypeChat); + final compact = c.toChannelShare().length; + final uri = c.toShareUri().length; + expect(compact, lessThan(uri)); + expect(uri - compact, greaterThan(30)); + }); + }); } diff --git a/untranslated.json b/untranslated.json index a75aef0..2f8061a 100644 --- a/untranslated.json +++ b/untranslated.json @@ -115,6 +115,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -256,6 +261,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -397,6 +407,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -538,6 +553,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -679,6 +699,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -820,6 +845,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -961,6 +991,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -1102,6 +1137,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -1243,6 +1283,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -1384,6 +1429,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -1525,6 +1575,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -1666,6 +1721,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -1807,6 +1867,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -1948,6 +2013,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -2089,6 +2159,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -2230,6 +2305,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock", @@ -2371,6 +2451,11 @@ "contacts_verifiedByMessage", "contacts_verifiedKeyOnly", "contacts_lastSeenNever", + "chat_attachTooltip", + "chat_attachGif", + "chat_attachMyContact", + "chat_attachMyContactSubtitle", + "chat_contactCardNeedsConnection", "snrIndicator_noNeighbors", "block_block", "block_unblock",