diff --git a/lib/app/state.dart b/lib/app/state.dart index b2a8c1b9..660622f3 100755 --- a/lib/app/state.dart +++ b/lib/app/state.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:logging/logging.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import '../../core/rpc.dart'; import '../../core/state.dart'; @@ -57,24 +58,35 @@ class AttachedDeviceNotifier extends StateNotifier> { final currentDeviceProvider = StateNotifierProvider((ref) { - final provider = CurrentDeviceNotifier(); + final provider = CurrentDeviceNotifier(ref.watch(prefProvider)); ref.listen(attachedDevicesProvider, provider._updateAttachedDevices); return provider; }); class CurrentDeviceNotifier extends StateNotifier { - CurrentDeviceNotifier() : super(null); + static const String _lastDeviceSerial = 'APP_STATE_LAST_SERIAL'; + final SharedPreferences _prefs; + CurrentDeviceNotifier(this._prefs) : super(null); _updateAttachedDevices(List? previous, List devices) { if (devices.isEmpty) { state = null; } else if (!devices.contains(state)) { - state = devices.first; + // Prefer last selected device + final serial = _prefs.getInt(_lastDeviceSerial) ?? -1; + state = devices.firstWhere( + (element) => element.info.serial == serial, + orElse: () => devices.first, + ); } } setCurrentDevice(DeviceNode device) { state = device; + final serial = device.info.serial; + if (serial != null) { + _prefs.setInt(_lastDeviceSerial, serial); + } } } diff --git a/lib/app/views/device_picker_dialog.dart b/lib/app/views/device_picker_dialog.dart new file mode 100755 index 00000000..5cd153f0 --- /dev/null +++ b/lib/app/views/device_picker_dialog.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../about_page.dart'; +import '../models.dart'; +import '../state.dart'; + +class DevicePickerDialog extends ConsumerWidget { + const DevicePickerDialog({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final device = ref.watch(currentDeviceProvider); + final devices = ref.watch(attachedDevicesProvider); + + Widget _buildDeviceInfo(DeviceNode device) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + Row( + children: [ + const CircleAvatar(child: Text('YK')), + const SizedBox(width: 16.0), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(device.name), + Text( + 'Version: ${device.info.version} Serial: ${device.info.serial}'), + ], + ), + ], + ), + const Divider(), + ], + ), + ); + } + + return SimpleDialog( + //title: Text(device?.name ?? 'No YubiKey'), + children: [ + if (device != null) _buildDeviceInfo(device), + ...devices.where((e) => e != device).map((e) => TextButton( + child: Text(e.name), + onPressed: () { + ref.read(currentDeviceProvider.notifier).setCurrentDevice(e); + Navigator.of(context).pop(); + }, + )), + const Divider(), + TextButton( + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute(builder: (context) => const AboutPage()), + ); + }, + child: const Text('About Yubico Authenticator...')) + ], + ); + } +} diff --git a/lib/app/views/main_page.dart b/lib/app/views/main_page.dart index 847e3a36..5e8f9d98 100755 --- a/lib/app/views/main_page.dart +++ b/lib/app/views/main_page.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'device_picker_dialog.dart'; import 'main_drawer.dart'; import 'no_device_screen.dart'; import 'device_info_screen.dart'; import '../models.dart'; import '../state.dart'; -import '../../about_page.dart'; import '../../oath/views/oath_screen.dart'; class MainPage extends ConsumerWidget { @@ -34,8 +34,9 @@ class MainPage extends ConsumerWidget { IconButton( icon: const Icon(Icons.info), onPressed: () { - Navigator.of(context).push( - MaterialPageRoute(builder: (context) => const AboutPage()), + showDialog( + context: context, + builder: (context) => const DevicePickerDialog(), ); }, )