feat(#163): scan a channel QR to add it (unified with community scanner)

The Add Channel "Scan QR Code" scanner now accepts channel share URIs
(meshcore://channel/add) alongside community QR JSON: it parses name +
secret, confirms, and adds the channel to the next free slot via
setChannel. Completes the channel-QR round-trip in-app, and interops with
the reference app's channel QRs.

Bumps build to +52 for the b52 combined test binary (path-hash + trace +
channel QR).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pull/201/head
Strycher 3 weeks ago
parent 01207f5019
commit ed4dce94f3

@ -1992,6 +1992,35 @@
} }
} }
}, },
"channels_scanQr": "Scan QR Code",
"channels_scanQrDesc": "Add a community or channel from a QR code",
"channels_scanQrInstructions": "Point at a MeshCore QR code",
"channels_invalidQr": "Invalid QR code",
"channels_noFreeSlot": "No free channel slot",
"channels_qrAddConfirm": "Add channel \"{name}\"?",
"@channels_qrAddConfirm": {
"placeholders": {
"name": {
"type": "String"
}
}
},
"channels_qrAdded": "Added \"{name}\".",
"@channels_qrAdded": {
"placeholders": {
"name": {
"type": "String"
}
}
},
"channels_qrExists": "\"{name}\" is already added.",
"@channels_qrExists": {
"placeholders": {
"name": {
"type": "String"
}
}
},
"community_hashtagPrivacyHint": "Community hashtag channels are only joinable by members of the community", "community_hashtagPrivacyHint": "Community hashtag channels are only joinable by members of the community",
"community_invalidQrCode": "Invalid community QR code", "community_invalidQrCode": "Invalid community QR code",
"community_alreadyMember": "Already a Member", "community_alreadyMember": "Already a Member",

