@ -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 . c ommunity _scanQr) ,
title: AdaptiveAppBarTitle ( context . l10n . c hannels _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 . c hannels_scanQr Instructions,
) ,
) ,
) ;
) ;
}
}
@ -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 + + ) {