app_state.dart 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import 'package:pb_authenticator_state/state.dart';
  2. import 'package:pb_authenticator_totp/totp.dart';
  3. import 'package:flutter/widgets.dart';
  4. import 'package:collection/collection.dart' show ListEquality;
  5. import 'package:shared_preferences/shared_preferences.dart';
  6. import 'package:flutter/material.dart';
  7. import 'package:flutter_secure_storage/flutter_secure_storage.dart';
  8. import 'package:local_auth/local_auth.dart';
  9. // TODO: Transition to new type
  10. typedef BaseItemType = LegacyAuthenticatorItem;
  11. /// Represents app state.
  12. class AppState extends ChangeNotifier {
  13. final RepositoryBase<BaseItemType> _repository;
  14. // Theme and screen capture settings
  15. ThemeMode _themeMode = ThemeMode.system;
  16. bool _screenCapturePrevented = false;
  17. // PIN and biometric settings
  18. bool _pinEnabled = false;
  19. bool _biometricEnabled = false;
  20. DateTime? _lastUnlockTime;
  21. static const _pinTimeout = Duration(minutes: 5);
  22. static const _pinKey = 'app_pin';
  23. static const _pinEnabledKey = 'pinEnabled';
  24. static const _biometricEnabledKey = 'biometricEnabled';
  25. static final _secureStorage = FlutterSecureStorage();
  26. bool get pinEnabled => _pinEnabled;
  27. bool get biometricEnabled => _biometricEnabled;
  28. DateTime? get lastUnlockTime => _lastUnlockTime;
  29. Duration get pinTimeout => _pinTimeout;
  30. ThemeMode get themeMode => _themeMode;
  31. bool get screenCapturePrevented => _screenCapturePrevented;
  32. AppState(this._repository) {
  33. _loadSettings();
  34. }
  35. /// List of TOTP items (internal implementation).
  36. List<BaseItemType>? _items;
  37. /// TOTP items as list.
  38. List<BaseItemType>? get items {
  39. if (_items == null) {
  40. loadItems();
  41. }
  42. return _items;
  43. }
  44. Future loadItems() async {
  45. _items = await _repository.loadItems();
  46. notifyListeners();
  47. }
  48. /// Adds a TOTP item to the list.
  49. Future addItem(TotpItem item) async {
  50. await _repository.addItem(item);
  51. await loadItems();
  52. }
  53. /// Replace list of TOTP items.
  54. Future replaceItems(List<BaseItemType> items) async {
  55. await _repository.replaceItems(items);
  56. await loadItems();
  57. }
  58. bool itemsChanged(List<BaseItemType>? newItems) {
  59. return !const ListEquality().equals(items, newItems);
  60. }
  61. Future<void> _loadSettings() async {
  62. final prefs = await SharedPreferences.getInstance();
  63. final themeIndex = prefs.getInt('themeMode') ?? 0;
  64. _themeMode = ThemeMode.values[themeIndex];
  65. _screenCapturePrevented = prefs.getBool('screenCapturePrevented') ?? false;
  66. _pinEnabled = prefs.getBool(_pinEnabledKey) ?? false;
  67. _biometricEnabled = prefs.getBool(_biometricEnabledKey) ?? false;
  68. notifyListeners();
  69. }
  70. Future<void> setThemeMode(ThemeMode mode) async {
  71. _themeMode = mode;
  72. final prefs = await SharedPreferences.getInstance();
  73. await prefs.setInt('themeMode', mode.index);
  74. notifyListeners();
  75. }
  76. Future<void> setScreenCapturePrevented(bool value) async {
  77. _screenCapturePrevented = value;
  78. final prefs = await SharedPreferences.getInstance();
  79. await prefs.setBool('screenCapturePrevented', value);
  80. // Platform channel will handle screen capture prevention
  81. notifyListeners();
  82. }
  83. Future<void> setPinEnabled(bool value) async {
  84. _pinEnabled = value;
  85. final prefs = await SharedPreferences.getInstance();
  86. await prefs.setBool(_pinEnabledKey, value);
  87. notifyListeners();
  88. }
  89. Future<void> setBiometricEnabled(bool value) async {
  90. _biometricEnabled = value;
  91. final prefs = await SharedPreferences.getInstance();
  92. await prefs.setBool(_biometricEnabledKey, value);
  93. notifyListeners();
  94. }
  95. Future<void> setPin(String pin) async {
  96. await _secureStorage.write(key: _pinKey, value: pin);
  97. }
  98. Future<String?> getPin() async {
  99. return await _secureStorage.read(key: _pinKey);
  100. }
  101. void updateLastUnlockTime() {
  102. _lastUnlockTime = DateTime.now();
  103. notifyListeners();
  104. }
  105. bool shouldRequireAuth() {
  106. if (!_pinEnabled && !_biometricEnabled) return false;
  107. if (_lastUnlockTime == null) return true;
  108. return DateTime.now().difference(_lastUnlockTime!) > _pinTimeout;
  109. }
  110. }