mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
#165 new: bio auth
This commit is contained in:
@@ -164,6 +164,12 @@ abstract class S {
|
|||||||
/// **'Attention'**
|
/// **'Attention'**
|
||||||
String get attention;
|
String get attention;
|
||||||
|
|
||||||
|
/// No description provided for @authRequired.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Auth required'**
|
||||||
|
String get authRequired;
|
||||||
|
|
||||||
/// No description provided for @auto.
|
/// No description provided for @auto.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
@@ -218,6 +224,12 @@ abstract class S {
|
|||||||
/// **'Run in backgroud'**
|
/// **'Run in backgroud'**
|
||||||
String get bgRun;
|
String get bgRun;
|
||||||
|
|
||||||
|
/// No description provided for @bioAuth.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Biometric auth'**
|
||||||
|
String get bioAuth;
|
||||||
|
|
||||||
/// No description provided for @canPullRefresh.
|
/// No description provided for @canPullRefresh.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ class SDe extends S {
|
|||||||
@override
|
@override
|
||||||
String get attention => 'Achtung';
|
String get attention => 'Achtung';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get authRequired => 'Autorisierung erforderlich';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get auto => 'System folgen';
|
String get auto => 'System folgen';
|
||||||
|
|
||||||
@@ -64,6 +67,9 @@ class SDe extends S {
|
|||||||
@override
|
@override
|
||||||
String get bgRun => 'Hintergrundaktualisierung';
|
String get bgRun => 'Hintergrundaktualisierung';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get bioAuth => 'Biozertifizierung';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get canPullRefresh => 'Danach: herunterziehen zum Aktualisieren';
|
String get canPullRefresh => 'Danach: herunterziehen zum Aktualisieren';
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ class SEn extends S {
|
|||||||
@override
|
@override
|
||||||
String get attention => 'Attention';
|
String get attention => 'Attention';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get authRequired => 'Auth required';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get auto => 'Auto';
|
String get auto => 'Auto';
|
||||||
|
|
||||||
@@ -64,6 +67,9 @@ class SEn extends S {
|
|||||||
@override
|
@override
|
||||||
String get bgRun => 'Run in backgroud';
|
String get bgRun => 'Run in backgroud';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get bioAuth => 'Biometric auth';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get canPullRefresh => 'You can pull to refresh.';
|
String get canPullRefresh => 'You can pull to refresh.';
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ class SId extends S {
|
|||||||
@override
|
@override
|
||||||
String get attention => 'Perhatian';
|
String get attention => 'Perhatian';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get authRequired => 'Auth diperlukan';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get auto => 'Auto';
|
String get auto => 'Auto';
|
||||||
|
|
||||||
@@ -64,6 +67,9 @@ class SId extends S {
|
|||||||
@override
|
@override
|
||||||
String get bgRun => 'Jalankan di Backgroud';
|
String get bgRun => 'Jalankan di Backgroud';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get bioAuth => 'Biosertifikasi';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get canPullRefresh => 'Anda dapat menarik untuk menyegarkan.';
|
String get canPullRefresh => 'Anda dapat menarik untuk menyegarkan.';
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ class SZh extends S {
|
|||||||
@override
|
@override
|
||||||
String get attention => '注意';
|
String get attention => '注意';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get authRequired => '需要认证';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get auto => '自动';
|
String get auto => '自动';
|
||||||
|
|
||||||
@@ -64,6 +67,9 @@ class SZh extends S {
|
|||||||
@override
|
@override
|
||||||
String get bgRun => '后台运行';
|
String get bgRun => '后台运行';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get bioAuth => '生物认证';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get canPullRefresh => '可以下拉刷新';
|
String get canPullRefresh => '可以下拉刷新';
|
||||||
|
|
||||||
@@ -772,6 +778,9 @@ class SZhTw extends SZh {
|
|||||||
@override
|
@override
|
||||||
String get attention => '注意';
|
String get attention => '注意';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get authRequired => '需要認證';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get auto => '自動';
|
String get auto => '自動';
|
||||||
|
|
||||||
@@ -799,6 +808,9 @@ class SZhTw extends SZh {
|
|||||||
@override
|
@override
|
||||||
String get bgRun => '背景運行';
|
String get bgRun => '背景運行';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get bioAuth => '生物認證';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get canPullRefresh => '可以下拉更新';
|
String get canPullRefresh => '可以下拉更新';
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:label="ServerBox"
|
android:label="ServerBox"
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package tech.lolli.toolbox
|
package tech.lolli.toolbox
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
|
|
||||||
class MainActivity : FlutterActivity() {
|
class MainActivity: FlutterFragmentActivity() {
|
||||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||||
super.configureFlutterEngine(flutterEngine)
|
super.configureFlutterEngine(flutterEngine)
|
||||||
val binaryMessenger = flutterEngine.dartExecutor.binaryMessenger
|
val binaryMessenger = flutterEngine.dartExecutor.binaryMessenger
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- icloud_storage (0.0.1):
|
- icloud_storage (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- local_auth_ios (0.0.1):
|
||||||
|
- Flutter
|
||||||
- path_provider_foundation (0.0.1):
|
- path_provider_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
@@ -29,6 +31,7 @@ DEPENDENCIES:
|
|||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
||||||
- icloud_storage (from `.symlinks/plugins/icloud_storage/ios`)
|
- icloud_storage (from `.symlinks/plugins/icloud_storage/ios`)
|
||||||
|
- local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`)
|
||||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- plain_notification_token (from `.symlinks/plugins/plain_notification_token/ios`)
|
- plain_notification_token (from `.symlinks/plugins/plain_notification_token/ios`)
|
||||||
- r_upgrade (from `.symlinks/plugins/r_upgrade/ios`)
|
- r_upgrade (from `.symlinks/plugins/r_upgrade/ios`)
|
||||||
@@ -47,6 +50,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/flutter_native_splash/ios"
|
:path: ".symlinks/plugins/flutter_native_splash/ios"
|
||||||
icloud_storage:
|
icloud_storage:
|
||||||
:path: ".symlinks/plugins/icloud_storage/ios"
|
:path: ".symlinks/plugins/icloud_storage/ios"
|
||||||
|
local_auth_ios:
|
||||||
|
:path: ".symlinks/plugins/local_auth_ios/ios"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||||
plain_notification_token:
|
plain_notification_token:
|
||||||
@@ -66,6 +71,7 @@ SPEC CHECKSUMS:
|
|||||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||||
flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
|
flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
|
||||||
icloud_storage: d9ac7a33ced81df08ba7ea1bf3099cc0ee58f60a
|
icloud_storage: d9ac7a33ced81df08ba7ea1bf3099cc0ee58f60a
|
||||||
|
local_auth_ios: c6cf091ded637a88f24f86a8875d8b0f526e2605
|
||||||
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||||
plain_notification_token: b36467dc91939a7b6754267c701bbaca14996ee1
|
plain_notification_token: b36467dc91939a7b6754267c701bbaca14996ee1
|
||||||
r_upgrade: 44d715c61914cce3d01ea225abffe894fd51c114
|
r_upgrade: 44d715c61914cce3d01ea225abffe894fd51c114
|
||||||
|
|||||||
@@ -68,5 +68,7 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
<false/>
|
<false/>
|
||||||
|
<key>NSFaceIDUsageDescription</key>
|
||||||
|
<string>Required for auth</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -64,5 +64,7 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>NSLocalNetworkUsageDescription</key>
|
<key>NSLocalNetworkUsageDescription</key>
|
||||||
<string>ServerBox needs to access your local network to discover and connect to your server.</string>
|
<string>ServerBox needs to access your local network to discover and connect to your server.</string>
|
||||||
|
<key>NSFaceIDUsageDescription</key>
|
||||||
|
<string>Required for auth</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -58,5 +58,7 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
<false/>
|
<false/>
|
||||||
|
<key>NSFaceIDUsageDescription</key>
|
||||||
|
<string>Required for auth</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
63
lib/core/utils/platform/auth.dart
Normal file
63
lib/core/utils/platform/auth.dart
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:local_auth/local_auth.dart';
|
||||||
|
import 'package:toolbox/core/utils/platform/base.dart';
|
||||||
|
import 'package:local_auth/error_codes.dart' as errs;
|
||||||
|
|
||||||
|
class BioAuth {
|
||||||
|
const BioAuth._();
|
||||||
|
|
||||||
|
static final _auth = LocalAuthentication();
|
||||||
|
|
||||||
|
static bool get isPlatformSupported => isAndroid || isIOS || isWindows;
|
||||||
|
|
||||||
|
static Future<bool> get isAvail async {
|
||||||
|
if (!isPlatformSupported) return false;
|
||||||
|
final canCheckBiometrics = await _auth.canCheckBiometrics;
|
||||||
|
if (!canCheckBiometrics) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final biometrics = await _auth.getAvailableBiometrics();
|
||||||
|
if (biometrics.isEmpty) return false;
|
||||||
|
return biometrics.contains(BiometricType.fingerprint) ||
|
||||||
|
biometrics.contains(BiometricType.face);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<AuthResult> auth([String? msg]) async {
|
||||||
|
if (!await isAvail) return AuthResult.notAvail;
|
||||||
|
try {
|
||||||
|
final reuslt = await _auth.authenticate(
|
||||||
|
localizedReason: msg ?? 'Auth required',
|
||||||
|
options: const AuthenticationOptions(
|
||||||
|
stickyAuth: true,
|
||||||
|
sensitiveTransaction: true,
|
||||||
|
biometricOnly: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (reuslt) {
|
||||||
|
return AuthResult.success;
|
||||||
|
}
|
||||||
|
return AuthResult.fail;
|
||||||
|
} on PlatformException catch (e) {
|
||||||
|
switch (e.code) {
|
||||||
|
case errs.notEnrolled:
|
||||||
|
return AuthResult.notAvail;
|
||||||
|
case errs.lockedOut:
|
||||||
|
case errs.permanentlyLockedOut:
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
return AuthResult.cancel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AuthResult {
|
||||||
|
success,
|
||||||
|
// Not match
|
||||||
|
fail,
|
||||||
|
// User cancel
|
||||||
|
cancel,
|
||||||
|
// Device doesn't support biometrics
|
||||||
|
notAvail,
|
||||||
|
}
|
||||||
@@ -205,6 +205,13 @@ class SettingStore extends PersistentStore {
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Only valid on iOS / Android
|
||||||
|
late final useBioAuth = StoreProperty(
|
||||||
|
box,
|
||||||
|
'useBioAuth',
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
// Never show these settings for users
|
// Never show these settings for users
|
||||||
// Guide for these settings:
|
// Guide for these settings:
|
||||||
// - key should start with `_` and be shorter as possible
|
// - key should start with `_` and be shorter as possible
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"alreadyLastDir": "Bereits im letzten Verzeichnis.",
|
"alreadyLastDir": "Bereits im letzten Verzeichnis.",
|
||||||
"alterUrl": "Url ändern",
|
"alterUrl": "Url ändern",
|
||||||
"attention": "Achtung",
|
"attention": "Achtung",
|
||||||
|
"authRequired": "Autorisierung erforderlich",
|
||||||
"auto": "System folgen",
|
"auto": "System folgen",
|
||||||
"autoCheckUpdate": "Aktualisierung automatisch prüfen",
|
"autoCheckUpdate": "Aktualisierung automatisch prüfen",
|
||||||
"autoConnect": "Automatisch verbinden",
|
"autoConnect": "Automatisch verbinden",
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
"backupTip": "Das Backup wird nur einfach verschlüsselt.\nBitte bewahre die Datei sicher auf.",
|
"backupTip": "Das Backup wird nur einfach verschlüsselt.\nBitte bewahre die Datei sicher auf.",
|
||||||
"backupVersionNotMatch": "Die Backup-Version stimmt nicht überein.",
|
"backupVersionNotMatch": "Die Backup-Version stimmt nicht überein.",
|
||||||
"bgRun": "Hintergrundaktualisierung",
|
"bgRun": "Hintergrundaktualisierung",
|
||||||
|
"bioAuth": "Biozertifizierung",
|
||||||
"canPullRefresh": "Danach: herunterziehen zum Aktualisieren",
|
"canPullRefresh": "Danach: herunterziehen zum Aktualisieren",
|
||||||
"cancel": "Abbrechen",
|
"cancel": "Abbrechen",
|
||||||
"choose": "Auswählen",
|
"choose": "Auswählen",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"alreadyLastDir": "Already in last directory.",
|
"alreadyLastDir": "Already in last directory.",
|
||||||
"alterUrl": "Alter url",
|
"alterUrl": "Alter url",
|
||||||
"attention": "Attention",
|
"attention": "Attention",
|
||||||
|
"authRequired": "Auth required",
|
||||||
"auto": "Auto",
|
"auto": "Auto",
|
||||||
"autoCheckUpdate": "Auto check update",
|
"autoCheckUpdate": "Auto check update",
|
||||||
"autoConnect": "Auto connect",
|
"autoConnect": "Auto connect",
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
"backupTip": "The exported data is simply encrypted. \nPlease keep it safe.",
|
"backupTip": "The exported data is simply encrypted. \nPlease keep it safe.",
|
||||||
"backupVersionNotMatch": "Backup version is not match.",
|
"backupVersionNotMatch": "Backup version is not match.",
|
||||||
"bgRun": "Run in backgroud",
|
"bgRun": "Run in backgroud",
|
||||||
|
"bioAuth": "Biometric auth",
|
||||||
"canPullRefresh": "You can pull to refresh.",
|
"canPullRefresh": "You can pull to refresh.",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"choose": "Choose",
|
"choose": "Choose",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"alreadyLastDir": "Sudah di direktori terakhir.",
|
"alreadyLastDir": "Sudah di direktori terakhir.",
|
||||||
"alterUrl": "Alter url",
|
"alterUrl": "Alter url",
|
||||||
"attention": "Perhatian",
|
"attention": "Perhatian",
|
||||||
|
"authRequired": "Auth diperlukan",
|
||||||
"auto": "Auto",
|
"auto": "Auto",
|
||||||
"autoCheckUpdate": "Periksa pembaruan otomatis",
|
"autoCheckUpdate": "Periksa pembaruan otomatis",
|
||||||
"autoConnect": "Hubungkan otomatis",
|
"autoConnect": "Hubungkan otomatis",
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
"backupTip": "Data yang diekspor hanya dienkripsi.\nTolong jaga keamanannya.",
|
"backupTip": "Data yang diekspor hanya dienkripsi.\nTolong jaga keamanannya.",
|
||||||
"backupVersionNotMatch": "Versi cadangan tidak cocok.",
|
"backupVersionNotMatch": "Versi cadangan tidak cocok.",
|
||||||
"bgRun": "Jalankan di Backgroud",
|
"bgRun": "Jalankan di Backgroud",
|
||||||
|
"bioAuth": "Biosertifikasi",
|
||||||
"canPullRefresh": "Anda dapat menarik untuk menyegarkan.",
|
"canPullRefresh": "Anda dapat menarik untuk menyegarkan.",
|
||||||
"cancel": "Membatalkan",
|
"cancel": "Membatalkan",
|
||||||
"choose": "Memilih",
|
"choose": "Memilih",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"alreadyLastDir": "已经是最上层目录了",
|
"alreadyLastDir": "已经是最上层目录了",
|
||||||
"alterUrl": "备选链接",
|
"alterUrl": "备选链接",
|
||||||
"attention": "注意",
|
"attention": "注意",
|
||||||
|
"authRequired": "需要认证",
|
||||||
"auto": "自动",
|
"auto": "自动",
|
||||||
"autoCheckUpdate": "自动检查更新",
|
"autoCheckUpdate": "自动检查更新",
|
||||||
"autoConnect": "自动连接",
|
"autoConnect": "自动连接",
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
"backupTip": "导出的数据仅进行了简单加密,请妥善保管。",
|
"backupTip": "导出的数据仅进行了简单加密,请妥善保管。",
|
||||||
"backupVersionNotMatch": "备份版本不匹配,无法恢复",
|
"backupVersionNotMatch": "备份版本不匹配,无法恢复",
|
||||||
"bgRun": "后台运行",
|
"bgRun": "后台运行",
|
||||||
|
"bioAuth": "生物认证",
|
||||||
"canPullRefresh": "可以下拉刷新",
|
"canPullRefresh": "可以下拉刷新",
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"choose": "选择",
|
"choose": "选择",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"alreadyLastDir": "已經是最上層目錄了",
|
"alreadyLastDir": "已經是最上層目錄了",
|
||||||
"alterUrl": "備選鏈接",
|
"alterUrl": "備選鏈接",
|
||||||
"attention": "注意",
|
"attention": "注意",
|
||||||
|
"authRequired": "需要認證",
|
||||||
"auto": "自動",
|
"auto": "自動",
|
||||||
"autoCheckUpdate": "自動檢查更新",
|
"autoCheckUpdate": "自動檢查更新",
|
||||||
"autoConnect": "自動連接",
|
"autoConnect": "自動連接",
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
"backupTip": "導出的數據僅進行了簡單加密,請妥善保管。",
|
"backupTip": "導出的數據僅進行了簡單加密,請妥善保管。",
|
||||||
"backupVersionNotMatch": "備份版本不匹配,無法還原",
|
"backupVersionNotMatch": "備份版本不匹配,無法還原",
|
||||||
"bgRun": "背景運行",
|
"bgRun": "背景運行",
|
||||||
|
"bioAuth": "生物認證",
|
||||||
"canPullRefresh": "可以下拉更新",
|
"canPullRefresh": "可以下拉更新",
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"choose": "選擇",
|
"choose": "選擇",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:get_it/get_it.dart';
|
|||||||
import 'package:toolbox/core/channel/bg_run.dart';
|
import 'package:toolbox/core/channel/bg_run.dart';
|
||||||
import 'package:toolbox/core/channel/home_widget.dart';
|
import 'package:toolbox/core/channel/home_widget.dart';
|
||||||
import 'package:toolbox/core/extension/context/dialog.dart';
|
import 'package:toolbox/core/extension/context/dialog.dart';
|
||||||
|
import 'package:toolbox/core/utils/platform/auth.dart';
|
||||||
import 'package:toolbox/core/utils/platform/base.dart';
|
import 'package:toolbox/core/utils/platform/base.dart';
|
||||||
import 'package:toolbox/data/res/github_id.dart';
|
import 'package:toolbox/data/res/github_id.dart';
|
||||||
import 'package:toolbox/data/res/logger.dart';
|
import 'package:toolbox/data/res/logger.dart';
|
||||||
@@ -46,6 +47,7 @@ class _HomePageState extends State<HomePage>
|
|||||||
late S _s;
|
late S _s;
|
||||||
|
|
||||||
bool _switchingPage = false;
|
bool _switchingPage = false;
|
||||||
|
bool _isAuthing = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -81,6 +83,7 @@ class _HomePageState extends State<HomePage>
|
|||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case AppLifecycleState.resumed:
|
case AppLifecycleState.resumed:
|
||||||
|
_auth();
|
||||||
if (!Providers.server.isAutoRefreshOn) {
|
if (!Providers.server.isAutoRefreshOn) {
|
||||||
Providers.server.startAutoRefresh();
|
Providers.server.startAutoRefresh();
|
||||||
}
|
}
|
||||||
@@ -338,6 +341,8 @@ class _HomePageState extends State<HomePage>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> afterFirstLayout(BuildContext context) async {
|
Future<void> afterFirstLayout(BuildContext context) async {
|
||||||
|
// Auth required for first launch
|
||||||
|
_auth();
|
||||||
if (Stores.setting.autoCheckAppUpdate.fetch()) {
|
if (Stores.setting.autoCheckAppUpdate.fetch()) {
|
||||||
doUpdate(context);
|
doUpdate(context);
|
||||||
}
|
}
|
||||||
@@ -385,4 +390,32 @@ class _HomePageState extends State<HomePage>
|
|||||||
Loggers.app.warning('Update json settings failed', e, trace);
|
Loggers.app.warning('Update json settings failed', e, trace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _auth() {
|
||||||
|
if (Stores.setting.useBioAuth.fetch()) {
|
||||||
|
if (!_isAuthing) {
|
||||||
|
_isAuthing = true;
|
||||||
|
BioAuth.auth(_s.authRequired).then(
|
||||||
|
(val) {
|
||||||
|
switch (val) {
|
||||||
|
case AuthResult.success:
|
||||||
|
// wait for animation
|
||||||
|
Future.delayed(
|
||||||
|
const Duration(seconds: 1), () => _isAuthing = false);
|
||||||
|
break;
|
||||||
|
case AuthResult.fail:
|
||||||
|
case AuthResult.cancel:
|
||||||
|
_isAuthing = false;
|
||||||
|
_auth();
|
||||||
|
break;
|
||||||
|
case AuthResult.notAvail:
|
||||||
|
_isAuthing = false;
|
||||||
|
Stores.setting.useBioAuth.put(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import 'package:toolbox/core/extension/context/snackbar.dart';
|
|||||||
import 'package:toolbox/core/extension/locale.dart';
|
import 'package:toolbox/core/extension/locale.dart';
|
||||||
import 'package:toolbox/core/extension/context/dialog.dart';
|
import 'package:toolbox/core/extension/context/dialog.dart';
|
||||||
import 'package:toolbox/core/extension/stringx.dart';
|
import 'package:toolbox/core/extension/stringx.dart';
|
||||||
|
import 'package:toolbox/core/utils/platform/auth.dart';
|
||||||
import 'package:toolbox/core/utils/platform/base.dart';
|
import 'package:toolbox/core/utils/platform/base.dart';
|
||||||
import 'package:toolbox/data/res/provider.dart';
|
import 'package:toolbox/data/res/provider.dart';
|
||||||
import 'package:toolbox/data/res/store.dart';
|
import 'package:toolbox/data/res/store.dart';
|
||||||
@@ -183,13 +184,16 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
//_buildLaunchPage(),
|
//_buildLaunchPage(),
|
||||||
_buildCheckUpdate(),
|
_buildCheckUpdate(),
|
||||||
];
|
];
|
||||||
|
if (isAndroid) {
|
||||||
|
children.add(_buildBgRun());
|
||||||
|
children.add(_buildAndroidWidgetSharedPreference());
|
||||||
|
}
|
||||||
if (isIOS) {
|
if (isIOS) {
|
||||||
children.add(_buildPushToken());
|
children.add(_buildPushToken());
|
||||||
children.add(_buildAutoUpdateHomeWidget());
|
children.add(_buildAutoUpdateHomeWidget());
|
||||||
}
|
}
|
||||||
if (isAndroid) {
|
if (BioAuth.isPlatformSupported) {
|
||||||
children.add(_buildBgRun());
|
children.add(_buildBioAuth());
|
||||||
children.add(_buildAndroidWidgetSharedPreference());
|
|
||||||
}
|
}
|
||||||
return Column(
|
return Column(
|
||||||
children: children.map((e) => RoundRectCard(e)).toList(),
|
children: children.map((e) => RoundRectCard(e)).toList(),
|
||||||
@@ -1096,4 +1100,41 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
// trailing: StoreSwitch(prop: _setting.doubleColumnServersPage),
|
// trailing: StoreSwitch(prop: _setting.doubleColumnServersPage),
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
Widget _buildBioAuth() {
|
||||||
|
return FutureWidget<bool>(
|
||||||
|
future: BioAuth.isAvail,
|
||||||
|
loading: ListTile(
|
||||||
|
title: Text(_s.bioAuth),
|
||||||
|
subtitle: Text(_s.serverTabLoading, style: UIs.textGrey),
|
||||||
|
),
|
||||||
|
error: (e, __) => ListTile(
|
||||||
|
title: Text(_s.bioAuth),
|
||||||
|
subtitle: Text('${_s.failed}: $e', style: UIs.textGrey),
|
||||||
|
),
|
||||||
|
success: (can) {
|
||||||
|
return ListTile(
|
||||||
|
title: Text(_s.bioAuth),
|
||||||
|
trailing: can
|
||||||
|
? StoreSwitch(
|
||||||
|
prop: Stores.setting.useBioAuth,
|
||||||
|
func: (val) async {
|
||||||
|
if (val) {
|
||||||
|
Stores.setting.useBioAuth.put(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Only auth when turn off (val == false)
|
||||||
|
final result = await BioAuth.auth(_s.authRequired);
|
||||||
|
// If failed, turn on again
|
||||||
|
if (result != AuthResult.success) {
|
||||||
|
Stores.setting.useBioAuth.put(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: Text(_s.error, style: UIs.textGrey),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
noData: UIs.placeholder,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class FutureWidget<T> extends StatelessWidget {
|
class FutureWidget<T> extends StatelessWidget {
|
||||||
final Future future;
|
final Future<T> future;
|
||||||
final Widget loading;
|
final Widget loading;
|
||||||
final Widget Function(Object? error, StackTrace? trace) error;
|
final Widget Function(Object? error, StackTrace? trace) error;
|
||||||
final Widget Function(T data) success;
|
final Widget Function(T data) success;
|
||||||
|
|||||||
40
pubspec.lock
40
pubspec.lock
@@ -518,6 +518,46 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.1"
|
||||||
|
local_auth:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: local_auth
|
||||||
|
sha256: "7e6c63082e399b61e4af71266b012e767a5d4525dd6e9ba41e174fd42d76e115"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.7"
|
||||||
|
local_auth_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: local_auth_android
|
||||||
|
sha256: "9ad0b1ffa6f04f4d91e38c2d4c5046583e23f4cae8345776a994e8670df57fb1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.34"
|
||||||
|
local_auth_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: local_auth_ios
|
||||||
|
sha256: "26a8d1ad0b4ef6f861d29921be8383000fda952e323a5b6752cf82ca9cf9a7a9"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.4"
|
||||||
|
local_auth_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: local_auth_platform_interface
|
||||||
|
sha256: fc5bd537970a324260fda506cfb61b33ad7426f37a8ea5c461cf612161ebba54
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.8"
|
||||||
|
local_auth_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: local_auth_windows
|
||||||
|
sha256: "505ba3367ca781efb1c50d3132e44a2446bccc4163427bc203b9b4d8994d97ea"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.10"
|
||||||
logging:
|
logging:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ dependencies:
|
|||||||
macos_window_utils: ^1.2.0
|
macos_window_utils: ^1.2.0
|
||||||
dynamic_color: ^1.6.6
|
dynamic_color: ^1.6.6
|
||||||
icloud_storage: ^2.2.0
|
icloud_storage: ^2.2.0
|
||||||
|
local_auth: ^2.1.7
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_native_splash: ^2.1.6
|
flutter_native_splash: ^2.1.6
|
||||||
|
|||||||
@@ -7,12 +7,15 @@
|
|||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <dynamic_color/dynamic_color_plugin_c_api.h>
|
#include <dynamic_color/dynamic_color_plugin_c_api.h>
|
||||||
|
#include <local_auth_windows/local_auth_plugin.h>
|
||||||
#include <share_plus/share_plus_windows_plugin_c_api.h>
|
#include <share_plus/share_plus_windows_plugin_c_api.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
DynamicColorPluginCApiRegisterWithRegistrar(
|
DynamicColorPluginCApiRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
|
registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
|
||||||
|
LocalAuthPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("LocalAuthPlugin"));
|
||||||
SharePlusWindowsPluginCApiRegisterWithRegistrar(
|
SharePlusWindowsPluginCApiRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
|
registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
|
||||||
UrlLauncherWindowsRegisterWithRegistrar(
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
dynamic_color
|
dynamic_color
|
||||||
|
local_auth_windows
|
||||||
share_plus
|
share_plus
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user