mirror of
https://github.com/koloideal/Casha.git
synced 2026-06-10 10:25:28 +03:00
update
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
|
||||||
|
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
|
||||||
<application
|
<application
|
||||||
android:label="Casha"
|
android:label="Casha"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
package com.example.casha
|
package com.example.casha
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||||
|
|
||||||
class MainActivity : FlutterActivity()
|
class MainActivity : FlutterFragmentActivity()
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import 'package:local_auth/local_auth.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
class BiometricService {
|
||||||
|
static final _auth = LocalAuthentication();
|
||||||
|
static const _key = 'biometric_enabled';
|
||||||
|
|
||||||
|
static Future<bool> isAvailable() async {
|
||||||
|
final canCheck = await _auth.canCheckBiometrics;
|
||||||
|
final isSupported = await _auth.isDeviceSupported();
|
||||||
|
return canCheck && isSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<bool> isEnabled() async {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
return prefs.getBool(_key) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<void> setEnabled(bool value) async {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
await prefs.setBool(_key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<bool> authenticate() async {
|
||||||
|
try {
|
||||||
|
return await _auth.authenticate(
|
||||||
|
localizedReason: 'Confirm your identity to open Casha',
|
||||||
|
options: const AuthenticationOptions(
|
||||||
|
biometricOnly: false,
|
||||||
|
stickyAuth: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import '../../core/constants.dart';
|
import '../../core/constants.dart';
|
||||||
|
import '../../core/services/biometric_service.dart';
|
||||||
import '../../shared/utils/currency_utils.dart';
|
import '../../shared/utils/currency_utils.dart';
|
||||||
import '../../shared/providers/amount_format_provider.dart';
|
import '../../shared/providers/amount_format_provider.dart';
|
||||||
import '../dashboard/provider.dart';
|
import '../dashboard/provider.dart';
|
||||||
@@ -387,6 +388,8 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
|
const _BiometricSection(),
|
||||||
|
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@@ -543,3 +546,106 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _BiometricSection extends StatefulWidget {
|
||||||
|
const _BiometricSection();
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_BiometricSection> createState() => _BiometricSectionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BiometricSectionState extends State<_BiometricSection> {
|
||||||
|
bool _available = false;
|
||||||
|
bool _enabled = false;
|
||||||
|
bool _loading = true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_load();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _load() async {
|
||||||
|
final available = await BiometricService.isAvailable();
|
||||||
|
final enabled = await BiometricService.isEnabled();
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_available = available;
|
||||||
|
_enabled = enabled;
|
||||||
|
_loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onToggle(bool val) async {
|
||||||
|
if (val) {
|
||||||
|
final ok = await BiometricService.authenticate();
|
||||||
|
if (!ok) return;
|
||||||
|
}
|
||||||
|
await BiometricService.setEnabled(val);
|
||||||
|
if (mounted) setState(() => _enabled = val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (_loading || !_available) return const SizedBox.shrink();
|
||||||
|
|
||||||
|
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
border: isDark ? null : Border.all(color: const Color(0xFFDDDDEE), width: 1),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.accent.withOpacity(0.15),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: const Icon(
|
||||||
|
Icons.fingerprint,
|
||||||
|
color: AppColors.accent,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Biometric Lock',
|
||||||
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Require fingerprint on app launch',
|
||||||
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Switch(
|
||||||
|
value: _enabled,
|
||||||
|
onChanged: _onToggle,
|
||||||
|
activeColor: const Color(0xFF7C6DED),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import '../../core/services/biometric_service.dart';
|
||||||
|
|
||||||
class SplashScreen extends StatefulWidget {
|
class SplashScreen extends StatefulWidget {
|
||||||
const SplashScreen({super.key});
|
const SplashScreen({super.key});
|
||||||
@@ -28,9 +30,17 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
|
|||||||
|
|
||||||
_controller.forward();
|
_controller.forward();
|
||||||
|
|
||||||
_controller.addStatusListener((status) {
|
_controller.addStatusListener((status) async {
|
||||||
if (status == AnimationStatus.completed) {
|
if (status == AnimationStatus.completed) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
|
final isEnabled = await BiometricService.isEnabled();
|
||||||
|
if (isEnabled) {
|
||||||
|
final authenticated = await BiometricService.authenticate();
|
||||||
|
if (!authenticated) {
|
||||||
|
SystemNavigator.pop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
context.go('/dashboard');
|
context.go('/dashboard');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,10 @@
|
|||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
import local_auth_darwin
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
|
LocalAuthPlugin.register(with: registry.registrar(forPlugin: "LocalAuthPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,6 +166,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.0"
|
version: "6.0.0"
|
||||||
|
flutter_plugin_android_lifecycle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_plugin_android_lifecycle
|
||||||
|
sha256: ee8068e0e1cd16c4a82714119918efdeed33b3ba7772c54b5d094ab53f9b7fd1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.33"
|
||||||
flutter_riverpod:
|
flutter_riverpod:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -288,6 +296,46 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.0"
|
version: "6.1.0"
|
||||||
|
local_auth:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: local_auth
|
||||||
|
sha256: "434d854cf478f17f12ab29a76a02b3067f86a63a6d6c4eb8fbfdcfe4879c1b7b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.0"
|
||||||
|
local_auth_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: local_auth_android
|
||||||
|
sha256: a0bdfcc0607050a26ef5b31d6b4b254581c3d3ce3c1816ab4d4f4a9173e84467
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.56"
|
||||||
|
local_auth_darwin:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: local_auth_darwin
|
||||||
|
sha256: "699873970067a40ef2f2c09b4c72eb1cfef64224ef041b3df9fdc5c4c1f91f49"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.6.1"
|
||||||
|
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: bc4e66a29b0fdf751aafbec923b5bed7ad6ed3614875d8151afe2578520b2ab5
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.11"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ dependencies:
|
|||||||
path_provider: ^2.1.5
|
path_provider: ^2.1.5
|
||||||
http: ^1.2.0
|
http: ^1.2.0
|
||||||
sensors_plus: ^6.1.0
|
sensors_plus: ^6.1.0
|
||||||
|
local_auth: ^2.3.0
|
||||||
|
|
||||||
flutter_launcher_icons:
|
flutter_launcher_icons:
|
||||||
android: true
|
android: true
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <local_auth_windows/local_auth_plugin.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
LocalAuthPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("LocalAuthPlugin"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
local_auth_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
|||||||
Reference in New Issue
Block a user