Files
submanager/lib/providers/app_lock_provider.dart
JiWoong Sul 843fa0601a chore: 불필요한 코드 및 빈 디렉토리 제거
- 미사용 파일 삭제: confirmation_dialog.dart
- 빈 디렉토리 삭제: shadcn, mappers, common/dialogs
- app_lock_provider: BuildContext async gap 경고 수정
2025-12-22 16:50:03 +09:00

180 lines
4.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:local_auth/local_auth.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import '../services/notification_service.dart';
import '../providers/subscription_provider.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import '../l10n/app_localizations.dart';
import '../navigator_key.dart';
class AppLockProvider extends ChangeNotifier {
final Box<bool> _appLockBox;
final LocalAuthentication _localAuth = LocalAuthentication();
final FlutterSecureStorage _secureStorage = const FlutterSecureStorage();
static const String _isEnabledKey = 'app_lock_enabled';
bool _isEnabled = false;
bool _isLocked = false;
bool _isBiometricEnabled = false;
bool _isBiometricAvailable = false;
AppLockProvider(this._appLockBox) {
_init();
}
bool get isEnabled => _isEnabled;
bool get isLocked => _isLocked;
bool get isBiometricEnabled => _isBiometricEnabled;
bool get isBiometricAvailable => _isBiometricAvailable;
Future<void> _init() async {
if (!kIsWeb) {
_isBiometricAvailable = await _localAuth.canCheckBiometrics;
} else {
_isBiometricAvailable = false;
}
_isLocked = _appLockBox.get('isLocked', defaultValue: false) ?? false;
await _loadState();
notifyListeners();
}
Future<void> _loadState() async {
final value = await _secureStorage.read(key: _isEnabledKey);
_isEnabled = value == 'true';
_isLocked = _appLockBox.get('isLocked', defaultValue: false) ?? false;
await _loadSettings();
notifyListeners();
}
Future<void> _loadSettings() async {
try {
final biometricEnabled =
await _secureStorage.read(key: 'biometric_enabled');
_isBiometricEnabled = biometricEnabled == 'true';
notifyListeners();
} catch (e) {
debugPrint('설정 로드 중 오류 발생: $e');
}
}
Future<bool> authenticate() async {
if (kIsWeb) {
_isLocked = false;
notifyListeners();
return true;
}
try {
// async 전에 context 기반 데이터 미리 획득
final ctx = navigatorKey.currentContext;
final loc = ctx != null ? AppLocalizations.of(ctx) : null;
final localizedReason =
loc?.unlockWithBiometric ?? 'Unlock with biometric authentication.';
final canCheck = await _checkBiometrics();
if (!canCheck) {
_isLocked = false;
notifyListeners();
return true;
}
final authenticated = await _localAuth.authenticate(
localizedReason: localizedReason,
options: const AuthenticationOptions(
stickyAuth: true,
biometricOnly: true,
),
);
if (authenticated) {
_isLocked = false;
await _appLockBox.put('isLocked', false);
notifyListeners();
}
return authenticated;
} catch (e) {
_isLocked = false;
notifyListeners();
return true;
}
}
Future<bool> _checkBiometrics() async {
if (kIsWeb) return false;
try {
return await _localAuth.canCheckBiometrics;
} catch (e) {
return false;
}
}
Future<void> toggleBiometricAuth() async {
if (kIsWeb) {
_isBiometricEnabled = false;
await _appLockBox.put('biometric_enabled', false);
notifyListeners();
return;
}
try {
final canCheck = await _checkBiometrics();
if (!canCheck) {
_isBiometricEnabled = false;
await _appLockBox.put('biometric_enabled', false);
notifyListeners();
return;
}
_isBiometricEnabled = !_isBiometricEnabled;
await _secureStorage.write(
key: 'biometric_enabled',
value: _isBiometricEnabled.toString(),
);
await _appLockBox.put('biometric_enabled', _isBiometricEnabled);
notifyListeners();
} catch (e) {
_isBiometricEnabled = false;
await _appLockBox.put('biometric_enabled', false);
notifyListeners();
}
}
void lock() {
if (_isBiometricEnabled) {
_isLocked = true;
notifyListeners();
}
}
Future<void> unlock() async {
_isLocked = false;
await _appLockBox.put('isLocked', false);
notifyListeners();
}
Future<void> enable() async {
_isEnabled = true;
await _secureStorage.write(key: _isEnabledKey, value: 'true');
notifyListeners();
}
Future<void> disable() async {
_isEnabled = false;
await _secureStorage.write(key: _isEnabledKey, value: 'false');
notifyListeners();
}
Future<void> refreshNotifications(BuildContext context) async {
final subscriptionProvider = Provider.of<SubscriptionProvider>(
context,
listen: false,
);
for (var subscription in subscriptionProvider.subscriptions) {
await NotificationService.scheduleSubscriptionNotification(subscription);
}
}
}