@ -6374,6 +6374,54 @@ abstract class AppLocalizations {
/// **'Scan to add \"{name}\".'** /// **'Scan to add \"{name}\".'**
String channels_shareQrInstructions(String name); String channels_shareQrInstructions(String name);
/// No description provided for @channels_scanQr.
///
/// In en, this message translates to:
/// **'Scan QR Code'**
String get channels_scanQr;
/// No description provided for @channels_scanQrDesc.
///
/// In en, this message translates to:
/// **'Add a community or channel from a QR code'**
String get channels_scanQrDesc;
/// No description provided for @channels_scanQrInstructions.
///
/// In en, this message translates to:
/// **'Point at a MeshCore QR code'**
String get channels_scanQrInstructions;
/// No description provided for @channels_invalidQr.
///
/// In en, this message translates to:
/// **'Invalid QR code'**
String get channels_invalidQr;
/// No description provided for @channels_noFreeSlot.
///
/// In en, this message translates to:
/// **'No free channel slot'**
String get channels_noFreeSlot;
/// No description provided for @channels_qrAddConfirm.
///
/// In en, this message translates to:
/// **'Add channel \"{name}\"?'**
String channels_qrAddConfirm(String name);
/// No description provided for @channels_qrAdded.
///
/// In en, this message translates to:
/// **'Added \"{name}\".'**
String channels_qrAdded(String name);
/// No description provided for @channels_qrExists.
///
/// In en, this message translates to:
/// **'\"{name}\" is already added.'**
String channels_qrExists(String name);
/// No description provided for @community_hashtagPrivacyHint. /// No description provided for @community_hashtagPrivacyHint.
/// ///
/// In en, this message translates to: /// In en, this message translates to:

@ -3688,6 +3688,36 @@ class AppLocalizationsBg extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'Хаштаг каналите на общността са достъпни само за членове на общността'; 'Хаштаг каналите на общността са достъпни само за членове на общността';

@ -3695,6 +3695,36 @@ class AppLocalizationsDe extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'Community-Hashtag-Kanäle können nur von Mitgliedern der Community betreten werden'; 'Community-Hashtag-Kanäle können nur von Mitgliedern der Community betreten werden';

@ -3624,6 +3624,36 @@ class AppLocalizationsEn extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'Community hashtag channels are only joinable by members of the community'; 'Community hashtag channels are only joinable by members of the community';

@ -3683,6 +3683,36 @@ class AppLocalizationsEs extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'Los canales de hashtag de la comunidad solo son accesibles para los miembros de la comunidad'; 'Los canales de hashtag de la comunidad solo son accesibles para los miembros de la comunidad';

@ -3706,6 +3706,36 @@ class AppLocalizationsFr extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'Les canaux hashtag de la communauté ne sont accessibles qu\'aux membres de la communauté'; 'Les canaux hashtag de la communauté ne sont accessibles qu\'aux membres de la communauté';

@ -3699,6 +3699,36 @@ class AppLocalizationsHu extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'A közösségi hashtagekhez tartozó csatornák csak a közösség tagjai számára érhetők el.'; 'A közösségi hashtagekhez tartozó csatornák csak a közösség tagjai számára érhetők el.';

@ -3688,6 +3688,36 @@ class AppLocalizationsIt extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'I canali hashtag della community sono accessibili solo ai membri della community'; 'I canali hashtag della community sono accessibili solo ai membri della community';

@ -3501,6 +3501,36 @@ class AppLocalizationsJa extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'コミュニティハッシュタグのチャンネルは、コミュニティのメンバーのみが参加できます。'; 'コミュニティハッシュタグのチャンネルは、コミュニティのメンバーのみが参加できます。';

@ -3503,6 +3503,36 @@ class AppLocalizationsKo extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'커뮤니티 해시태그 채널은 커뮤니티 구성원만 가입할 수 있습니다.'; '커뮤니티 해시태그 채널은 커뮤니티 구성원만 가입할 수 있습니다.';

@ -3669,6 +3669,36 @@ class AppLocalizationsNl extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'Community hashtag-kanalen zijn alleen toegankelijk voor leden van de community'; 'Community hashtag-kanalen zijn alleen toegankelijk voor leden van de community';

@ -3701,6 +3701,36 @@ class AppLocalizationsPl extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'Kanały hashtagowe społeczności są dostępne tylko dla członków społeczności'; 'Kanały hashtagowe społeczności są dostępne tylko dla członków społeczności';

@ -3682,6 +3682,36 @@ class AppLocalizationsPt extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'Os canais de hashtag da comunidade só podem ser acessados por membros da comunidade'; 'Os canais de hashtag da comunidade só podem ser acessados por membros da comunidade';

@ -3690,6 +3690,36 @@ class AppLocalizationsRu extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'Хэштег-каналы сообщества доступны только его участникам'; 'Хэштег-каналы сообщества доступны только его участникам';

@ -3668,6 +3668,36 @@ class AppLocalizationsSk extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'Hashtagové kanály komunity sú prístupné len členom komunity'; 'Hashtagové kanály komunity sú prístupné len členom komunity';

@ -3663,6 +3663,36 @@ class AppLocalizationsSl extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'Hashtag kanali skupnosti so dostopni samo članom skupnosti'; 'Hashtag kanali skupnosti so dostopni samo članom skupnosti';

@ -3643,6 +3643,36 @@ class AppLocalizationsSv extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'Community-hashtagkanaler kan endast nås av medlemmar i communityn'; 'Community-hashtagkanaler kan endast nås av medlemmar i communityn';

@ -3686,6 +3686,36 @@ class AppLocalizationsUk extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => String get community_hashtagPrivacyHint =>
'Хештег-канали спільноти доступні лише членам спільноти'; 'Хештег-канали спільноти доступні лише членам спільноти';

@ -3406,6 +3406,36 @@ class AppLocalizationsZh extends AppLocalizations {
return 'Scan to add \"$name\".'; return 'Scan to add \"$name\".';
} }
@override
String get channels_scanQr => 'Scan QR Code';
@override
String get channels_scanQrDesc => 'Add a community or channel from a QR code';
@override
String get channels_scanQrInstructions => 'Point at a MeshCore QR code';
@override
String get channels_invalidQr => 'Invalid QR code';
@override
String get channels_noFreeSlot => 'No free channel slot';
@override
String channels_qrAddConfirm(String name) {
return 'Add channel \"$name\"?';
}
@override
String channels_qrAdded(String name) {
return 'Added \"$name\".';
}
@override
String channels_qrExists(String name) {
return '\"$name\" is already added.';
}
@override @override
String get community_hashtagPrivacyHint => '仅社区成员可加入社区标签频道。'; String get community_hashtagPrivacyHint => '仅社区成员可加入社区标签频道。';

@ -1355,8 +1355,8 @@ class _ChannelsScreenState extends State<ChannelsScreen>
buildOptionTile( buildOptionTile(
optionIndex: 4, optionIndex: 4,
icon: Icons.qr_code_scanner, icon: Icons.qr_code_scanner,
title: dialogContext.l10n.community_scanQr, title: dialogContext.l10n.channels_scanQr,
subtitle: dialogContext.l10n.community_join, subtitle: dialogContext.l10n.channels_scanQrDesc,
), ),
if (selectedOption == 4) if (selectedOption == 4)
buildExpandedContent(_channelMessageStore)!, buildExpandedContent(_channelMessageStore)!,

