@ -223,12 +223,28 @@ class _SettingsScreenState extends State<SettingsScreen> {
padding: const EdgeInsets . all ( 16 ) ,
padding: const EdgeInsets . all ( 16 ) ,
children: [
children: [
Card (
Card (
child: ListTile (
child: Column (
leading: const Icon ( Icons . visibility_off_outlined ) ,
crossAxisAlignment: CrossAxisAlignment . start ,
title: Text ( l10n . settings_privacy ) ,
children: [
subtitle: Text ( l10n . settings_privacySubtitle ) ,
Padding (
trailing: const Icon ( Icons . chevron_right ) ,
padding: const EdgeInsets . fromLTRB ( 16 , 16 , 16 , 4 ) ,
onTap: ( ) = > _privacySettings ( context , connector ) ,
child: Text (
l10n . settings_privacy ,
style: const TextStyle (
fontSize: 18 ,
fontWeight: FontWeight . bold ,
) ,
) ,
) ,
_PrivacySection (
key: ValueKey (
' ${ connector . telemetryModeBase } - ${ connector . telemetryModeLoc } - '
' ${ connector . telemetryModeEnv } - ${ connector . advertLocationPolicy } - '
' ${ connector . multiAcks } ' ,
) ,
connector: connector ,
) ,
] ,
) ,
) ,
) ,
) ,
] ,
] ,
@ -975,129 +991,171 @@ class _SettingsScreenState extends State<SettingsScreen> {
}
}
}
}
void _privacySettings ( BuildContext context , MeshCoreConnector connector ) {
/ / / Inline privacy controls for the Privacy pane .
final l10n = context . l10n ;
/ / /
/ / / Advert - location , multi - ACKs , and the three telemetry - access modes all commit
int telemetryMode = connector . telemetryModeBase ;
/ / / through a single [ MeshCoreConnector . setTelemetryModeBase ] call , so each
int telemetryLocMode = connector . telemetryModeLoc ;
/ / / control sends the full current state on change ( coalesced ) and reverts to the
int telemetryEnvMode = connector . telemetryModeEnv ;
/ / / device ' s values on failure. The host re-keys this widget on the connector ' s
bool advertLocPolicy = connector . advertLocationPolicy = = 0 ? false : true ;
/ / / current values , so a device - reported change rebuilds it with fresh values .
int multiAcks = connector . multiAcks ;
class _PrivacySection extends StatefulWidget {
final MeshCoreConnector connector ;
final telemModeBase = [
DropdownMenuItem ( value: teleModeDeny , child: Text ( l10n . settings_denyAll ) ) ,
const _PrivacySection ( { super . key , required this . connector } ) ;
DropdownMenuItem (
value: teleModeAllowFlags ,
@ override
child: Text ( l10n . settings_allowByContact ) ,
State < _PrivacySection > createState ( ) = > _PrivacySectionState ( ) ;
) ,
}
DropdownMenuItem (
value: teleModeAllowAll ,
class _PrivacySectionState extends State < _PrivacySection > {
child: Text ( l10n . settings_allowAll ) ,
late int _telemetryMode ;
) ,
late int _telemetryLocMode ;
] ;
late int _telemetryEnvMode ;
late bool _advertLocPolicy ;
showDialog (
late int _multiAcks ;
context: context ,
builder: ( dialogContext ) = > StatefulBuilder (
bool _applying = false ;
builder: ( context , setDialogState ) = > AlertDialog (
bool _applyAgain = false ;
title: Text ( l10n . settings_privacy ) ,
content: SingleChildScrollView (
@ override
child: Column (
void initState ( ) {
mainAxisSize: MainAxisSize . min ,
super . initState ( ) ;
crossAxisAlignment: CrossAxisAlignment . start ,
_seedFromConnector ( ) ;
children: [
}
Text ( l10n . settings_privacySettingsDescription ) ,
const SizedBox ( height: 16 ) ,
void _seedFromConnector ( ) {
FeatureToggleRow (
final c = widget . connector ;
title: l10n . settings_advertLocation ,
_telemetryMode = c . telemetryModeBase ;
subtitle: l10n . settings_advertLocationSubtitle ,
_telemetryLocMode = c . telemetryModeLoc ;
value: advertLocPolicy ,
_telemetryEnvMode = c . telemetryModeEnv ;
onChanged: ( value ) {
_advertLocPolicy = c . advertLocationPolicy ! = 0 ;
setDialogState ( ( ) = > advertLocPolicy = value ) ;
_multiAcks = c . multiAcks ;
} ,
}
) ,
const SizedBox ( height: 8 ) ,
Future < void > _apply ( ) async {
SwitchListTile (
if ( _applying ) {
title: Text ( l10n . settings_multiAck ) ,
_applyAgain = true ;
value: multiAcks = = 1 ,
return ;
onChanged: ( value ) {
}
setDialogState ( ( ) = > multiAcks = value ? 1 : 0 ) ;
_applying = true ;
} ,
try {
contentPadding: EdgeInsets . zero ,
do {
) ,
_applyAgain = false ;
const SizedBox ( height: 16 ) ,
await widget . connector . setTelemetryModeBase (
DropdownButtonFormField < int > (
_telemetryMode ,
initialValue: telemetryMode ,
_telemetryLocMode ,
decoration: InputDecoration (
_telemetryEnvMode ,
labelText: l10n . settings_telemetryBaseMode ,
_advertLocPolicy ? 1 : 0 ,
border: const OutlineInputBorder ( ) ,
_multiAcks ,
) ,
) ;
items: telemModeBase ,
await widget . connector . refreshDeviceInfo ( ) ;
onChanged: ( value ) {
} while ( _applyAgain ) ;
if ( value ! = null ) {
} catch ( e ) {
setDialogState ( ( ) = > telemetryMode = value ) ;
if ( ! mounted ) return ;
}
setState ( _seedFromConnector ) ;
} ,
showDismissibleSnackBar (
) ,
context ,
const SizedBox ( height: 16 ) ,
content: Text ( context . l10n . settings_error ( e . toString ( ) ) ) ,
DropdownButtonFormField < int > (
) ;
initialValue: telemetryLocMode ,
} finally {
decoration: InputDecoration (
_applying = false ;
labelText: l10n . settings_telemetryLocationMode ,
}
border: const OutlineInputBorder ( ) ,
}
) ,
items: telemModeBase ,
Widget _telemetryDropdown ( {
onChanged: ( value ) {
required String label ,
if ( value ! = null ) {
required int value ,
setDialogState ( ( ) = > telemetryLocMode = value ) ;
required ValueChanged < int > onChanged ,
}
} ) {
} ,
final l10n = context . l10n ;
) ,
return Padding (
const SizedBox ( height: 16 ) ,
padding: const EdgeInsets . fromLTRB ( 16 , 8 , 16 , 0 ) ,
DropdownButtonFormField < int > (
child: DropdownButtonFormField < int > (
initialValue: telemetryEnvMode ,
key: ValueKey ( ' $ label - $ value ' ) ,
decoration: InputDecoration (
initialValue: value ,
labelText: l10n . settings_telemetryEnvironmentMode ,
decoration: InputDecoration (
border: const OutlineInputBorder ( ) ,
labelText: label ,
) ,
border: const OutlineInputBorder ( ) ,
items: telemModeBase ,
onChanged: ( value ) {
if ( value ! = null ) {
setDialogState ( ( ) = > telemetryEnvMode = value ) ;
}
} ,
) ,
] ,
) ,
) ,
) ,
action s: [
items: [
TextButton (
DropdownMenuItem (
onPressed: ( ) = > Navigator . pop ( context ) ,
value: teleModeDeny ,
child: Text ( l10n . common_cance l) ,
child: Text ( l10n . settings_denyAll ) ,
) ,
) ,
TextButton (
DropdownMenuItem (
onPressed: ( ) async {
value: teleModeAllowFlags ,
Navigator . pop ( context ) ;
child: Text ( l10n . settings_allowByContact ) ,
await connector . setTelemetryModeBase (
) ,
telemetryMode ,
DropdownMenuItem (
telemetryLocMode ,
value: teleModeAllowAll ,
telemetryEnvMode ,
child: Text ( l10n . settings_allowAll ) ,
advertLocPolicy ? 1 : 0 ,
multiAcks ,
) ;
await connector . refreshDeviceInfo ( ) ;
if ( ! context . mounted ) return ;
showDismissibleSnackBar (
context ,
content: Text ( l10n . settings_telemetryModeUpdated ) ,
) ;
} ,
child: Text ( l10n . common_save ) ,
) ,
) ,
] ,
] ,
onChanged: ( v ) {
if ( v = = null ) return ;
onChanged ( v ) ;
} ,
) ,
) ,
) ,
) ;
) ;
}
@ override
Widget build ( BuildContext context ) {
final l10n = context . l10n ;
return Column (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
Padding (
padding: const EdgeInsets . fromLTRB ( 16 , 0 , 16 , 8 ) ,
child: Text ( l10n . settings_privacySettingsDescription ) ,
) ,
SwitchListTile (
secondary: const Icon ( Icons . share_location_outlined ) ,
title: Text ( l10n . settings_advertLocation ) ,
subtitle: Text ( l10n . settings_advertLocationSubtitle ) ,
value: _advertLocPolicy ,
onChanged: ( value ) {
setState ( ( ) = > _advertLocPolicy = value ) ;
_apply ( ) ;
} ,
) ,
SwitchListTile (
secondary: const Icon ( Icons . done_all ) ,
title: Text ( l10n . settings_multiAck ) ,
value: _multiAcks = = 1 ,
onChanged: ( value ) {
setState ( ( ) = > _multiAcks = value ? 1 : 0 ) ;
_apply ( ) ;
} ,
) ,
_telemetryDropdown (
label: l10n . settings_telemetryBaseMode ,
value: _telemetryMode ,
onChanged: ( v ) {
setState ( ( ) = > _telemetryMode = v ) ;
_apply ( ) ;
} ,
) ,
_telemetryDropdown (
label: l10n . settings_telemetryLocationMode ,
value: _telemetryLocMode ,
onChanged: ( v ) {
setState ( ( ) = > _telemetryLocMode = v ) ;
_apply ( ) ;
} ,
) ,
_telemetryDropdown (
label: l10n . settings_telemetryEnvironmentMode ,
value: _telemetryEnvMode ,
onChanged: ( v ) {
setState ( ( ) = > _telemetryEnvMode = v ) ;
_apply ( ) ;
} ,
) ,
const SizedBox ( height: 8 ) ,
] ,
) ;
}
}
}
/ / / Inline path - hash size selector for the connected device .
/ / / Inline path - hash size selector for the connected device .