Skip to content

Commit

Permalink
Add toggle devices in settings
Browse files Browse the repository at this point in the history
  • Loading branch information
elibon99 committed Jan 30, 2025
1 parent d037ccd commit e92b8b9
Show file tree
Hide file tree
Showing 12 changed files with 163 additions and 27 deletions.
26 changes: 26 additions & 0 deletions lib/app/state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,32 @@ final primaryColorProvider = Provider<Color>((ref) {
return lastUsedColor != null ? Color(lastUsedColor) : defaultColor;
});

final hiddenDevicesProvider =
StateNotifierProvider<HiddenDevicesNotifier, List<String>>(
(ref) => HiddenDevicesNotifier(ref.watch(prefProvider)));

class HiddenDevicesNotifier extends StateNotifier<List<String>> {
static const String _key = 'DEVICE_PICKER_HIDDEN';
final SharedPreferences _prefs;

HiddenDevicesNotifier(this._prefs) : super(_prefs.getStringList(_key) ?? []);

void showAll() {
state = [];
_prefs.setStringList(_key, state);
}

void hideDevice(DevicePath devicePath) {
state = [...state, devicePath.key];
_prefs.setStringList(_key, state);
}

void showDevice(DevicePath devicePath) {
state = state.where((e) => e != devicePath.key).toList();
_prefs.setStringList(_key, state);
}
}