@ -4,6 +4,7 @@ import 'package:uuid/uuid.dart';
import '../connector/meshcore_connector.dart'; import '../connector/meshcore_connector.dart';
import '../l10n/l10n.dart'; import '../l10n/l10n.dart';
import '../models/channel.dart';
import '../models/community.dart'; import '../models/community.dart';
import '../storage/community_store.dart'; import '../storage/community_store.dart';
import '../widgets/adaptive_app_bar_title.dart'; import '../widgets/adaptive_app_bar_title.dart';
@ -31,16 +32,18 @@ class _CommunityQrScannerScreenState extends State<CommunityQrScannerScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: AdaptiveAppBarTitle(context.l10n.community_scanQr), title: AdaptiveAppBarTitle(context.l10n.channels_scanQr),
centerTitle: true, centerTitle: true,
), ),
body: _isProcessing body: _isProcessing
? const Center(child: CircularProgressIndicator()) ? const Center(child: CircularProgressIndicator())
: QrScannerWidget( : QrScannerWidget(
onScanned: (data) => _handleScannedData(context, data), onScanned: (data) => _handleScannedData(context, data),
validator: Community.isValidQrData, validator: (data) =>
Community.isValidQrData(data) ||
Channel.isValidShareUri(data),
onValidationFailed: (_) => _showInvalidQrError(context), onValidationFailed: (_) => _showInvalidQrError(context),
instructions: context.l10n.community_scanInstructions, instructions: context.l10n.channels_scanQrInstructions,
), ),
); );
} }
@ -56,6 +59,12 @@ class _CommunityQrScannerScreenState extends State<CommunityQrScannerScreen> {
_communityStore.setPublicKeyHex = connector.selfPublicKeyHex; _communityStore.setPublicKeyHex = connector.selfPublicKeyHex;
try { try {
// A channel share URI (meshcore://channel/add) is handled separately
// from community QR JSON. (#161)
if (Channel.isValidShareUri(data)) {
await _handleChannelUri(context, data);
return;
}
// Parse the community data // Parse the community data
final community = Community.fromQrData(const Uuid().v4(), data); final community = Community.fromQrData(const Uuid().v4(), data);
@ -239,6 +248,71 @@ class _CommunityQrScannerScreenState extends State<CommunityQrScannerScreen> {
} }
} }
Future<void> _handleChannelUri(BuildContext context, String data) async {
final channel = Channel.fromShareUri(data);
if (channel == null) {
if (context.mounted) {
showDismissibleSnackBar(
context,
content: Text(context.l10n.channels_invalidQr),
backgroundColor: Colors.red,
);
}
return;
}
final connector = context.read<MeshCoreConnector>();
if (connector.channels.any((c) => c.pskHex == channel.pskHex)) {
if (context.mounted) {
showDismissibleSnackBar(
context,
content: Text(context.l10n.channels_qrExists(channel.name)),
);
Navigator.pop(context);
}
return;
}
final nextIndex = _findNextAvailableChannelIndex(connector);
if (nextIndex == null) {
if (context.mounted) {
showDismissibleSnackBar(
context,
content: Text(context.l10n.channels_noFreeSlot),
backgroundColor: Colors.red,
);
}
return;
}
if (!context.mounted) return;
final confirmed = await showDialog<bool>(
context: context,
builder: (dialogContext) => AlertDialog(
title: Text(context.l10n.channels_scanQr),
content: Text(context.l10n.channels_qrAddConfirm(channel.name)),
actions: [
TextButton(
onPressed: () => Navigator.pop(dialogContext, false),
child: Text(context.l10n.common_cancel),
),
FilledButton(
onPressed: () => Navigator.pop(dialogContext, true),
child: Text(context.l10n.common_add),
),
],
),
);
if (confirmed == true && context.mounted) {
connector.setChannel(nextIndex, channel.name, channel.psk);
showDismissibleSnackBar(
context,
content: Text(context.l10n.channels_qrAdded(channel.name)),
backgroundColor: Colors.green,
);
Navigator.pop(context);
} else if (context.mounted) {
Navigator.pop(context);
}
}
int? _findNextAvailableChannelIndex(MeshCoreConnector connector) { int? _findNextAvailableChannelIndex(MeshCoreConnector connector) {
final usedIndices = connector.channels.map((c) => c.index).toSet(); final usedIndices = connector.channels.map((c) => c.index).toSet();
for (int i = 0; i < connector.maxChannels; i++) { for (int i = 0; i < connector.maxChannels; i++) {

Loading…
Cancel
Save

Powered by TurnKey Linux.