Add contact settings and discovery features

- Implemented contact settings in localization files for Swedish, Ukrainian, and Chinese.
- Added new DiscoveryContact model to handle discovered contacts.
- Created DiscoveryScreen to display discovered contacts with filtering and sorting options.
- Integrated contact discovery storage to persist discovered contacts.
- Updated settings screen to include options for automatic contact addition.
- Enhanced app bar and list filter widgets for better user experience.
- Fixed variable naming inconsistencies in contact model.
This commit is contained in:
Winston Lowe
2026-02-28 19:11:11 -08:00
parent e139383335
commit 75610695c2
28 changed files with 1958 additions and 41 deletions
+111 -2
View File
@@ -9,6 +9,7 @@ import '../connector/meshcore_protocol.dart';
import '../l10n/l10n.dart';
import '../models/radio_settings.dart';
import '../widgets/adaptive_app_bar_title.dart';
import '../widgets/app_bar.dart';
import 'app_settings_screen.dart';
import 'app_debug_log_screen.dart';
import 'ble_debug_log_screen.dart';
@@ -43,8 +44,11 @@ class _SettingsScreenState extends State<SettingsScreen> {
final l10n = context.l10n;
return Scaffold(
appBar: AppBar(
title: AdaptiveAppBarTitle(l10n.settings_title),
centerTitle: true,
title: AppBarTitle(
l10n.settings_title,
indicators: false,
subtitle: false,
),
),
body: SafeArea(
top: false,
@@ -274,6 +278,14 @@ class _SettingsScreenState extends State<SettingsScreen> {
onTap: () => _editLocation(context, connector),
),
const Divider(height: 1),
ListTile(
leading: const Icon(Icons.group_add_outlined),
title: Text(l10n.settings_contactSettings),
subtitle: Text(l10n.settings_contactSettingsSubtitle),
trailing: const Icon(Icons.chevron_right),
onTap: () => _editAutoAddConfig(context, connector),
),
const Divider(height: 1),
ListTile(
leading: const Icon(Icons.visibility_off_outlined),
title: Text(l10n.settings_privacyMode),
@@ -849,6 +861,103 @@ class _SettingsScreenState extends State<SettingsScreen> {
),
);
}
void _editAutoAddConfig(BuildContext context, MeshCoreConnector connector) {
final l10n = context.l10n;
bool autoAddChat = false;
bool autoAddRepeater = false;
bool autoAddRoomServer = false;
bool autoAddSensor = false;
bool overwriteOldest = false;
final connector = context.read<MeshCoreConnector>();
autoAddChat = connector.autoAddUsers ?? false;
autoAddRepeater = connector.autoAddRepeaters ?? false;
autoAddRoomServer = connector.autoAddRoomServers ?? false;
autoAddSensor = connector.autoAddSensors ?? false;
overwriteOldest = connector.autoAddOverwriteOldest ?? false;
showDialog(
context: context,
builder: (dialogContext) => StatefulBuilder(
builder: (context, setDialogState) => AlertDialog(
title: Text(l10n.contactsSettings_autoAddTitle),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
FeatureToggleRow(
title: l10n.contactsSettings_autoAddUsersTitle,
subtitle: l10n.contactsSettings_autoAddUsersSubtitle,
value: autoAddChat,
onChanged: (value) {
setDialogState(() => autoAddChat = value);
},
),
SizedBox(height: 8),
FeatureToggleRow(
title: l10n.contactsSettings_autoAddRepeatersTitle,
subtitle: l10n.contactsSettings_autoAddRepeatersSubtitle,
value: autoAddRepeater,
onChanged: (value) {
setDialogState(() => autoAddRepeater = value);
},
),
SizedBox(height: 8),
FeatureToggleRow(
title: l10n.contactsSettings_autoAddRoomServersTitle,
subtitle: l10n.contactsSettings_autoAddRoomServersSubtitle,
value: autoAddRoomServer,
onChanged: (value) {
setDialogState(() => autoAddRoomServer = value);
},
),
SizedBox(height: 8),
FeatureToggleRow(
title: l10n.contactsSettings_autoAddSensorsTitle,
subtitle: l10n.contactsSettings_autoAddSensorsSubtitle,
value: autoAddSensor,
onChanged: (value) {
setDialogState(() => autoAddSensor = value);
},
),
Divider(height: 4),
FeatureToggleRow(
title: l10n.contactsSettings_overwriteOldestTitle,
subtitle: l10n.contactsSettings_overwriteOldestSubtitle,
value: overwriteOldest,
onChanged: (value) {
setDialogState(() => overwriteOldest = value);
},
),
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(l10n.common_cancel),
),
TextButton(
onPressed: () async {
final frame = buildSetAutoAddConfigFrame(
autoAddChat: autoAddChat,
autoAddRepeater: autoAddRepeater,
autoAddRoomServer: autoAddRoomServer,
autoAddSensor: autoAddSensor,
overwriteOldest: overwriteOldest,
);
await connector.sendFrame(frame);
await connector.sendFrame(buildGetAutoAddFlagsFrame());
Navigator.pop(context);
},
child: Text(l10n.common_save),
),
],
),
),
);
}
}
class _RadioSettingsDialog extends StatefulWidget {