This commit is contained in:
moon 2026-04-20 16:14:46 +06:30
parent 1bf4c99843
commit fb2dbd1865
11 changed files with 129 additions and 1 deletions

View File

@ -1,5 +1,6 @@
import 'package:cb_prestige_qr/core/utils/MainShell.dart';
import 'package:flutter/material.dart';
import 'package:local_auth/local_auth.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@ -8,13 +9,33 @@ class LoginPage extends StatefulWidget {
State<LoginPage> createState() => _LoginPageState();
}
enum _SupportState { unknown, supported, unsupported }
class _LoginPageState extends State<LoginPage> {
final _formKey = GlobalKey<FormState>();
final _usernameController = TextEditingController();
final _passwordController = TextEditingController();
final LocalAuthentication auth = LocalAuthentication();
bool? _canCheckBiometric;
List<BiometricType>? _availableBiometrics;
String _authorized = "Not Authorized";
bool _isAuthenticating = false;
_SupportState _supportState = _SupportState.unknown;
var _obscurePassword = true;
@override
void initState(){
super.initState();
auth.isDeviceSupported().then(
(bool isSupported) => setState(
() => _supportState = isSupported
? _SupportState.supported
: _SupportState.unsupported,
),
);
}
@override
void dispose() {
_usernameController.dispose();

View File

@ -4,6 +4,7 @@ abstract class SettingsLocalDataSource {
SettingsContent getSettings();
void setNotificationsEnabled(bool value);
void setHapticsEnabled(bool value);
void setFingerEnabled(bool value);
}
class SettingsLocalDataSourceImpl implements SettingsLocalDataSource {
@ -11,12 +12,14 @@ class SettingsLocalDataSourceImpl implements SettingsLocalDataSource {
bool _notificationsEnabled = true;
bool _hapticsEnabled = true;
bool _fingerEnabled = true;
@override
SettingsContent getSettings() {
return SettingsContent(
notificationsEnabled: _notificationsEnabled,
hapticsEnabled: _hapticsEnabled,
fingerEnabled: _fingerEnabled,
appVersionLabel: 'v1.0.0',
);
}
@ -30,4 +33,9 @@ class SettingsLocalDataSourceImpl implements SettingsLocalDataSource {
void setHapticsEnabled(bool value) {
_hapticsEnabled = value;
}
@override
void setFingerEnabled(bool value) {
_fingerEnabled = value;
}
}

View File

@ -19,4 +19,9 @@ class SettingsRepositoryImpl implements SettingsRepository {
Future<void> setHapticsEnabled(bool value) async {
_localDataSource.setHapticsEnabled(value);
}
@override
Future<void> setFingerEnabled(bool value) async {
_localDataSource.setFingerEnabled(value);
}
}

View File

@ -2,10 +2,12 @@ class SettingsContent {
const SettingsContent({
required this.notificationsEnabled,
required this.hapticsEnabled,
required this.fingerEnabled,
required this.appVersionLabel,
});
final bool notificationsEnabled;
final bool hapticsEnabled;
final bool fingerEnabled;
final String appVersionLabel;
}

View File

@ -4,4 +4,5 @@ abstract class SettingsRepository {
Future<SettingsContent> getSettings();
Future<void> setNotificationsEnabled(bool value);
Future<void> setHapticsEnabled(bool value);
Future<void> setFingerEnabled(bool value);
}

View File

@ -0,0 +1,9 @@
import '../repositories/settings_repository.dart';
class SetFingerEnabled {
const SetFingerEnabled(this._repository);
final SettingsRepository _repository;
Future<void> call(bool value) => _repository.setFingerEnabled(value);
}

View File

@ -5,21 +5,25 @@ class SettingsUiState {
const SettingsUiState({
required this.notificationsEnabled,
required this.hapticsEnabled,
required this.fingerEnabled,
required this.appVersionLabel,
});
final bool notificationsEnabled;
final bool hapticsEnabled;
final bool fingerEnabled;
final String appVersionLabel;
SettingsUiState copyWith({
bool? notificationsEnabled,
bool? hapticsEnabled,
bool? fingerEnabled,
String? appVersionLabel,
}) {
return SettingsUiState(
notificationsEnabled: notificationsEnabled ?? this.notificationsEnabled,
hapticsEnabled: hapticsEnabled ?? this.hapticsEnabled,
fingerEnabled: fingerEnabled ?? this.fingerEnabled,
appVersionLabel: appVersionLabel ?? this.appVersionLabel,
);
}

View File

@ -5,6 +5,7 @@ import '../../data/repositories/settings_repository_impl.dart';
import '../../domain/entities/settings_content.dart';
import '../../domain/repositories/settings_repository.dart';
import '../../domain/use_cases/get_settings.dart';
import '../../domain/use_cases/set_finger_enabled.dart';
import '../../domain/use_cases/set_haptics_enabled.dart';
import '../../domain/use_cases/set_notifications_enabled.dart';
import 'settings_ui_state.dart';
@ -29,6 +30,10 @@ final _setHapticsEnabledProvider = Provider<SetHapticsEnabled>(
(ref) => SetHapticsEnabled(ref.watch(_settingsRepositoryProvider)),
);
final _setFingerEnabledProvider = Provider<SetFingerEnabled>(
(ref) => SetFingerEnabled(ref.watch(_settingsRepositoryProvider)),
);
final settingsViewModelProvider =
AsyncNotifierProvider<SettingsViewModel, SettingsUiState>(
SettingsViewModel.new,
@ -45,6 +50,7 @@ class SettingsViewModel extends AsyncNotifier<SettingsUiState> {
return SettingsUiState(
notificationsEnabled: content.notificationsEnabled,
hapticsEnabled: content.hapticsEnabled,
fingerEnabled: content.fingerEnabled,
appVersionLabel: content.appVersionLabel,
);
}
@ -58,4 +64,9 @@ class SettingsViewModel extends AsyncNotifier<SettingsUiState> {
await ref.watch(_setHapticsEnabledProvider)(value);
state = state.whenData((s) => s.copyWith(hapticsEnabled: value));
}
Future<void> toggleFinger(bool value) async {
await ref.watch(_setFingerEnabledProvider)(value);
state = state.whenData((s) => s.copyWith(fingerEnabled: value));
}
}

View File

@ -27,6 +27,7 @@ class SettingsPage extends ConsumerWidget {
state: state,
onNotificationsChanged: viewModel.toggleNotifications,
onHapticsChanged: viewModel.toggleHaptics,
onFingerChanged: viewModel.toggleFinger,
),
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, stackTrace) => Center(
@ -45,11 +46,13 @@ class _SettingsBody extends StatelessWidget {
required this.state,
required this.onNotificationsChanged,
required this.onHapticsChanged,
required this.onFingerChanged,
});
final SettingsUiState state;
final ValueChanged<bool> onNotificationsChanged;
final ValueChanged<bool> onHapticsChanged;
final ValueChanged<bool> onFingerChanged;
@override
Widget build(BuildContext context) {
@ -72,6 +75,13 @@ class _SettingsBody extends StatelessWidget {
title: const Text('Haptics'),
subtitle: const Text('Vibration feedback'),
),
const Divider(height: 1),
SwitchListTile.adaptive(
value: state.fingerEnabled,
onChanged: onFingerChanged,
title: const Text('Fingerprint'),
subtitle: const Text('Enable fingerprint authentication'),
),
],
),
const SizedBox(height: 12),

View File

@ -278,6 +278,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.4.7"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: "38d1c268de9097ff59cf0e844ac38759fc78f76836d37edad06fa21e182055a0"
url: "https://pub.dev"
source: hosted
version: "2.0.34"
flutter_riverpod:
dependency: transitive
description:
@ -384,6 +392,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.8.0"
intl:
dependency: transitive
description:
name: intl
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
url: "https://pub.dev"
source: hosted
version: "0.20.2"
io:
dependency: transitive
description:
@ -432,6 +448,46 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.1.0"
local_auth:
dependency: "direct main"
description:
name: local_auth
sha256: ae6f382f638108c6becd134318d7c3f0a93875383a54010f61d7c97ac05d5137
url: "https://pub.dev"
source: hosted
version: "3.0.1"
local_auth_android:
dependency: transitive
description:
name: local_auth_android
sha256: b41970749c2d43791790724b76917eeee1e90de76e6b0eec3edca03a329bf44c
url: "https://pub.dev"
source: hosted
version: "2.0.7"
local_auth_darwin:
dependency: transitive
description:
name: local_auth_darwin
sha256: a8c3d4e17454111f7fd31ff72a31222359f6059f7fe956c2dcfe0f88f49826d4
url: "https://pub.dev"
source: hosted
version: "2.0.3"
local_auth_platform_interface:
dependency: transitive
description:
name: local_auth_platform_interface
sha256: f98b8e388588583d3f781f6806e4f4c9f9e189d898d27f0c249b93a1973dd122
url: "https://pub.dev"
source: hosted
version: "1.1.0"
local_auth_windows:
dependency: transitive
description:
name: local_auth_windows
sha256: be12c5b8ba5e64896983123655c5f67d2484ecfcc95e367952ad6e3bff94cb16
url: "https://pub.dev"
source: hosted
version: "2.0.1"
logging:
dependency: transitive
description:
@ -855,4 +911,4 @@ packages:
version: "3.1.3"
sdks:
dart: ">=3.11.3 <4.0.0"
flutter: ">=3.35.0"
flutter: ">=3.38.0"

View File

@ -40,6 +40,7 @@ dependencies:
riverpod_annotation: ^4.0.2
carousel_slider: ^5.1.2
mobile_scanner: ^7.2.0
local_auth: ^3.0.1
dev_dependencies:
flutter_test: