app_state.dart 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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. // Show/hide icons setting
  27. bool _showIcons = true;
  28. static const _showIconsKey = 'showIcons';
  29. bool get showIcons => _showIcons;
  30. // Force monochrome icons setting
  31. bool _forceMonochromeIcons = false;
  32. static const _forceMonochromeIconsKey = 'forceMonochromeIcons';
  33. bool get forceMonochromeIcons => _forceMonochromeIcons;
  34. bool get pinEnabled => _pinEnabled;
  35. bool get biometricEnabled => _biometricEnabled;
  36. DateTime? get lastUnlockTime => _lastUnlockTime;
  37. Duration get pinTimeout => _pinTimeout;
  38. ThemeMode get themeMode => _themeMode;
  39. bool get screenCapturePrevented => _screenCapturePrevented;
  40. AppState(this._repository) {
  41. _loadSettings();
  42. }
  43. /// List of TOTP items (internal implementation).
  44. List<BaseItemType>? _items;
  45. /// TOTP items as list.
  46. List<BaseItemType>? get items {
  47. if (_items == null) {
  48. loadItems();
  49. }
  50. return _items;
  51. }
  52. Future loadItems() async {
  53. _items = await _repository.loadItems();
  54. notifyListeners();
  55. }
  56. /// Adds a TOTP item to the list.
  57. Future addItem(TotpItem item) async {
  58. await _repository.addItem(item);
  59. await loadItems();
  60. }
  61. /// Replace list of TOTP items.
  62. Future replaceItems(List<BaseItemType> items) async {
  63. await _repository.replaceItems(items);
  64. await loadItems();
  65. }
  66. bool itemsChanged(List<BaseItemType>? newItems) {
  67. return !const ListEquality().equals(items, newItems);
  68. }
  69. Future<void> _loadSettings() async {
  70. final prefs = await SharedPreferences.getInstance();
  71. final themeIndex = prefs.getInt('themeMode') ?? 0;
  72. _themeMode = ThemeMode.values[themeIndex];
  73. _screenCapturePrevented = prefs.getBool('screenCapturePrevented') ?? false;
  74. _pinEnabled = prefs.getBool(_pinEnabledKey) ?? false;
  75. _biometricEnabled = prefs.getBool(_biometricEnabledKey) ?? false;
  76. _showIcons = prefs.getBool(_showIconsKey) ?? true;
  77. _forceMonochromeIcons = prefs.getBool(_forceMonochromeIconsKey) ?? false;
  78. notifyListeners();
  79. }
  80. Future<void> setThemeMode(ThemeMode mode) async {
  81. _themeMode = mode;
  82. final prefs = await SharedPreferences.getInstance();
  83. await prefs.setInt('themeMode', mode.index);
  84. notifyListeners();
  85. }
  86. Future<void> setScreenCapturePrevented(bool value) async {
  87. _screenCapturePrevented = value;
  88. final prefs = await SharedPreferences.getInstance();
  89. await prefs.setBool('screenCapturePrevented', value);
  90. // Platform channel will handle screen capture prevention
  91. notifyListeners();
  92. }
  93. Future<void> setPinEnabled(bool value) async {
  94. _pinEnabled = value;
  95. final prefs = await SharedPreferences.getInstance();
  96. await prefs.setBool(_pinEnabledKey, value);
  97. notifyListeners();
  98. }
  99. Future<void> setBiometricEnabled(bool value) async {
  100. _biometricEnabled = value;
  101. final prefs = await SharedPreferences.getInstance();
  102. await prefs.setBool(_biometricEnabledKey, value);
  103. notifyListeners();
  104. }
  105. Future<void> setShowIcons(bool value) async {
  106. _showIcons = value;
  107. final prefs = await SharedPreferences.getInstance();
  108. await prefs.setBool(_showIconsKey, value);
  109. notifyListeners();
  110. }
  111. Future<void> setForceMonochromeIcons(bool value) async {
  112. _forceMonochromeIcons = value;
  113. final prefs = await SharedPreferences.getInstance();
  114. await prefs.setBool(_forceMonochromeIconsKey, value);
  115. notifyListeners();
  116. }
  117. Future<void> setPin(String pin) async {
  118. await _secureStorage.write(key: _pinKey, value: pin);
  119. }
  120. Future<String?> getPin() async {
  121. return await _secureStorage.read(key: _pinKey);
  122. }
  123. void updateLastUnlockTime() {
  124. _lastUnlockTime = DateTime.now();
  125. notifyListeners();
  126. }
  127. bool shouldRequireAuth() {
  128. if (!_pinEnabled && !_biometricEnabled) return false;
  129. if (_lastUnlockTime == null) return true;
  130. return DateTime.now().difference(_lastUnlockTime!) > _pinTimeout;
  131. }
  132. }