// Override with platform implementation
final attachedDevicesProvider =
NotifierProvider<AttachedDevicesNotifier, List<DeviceNode>>(
Expand Down
30 changes: 4 additions & 26 deletions lib/app/views/device_picker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:shared_preferences/shared_preferences.dart';

import '../../android/state.dart';
import '../../core/state.dart';
Expand All @@ -30,27 +29,6 @@ import 'device_avatar.dart';
import 'keys.dart' as keys;
import 'keys.dart';

final _hiddenDevicesProvider =
StateNotifierProvider<_HiddenDevicesNotifier, List<String>>(
(ref) => _HiddenDevicesNotifier(ref.watch(prefProvider)));

class _HiddenDevicesNotifier extends StateNotifier<List<String>> {
static const String _key = 'DEVICE_PICKER_HIDDEN';
final SharedPreferences _prefs;

_HiddenDevicesNotifier(this._prefs) : super(_prefs.getStringList(_key) ?? []);

void showAll() {
state = [];
_prefs.setStringList(_key, state);
}

void hideDevice(DevicePath devicePath) {
state = [...state, devicePath.key];
_prefs.setStringList(_key, state);
}
}

class DevicePickerContent extends ConsumerWidget {
final bool extended;

Expand All @@ -59,7 +37,7 @@ class DevicePickerContent extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = AppLocalizations.of(context)!;
final hidden = ref.watch(_hiddenDevicesProvider);
final hidden = ref.watch(hiddenDevicesProvider);
final devices = ref
.watch(attachedDevicesProvider)
.where((e) => !hidden.contains(e.path.key))
Expand Down Expand Up @@ -343,14 +321,14 @@ class _DeviceRowState extends ConsumerState<_DeviceRow> {
List<PopupMenuItem> _getMenuItems(
BuildContext context, WidgetRef ref, DeviceNode? node) {
final l10n = AppLocalizations.of(context)!;
final hidden = ref.watch(_hiddenDevicesProvider);
final hidden = ref.watch(hiddenDevicesProvider);

return [
if (isDesktop && hidden.isNotEmpty)
PopupMenuItem(
enabled: hidden.isNotEmpty,
onTap: () {
ref.read(_hiddenDevicesProvider.notifier).showAll();
ref.read(hiddenDevicesProvider.notifier).showAll();
},
child: ListTile(
title: Text(l10n.s_show_hidden_devices),
Expand All @@ -363,7 +341,7 @@ class _DeviceRowState extends ConsumerState<_DeviceRow> {
if (isDesktop && node is NfcReaderNode)
PopupMenuItem(
onTap: () {
ref.read(_hiddenDevicesProvider.notifier).hideDevice(node.path);
ref.read(hiddenDevicesProvider.notifier).hideDevice(node.path);
},
child: ListTile(
title: Text(l10n.s_hide_device),
Expand Down
2 changes: 2 additions & 0 deletions lib/app/views/keys.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ const settingDrawerIcon = Key('$_prefix.settings_drawer_icon');
const helpDrawerIcon = Key('$_prefix.setting_drawer_icon');
const themeModeSetting = Key('$_prefix.settings.theme_mode');
const languageSetting = Key('$_prefix.settings.language');
const toggleDevicesSetting = Key('$_prefix.settings.toggle_devices');
const customIconSetting = Key('$_prefix.settings.custom_icons');
Key themeModeOption(ThemeMode mode) => Key('$_prefix.theme_mode.${mode.name}');
const tosButton = Key('$_prefix.tos_button');
const privacyButton = Key('$_prefix.privacy_button');
Expand Down
107 changes: 107 additions & 0 deletions lib/app/views/settings_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:material_symbols_icons/symbols.dart';

import '../../android/state.dart';
import '../../android/views/settings_views.dart';
import '../../core/models.dart';
import '../../core/state.dart';
import '../../widgets/list_title.dart';
import '../../widgets/responsive_dialog.dart';
Expand Down Expand Up @@ -149,6 +151,7 @@ class _IconsView extends ConsumerWidget {
return ListTile(
title: Text(l10n.s_custom_icons),
subtitle: Text(l10n.l_set_icons_for_accounts),
key: keys.customIconSetting,
onTap: () {
showDialog(
context: context,
Expand All @@ -160,6 +163,109 @@ class _IconsView extends ConsumerWidget {
}
}

class _ToggleDevicesDialog extends ConsumerWidget {
const _ToggleDevicesDialog();

@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = AppLocalizations.of(context)!;
final theme = Theme.of(context);
final textTheme = theme.textTheme;
final colorScheme = theme.colorScheme;
final hidden = ref.watch(hiddenDevicesProvider);
final nfcDevices = ref
.watch(attachedDevicesProvider)
.where((e) => e.transport == Transport.nfc);
if (nfcDevices.isEmpty) {
Navigator.of(context).pop();
}
return ResponsiveDialog(
title: Text(l10n.s_toggle_devices),
dialogMaxWidth: 500,
builder: (context, _) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 18.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(l10n.p_toggle_devices_desc),
const SizedBox(height: 8.0),
...nfcDevices.map(
(e) => Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Symbols.contactless,
color: colorScheme.onSurfaceVariant,
),
const SizedBox(width: 12.0),
Flexible(
child: Text(
e.name,
style: textTheme.bodyMedium
?.copyWith(color: colorScheme.onSurfaceVariant),
softWrap: false,
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(
width: 12.0,
)
],
),
),
Switch(
value: !hidden.contains(e.path.key),
onChanged: (show) {
if (!show) {
ref
.read(hiddenDevicesProvider.notifier)
.hideDevice(e.path);
} else {
ref
.read(hiddenDevicesProvider.notifier)
.showDevice(e.path);
}
},
)
],
),
)
],
),
),
);
}
}

class _ToggleDevicesView extends ConsumerWidget {
const _ToggleDevicesView();

@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = AppLocalizations.of(context)!;
final nfcDevices = ref
.watch(attachedDevicesProvider)
.where((e) => e.transport == Transport.nfc);

return ListTile(
title: Text(l10n.s_toggle_devices),
subtitle: Text(l10n.l_toggle_devices_desc),
key: keys.toggleDevicesSetting,
enabled: nfcDevices.isNotEmpty,
onTap: () {
showDialog(
context: context, builder: (context) => _ToggleDevicesDialog());
},
);
}
}

class SettingsPage extends ConsumerWidget {
const SettingsPage({super.key});

Expand Down Expand Up @@ -189,6 +295,7 @@ class SettingsPage extends ConsumerWidget {
const _ThemeModeView(),
const _IconsView(),
ListTitle(l10n.s_options),
if (!isAndroid) const _ToggleDevicesView(),
const _LanguageView()
],
),
Expand Down
3 changes: 3 additions & 0 deletions lib/l10n/app_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@
"s_select_to_scan": "Zum Scannen auswählen",
"s_hide_device": "Gerät verstecken",
"s_show_hidden_devices": "Versteckte Geräte anzeigen",
"s_toggle_devices": null,
"l_toggle_devices_desc": null,
"p_toggle_devices_desc": null,
"s_sn_serial": "S/N: {serial}",
"@s_sn_serial": {
"placeholders": {
Expand Down
3 changes: 3 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@
"s_select_to_scan": "Select to scan",
"s_hide_device": "Hide device",
"s_show_hidden_devices": "Show hidden devices",
"s_toggle_devices": "Toggle devices",
"l_toggle_devices_desc": "Show or hide devices",
"p_toggle_devices_desc": "Show or hide devices.",
"s_sn_serial": "S/N: {serial}",
"@s_sn_serial": {
"placeholders": {
Expand Down
3 changes: 3 additions & 0 deletions lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@
"s_select_to_scan": "Sélectionner pour scanner",
"s_hide_device": "Masquer appareil",
"s_show_hidden_devices": "Afficher appareils masqués",
"s_toggle_devices": null,
"l_toggle_devices_desc": null,
"p_toggle_devices_desc": null,
"s_sn_serial": "N/S\u00a0: {serial}",
"@s_sn_serial": {
"placeholders": {
Expand Down
3 changes: 3 additions & 0 deletions lib/l10n/app_ja.arb
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@
"s_select_to_scan": "選択してスキャン",
"s_hide_device": "デバイスを非表示",
"s_show_hidden_devices": "非表示のデバイスを表示",
"s_toggle_devices": null,
"l_toggle_devices_desc": null,
"p_toggle_devices_desc": null,
"s_sn_serial": "S/N:{serial}",
"@s_sn_serial": {
"placeholders": {
Expand Down
3 changes: 3 additions & 0 deletions lib/l10n/app_pl.arb
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@
"s_select_to_scan": "Wybierz, aby zeskanować",
"s_hide_device": "Ukryj urządzenie",
"s_show_hidden_devices": "Pokaż ukryte urządzenia",
"s_toggle_devices": null,
"l_toggle_devices_desc": null,
"p_toggle_devices_desc": null,
"s_sn_serial": "S/N: {serial}",
"@s_sn_serial": {
"placeholders": {
Expand Down
3 changes: 3 additions & 0 deletions lib/l10n/app_sk.arb
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@
"s_select_to_scan": "Vyberte na skenovanie",
"s_hide_device": "Skryť zariadenie",
"s_show_hidden_devices": "Zobraziť skryté zariadenia",
"s_toggle_devices": null,
"l_toggle_devices_desc": null,
"p_toggle_devices_desc": null,
"s_sn_serial": "S/N: {serial}",
"@s_sn_serial": {
"placeholders": {
Expand Down
3 changes: 3 additions & 0 deletions lib/l10n/app_vi.arb
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@
"s_select_to_scan": "Chọn để quét",
"s_hide_device": "Ẩn thiết bị",
"s_show_hidden_devices": "Hiển thị các thiết bị ẩn",
"s_toggle_devices": null,
"l_toggle_devices_desc": null,
"p_toggle_devices_desc": null,
"s_sn_serial": "S/N: {serial}",
"@s_sn_serial": {
"placeholders": {
Expand Down
4 changes: 3 additions & 1 deletion lib/widgets/responsive_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class ResponsiveDialog extends StatefulWidget {
final List<Widget> actions;
final Function()? onCancel;
final bool allowCancel;
final double dialogMaxWidth;

const ResponsiveDialog({
super.key,
Expand All @@ -34,6 +35,7 @@ class ResponsiveDialog extends StatefulWidget {
this.actions = const [],
this.onCancel,
this.allowCancel = true,
this.dialogMaxWidth = 600,
});

@override
Expand Down Expand Up @@ -88,7 +90,7 @@ class _ResponsiveDialogState extends State<ResponsiveDialog> {
scrollable: true,
contentPadding: const EdgeInsets.symmetric(vertical: 8),
content: SizedBox(
width: 600,
width: widget.dialogMaxWidth,
child:
Container(key: _childKey, child: widget.builder(context, false)),
),
Expand Down

0 comments on commit e92b8b9

Please sign in to comment.