Skip to content

Commit

Permalink
Merge PR #1785
Browse files Browse the repository at this point in the history
  • Loading branch information
elibon99 committed Feb 7, 2025
2 parents afcaf56 + 7df3ba6 commit 607df24
Show file tree
Hide file tree
Showing 13 changed files with 181 additions and 43 deletions.
26 changes: 26 additions & 0 deletions lib/app/state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,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
34 changes: 6 additions & 28 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,17 +321,17 @@ 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),
title: Text(l10n.s_show_hidden_readers),
leading: const Icon(Symbols.visibility),
dense: true,
contentPadding: EdgeInsets.zero,
Expand All @@ -363,10 +341,10 @@ 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),
title: Text(l10n.s_hide_reader),
leading: const Icon(Symbols.visibility_off),
dense: true,
contentPadding: EdgeInsets.zero,
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
1 change: 1 addition & 0 deletions lib/app/views/main_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class MainPage extends ConsumerWidget {
'user_interaction_prompt',
'oath_add_account',
'icon_pack_dialog',
'toggle_readers_dialog',
'android_qr_scanner_view',
].contains(route.settings.name);
});
Expand Down
111 changes: 111 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 @@ -175,6 +177,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(
// Avoid duplicate SafeAreas
Expand All @@ -190,6 +193,113 @@ class _IconsView extends ConsumerWidget {
}
}

class _ToggleReadersDialog extends ConsumerWidget {
const _ToggleReadersDialog();

@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) {
// Pop dialog if no NFC devices
Navigator.of(context).pop();
}
return ResponsiveDialog(
title: Text(l10n.s_toggle_readers),
dialogMaxWidth: 500,
builder: (context, _) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 18.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(l10n.l_toggle_readers_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 _ToggleReadersView extends ConsumerWidget {
const _ToggleReadersView();

@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_readers),
subtitle: Text(l10n.l_toggle_readers_desc),
key: keys.toggleDevicesSetting,
enabled: nfcDevices.isNotEmpty,
onTap: () {
showDialog(
context: context,
routeSettings: const RouteSettings(name: 'toggle_readers_dialog'),
builder: (context) => _ToggleReadersDialog(),
);
},
);
}
}

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

Expand Down Expand Up @@ -219,6 +329,7 @@ class SettingsPage extends ConsumerWidget {
const _ThemeModeView(),
const _IconsView(),
ListTitle(l10n.s_options),
if (!isAndroid) const _ToggleReadersView(),
const _LanguageView()
],
),
Expand Down
8 changes: 7 additions & 1 deletion lib/desktop/state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,15 @@ class DesktopCurrentDeviceNotifier extends CurrentDeviceNotifier {
DeviceNode? build() {
SharedPreferences prefs = ref.watch(prefProvider);
final devices = ref.watch(attachedDevicesProvider);
final hidden = ref.watch(hiddenDevicesProvider);
final lastDevice = prefs.getString(_lastDevice) ?? '';

var node = devices.where((dev) => dev.path.key == lastDevice).firstOrNull;
// Ensure hidden devices are deselected
var node = devices
.where(
(dev) => dev.path.key == lastDevice && !hidden.contains(dev.path.key),
)
.firstOrNull;
if (node == null) {
final parts = lastDevice.split('/');
if (parts.firstOrNull == 'pid') {
Expand Down
6 changes: 4 additions & 2 deletions lib/l10n/app_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,10 @@

"@_yubikey_selection": {},
"s_select_to_scan": "Zum Scannen auswählen",
"s_hide_device": "Gerät verstecken",
"s_show_hidden_devices": "Versteckte Geräte anzeigen",
"s_hide_reader": null,
"s_show_hidden_readers": null,
"s_toggle_readers": null,
"l_toggle_readers_desc": null,
"s_sn_serial": "S/N: {serial}",
"@s_sn_serial": {
"placeholders": {
Expand Down
6 changes: 4 additions & 2 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,10 @@

"@_yubikey_selection": {},
"s_select_to_scan": "Select to scan",
"s_hide_device": "Hide device",
"s_show_hidden_devices": "Show hidden devices",
"s_hide_reader": "Hide reader",
"s_show_hidden_readers": "Show hidden readers",
"s_toggle_readers": "Toggle readers",
"l_toggle_readers_desc": "Show or hide readers",
"s_sn_serial": "S/N: {serial}",
"@s_sn_serial": {
"placeholders": {
Expand Down
6 changes: 4 additions & 2 deletions lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,10 @@

"@_yubikey_selection": {},
"s_select_to_scan": "Sélectionner pour scanner",
"s_hide_device": "Masquer appareil",
"s_show_hidden_devices": "Afficher appareils masqués",
"s_hide_reader": null,
"s_show_hidden_readers": null,
"s_toggle_readers": null,
"l_toggle_readers_desc": null,
"s_sn_serial": "N/S\u00a0: {serial}",
"@s_sn_serial": {
"placeholders": {
Expand Down
6 changes: 4 additions & 2 deletions lib/l10n/app_ja.arb
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,10 @@

"@_yubikey_selection": {},
"s_select_to_scan": "選択してスキャン",
"s_hide_device": "デバイスを非表示",
"s_show_hidden_devices": "非表示のデバイスを表示",
"s_hide_reader": null,
"s_show_hidden_readers": null,
"s_toggle_readers": null,
"l_toggle_readers_desc": null,
"s_sn_serial": "S/N:{serial}",
"@s_sn_serial": {
"placeholders": {
Expand Down
6 changes: 4 additions & 2 deletions lib/l10n/app_pl.arb
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,10 @@

"@_yubikey_selection": {},
"s_select_to_scan": "Wybierz, aby zeskanować",
"s_hide_device": "Ukryj urządzenie",
"s_show_hidden_devices": "Pokaż ukryte urządzenia",
"s_hide_reader": null,
"s_show_hidden_readers": null,
"s_toggle_readers": null,
"l_toggle_readers_desc": null,
"s_sn_serial": "S/N: {serial}",
"@s_sn_serial": {
"placeholders": {
Expand Down
6 changes: 4 additions & 2 deletions lib/l10n/app_sk.arb
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,10 @@

"@_yubikey_selection": {},
"s_select_to_scan": "Vyberte na skenovanie",
"s_hide_device": "Skryť zariadenie",
"s_show_hidden_devices": "Zobraziť skryté zariadenia",
"s_hide_reader": null,
"s_show_hidden_readers": null,
"s_toggle_readers": null,
"l_toggle_readers_desc": null,
"s_sn_serial": "S/N: {serial}",
"@s_sn_serial": {
"placeholders": {
Expand Down
6 changes: 4 additions & 2 deletions lib/l10n/app_vi.arb
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,10 @@

"@_yubikey_selection": {},
"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_hide_reader": null,
"s_show_hidden_readers": null,
"s_toggle_readers": null,
"l_toggle_readers_desc": null,
"s_sn_serial": "S/N: {serial}",
"@s_sn_serial": {
"placeholders": {
Expand Down

0 comments on commit 607df24

Please sign in to comment.