2021-12-02 13:44:17 +03:00
|
|
|
import 'package:flutter/material.dart';
|
2021-11-19 17:05:57 +03:00
|
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
2021-11-23 15:02:05 +03:00
|
|
|
import 'package:logging/logging.dart';
|
2021-11-23 16:51:36 +03:00
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
2021-11-19 17:05:57 +03:00
|
|
|
|
2021-12-02 13:44:17 +03:00
|
|
|
import '../core/state.dart';
|
|
|
|
import '../oath/menu_actions.dart';
|
2021-11-19 17:05:57 +03:00
|
|
|
import 'models.dart';
|
|
|
|
|
2022-02-21 11:38:09 +03:00
|
|
|
final _log = Logger('app.state');
|
2021-11-23 15:02:05 +03:00
|
|
|
|
2022-03-14 13:48:39 +03:00
|
|
|
// Override this to alter the set of supported apps.
|
|
|
|
final supportedAppsProvider =
|
|
|
|
Provider<List<Application>>((ref) => Application.values);
|
|
|
|
|
2022-01-27 14:34:29 +03:00
|
|
|
// Default implementation is always focused, override with platform specific version.
|
|
|
|
final windowStateProvider = Provider<WindowState>(
|
|
|
|
(ref) => WindowState(focused: true, visible: true, active: true),
|
|
|
|
);
|
2021-12-03 12:27:29 +03:00
|
|
|
|
2021-12-02 13:44:17 +03:00
|
|
|
final themeModeProvider = StateNotifierProvider<ThemeModeNotifier, ThemeMode>(
|
|
|
|
(ref) => ThemeModeNotifier(ref.watch(prefProvider)));
|
|
|
|
|
|
|
|
class ThemeModeNotifier extends StateNotifier<ThemeMode> {
|
|
|
|
static const String _key = 'APP_STATE_THEME';
|
|
|
|
final SharedPreferences _prefs;
|
|
|
|
ThemeModeNotifier(this._prefs) : super(_fromName(_prefs.getString(_key)));
|
|
|
|
|
|
|
|
void setThemeMode(ThemeMode mode) {
|
2022-02-21 11:38:09 +03:00
|
|
|
_log.config('Set theme to $mode');
|
2021-12-02 13:44:17 +03:00
|
|
|
state = mode;
|
|
|
|
_prefs.setString(_key, mode.name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ThemeMode _fromName(String? name) {
|
|
|
|
switch (name) {
|
|
|
|
case 'light':
|
|
|
|
return ThemeMode.light;
|
|
|
|
case 'dark':
|
|
|
|
return ThemeMode.dark;
|
|
|
|
default:
|
|
|
|
return ThemeMode.system;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
final searchProvider =
|
|
|
|
StateNotifierProvider<SearchNotifier, String>((ref) => SearchNotifier());
|
|
|
|
|
|
|
|
class SearchNotifier extends StateNotifier<String> {
|
|
|
|
SearchNotifier() : super('');
|
|
|
|
|
|
|
|
setFilter(String value) {
|
|
|
|
state = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-27 14:34:29 +03:00
|
|
|
// Override with platform implementation
|
2022-03-07 11:57:29 +03:00
|
|
|
final attachedDevicesProvider =
|
|
|
|
StateNotifierProvider<AttachedDevicesNotifier, List<DeviceNode>>(
|
|
|
|
(ref) => AttachedDevicesNotifier([]),
|
2022-01-27 14:34:29 +03:00
|
|
|
);
|
2022-01-12 14:49:04 +03:00
|
|
|
|
2022-03-07 11:57:29 +03:00
|
|
|
class AttachedDevicesNotifier extends StateNotifier<List<DeviceNode>> {
|
|
|
|
AttachedDevicesNotifier(List<DeviceNode> state) : super(state);
|
|
|
|
|
|
|
|
/// Force a refresh of all device data.
|
|
|
|
void refresh() {}
|
|
|
|
}
|
|
|
|
|
2022-01-27 14:34:29 +03:00
|
|
|
// Override with platform implementation
|
2022-03-07 11:57:29 +03:00
|
|
|
final currentDeviceDataProvider = Provider<YubiKeyData?>(
|
2022-03-04 19:45:08 +03:00
|
|
|
(ref) => throw UnimplementedError(),
|
2022-01-27 14:34:29 +03:00
|
|
|
);
|
2022-01-12 14:49:04 +03:00
|
|
|
|
2022-03-21 11:34:45 +03:00
|
|
|
// Override with platform implementation
|
2021-11-19 17:05:57 +03:00
|
|
|
final currentDeviceProvider =
|
2022-03-21 11:34:45 +03:00
|
|
|
StateNotifierProvider<CurrentDeviceNotifier, DeviceNode?>(
|
|
|
|
(ref) => throw UnimplementedError());
|
2021-11-19 17:05:57 +03:00
|
|
|
|
2022-03-21 11:34:45 +03:00
|
|
|
abstract class CurrentDeviceNotifier extends StateNotifier<DeviceNode?> {
|
|
|
|
CurrentDeviceNotifier(DeviceNode? state) : super(state);
|
|
|
|
setCurrentDevice(DeviceNode device);
|
2021-11-19 17:05:57 +03:00
|
|
|
}
|
|
|
|
|
2022-03-14 13:48:39 +03:00
|
|
|
final currentAppProvider =
|
|
|
|
StateNotifierProvider<CurrentAppNotifier, Application>((ref) {
|
|
|
|
final notifier = CurrentAppNotifier(ref.watch(supportedAppsProvider));
|
2022-03-14 12:57:00 +03:00
|
|
|
ref.listen<YubiKeyData?>(currentDeviceDataProvider, (_, data) {
|
|
|
|
notifier._notifyDeviceChanged(data);
|
|
|
|
}, fireImmediately: true);
|
|
|
|
return notifier;
|
|
|
|
});
|
|
|
|
|
2022-03-14 13:48:39 +03:00
|
|
|
class CurrentAppNotifier extends StateNotifier<Application> {
|
|
|
|
final List<Application> _supportedApps;
|
|
|
|
CurrentAppNotifier(this._supportedApps) : super(_supportedApps.first);
|
2021-11-19 17:05:57 +03:00
|
|
|
|
2022-03-14 13:48:39 +03:00
|
|
|
void setCurrentApp(Application app) {
|
|
|
|
state = app;
|
2021-11-19 17:05:57 +03:00
|
|
|
}
|
2021-12-02 13:44:17 +03:00
|
|
|
|
2022-03-14 12:57:00 +03:00
|
|
|
void _notifyDeviceChanged(YubiKeyData? data) {
|
2022-03-14 13:48:39 +03:00
|
|
|
if (data == null ||
|
|
|
|
state.getAvailability(data) != Availability.unsupported) {
|
|
|
|
// Keep current app
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
state = _supportedApps.firstWhere(
|
|
|
|
(app) => app.getAvailability(data) == Availability.enabled,
|
|
|
|
orElse: () => _supportedApps.first,
|
|
|
|
);
|
2022-03-14 12:57:00 +03:00
|
|
|
}
|
|
|
|
}
|
2022-03-04 19:45:08 +03:00
|
|
|
|
2022-02-08 17:40:26 +03:00
|
|
|
final menuActionsProvider = Provider.autoDispose<List<MenuAction>>((ref) {
|
2022-03-14 13:48:39 +03:00
|
|
|
switch (ref.watch(currentAppProvider)) {
|
|
|
|
case Application.oath:
|
2022-02-08 17:40:26 +03:00
|
|
|
return buildOathMenuActions(ref);
|
2022-02-24 17:19:57 +03:00
|
|
|
// TODO: Handle other cases.
|
|
|
|
default:
|
|
|
|
return [];
|
2021-12-02 13:44:17 +03:00
|
|
|
}
|
|
|
|
});
|
2022-02-10 17:24:28 +03:00
|
|
|
|
|
|
|
abstract class QrScanner {
|
|
|
|
Future<String> scanQr();
|
|
|
|
}
|
|
|
|
|
|
|
|
final qrScannerProvider = Provider<QrScanner?>(
|
|
|
|
(ref) => null,
|
|
|
|
);
|