mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
add authorization
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
<uses-permission android:name="android.permission.MANAGE_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.USE_BIOMETRIC"/>
|
||||
<application
|
||||
android:label="venera"
|
||||
android:name="${applicationName}"
|
||||
|
@@ -10,10 +10,11 @@ import android.view.KeyEvent
|
||||
import android.Manifest
|
||||
import android.os.Environment
|
||||
import android.provider.Settings
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.EventChannel
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
@@ -22,82 +23,15 @@ import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.lang.Exception
|
||||
|
||||
class MainActivity : FlutterActivity() {
|
||||
class MainActivity : FlutterFragmentActivity() {
|
||||
var volumeListen = VolumeListen()
|
||||
var listening = false
|
||||
|
||||
private val pickDirectoryCode = 1
|
||||
|
||||
private lateinit var result: MethodChannel.Result
|
||||
|
||||
private val storageRequestCode = 0x10
|
||||
private var storagePermissionRequest: ((Boolean) -> Unit)? = null
|
||||
|
||||
private val selectFileCode = 0x11
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == pickDirectoryCode) {
|
||||
if(resultCode != Activity.RESULT_OK) {
|
||||
result.success(null)
|
||||
return
|
||||
}
|
||||
val pickedDirectoryUri = data?.data
|
||||
if (pickedDirectoryUri == null) {
|
||||
result.success(null)
|
||||
return
|
||||
}
|
||||
Thread {
|
||||
try {
|
||||
result.success(onPickedDirectory(pickedDirectoryUri))
|
||||
}
|
||||
catch (e: Exception) {
|
||||
result.error("Failed to Copy Files", e.toString(), null)
|
||||
}
|
||||
}.start()
|
||||
} else if (requestCode == storageRequestCode) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
storagePermissionRequest?.invoke(Environment.isExternalStorageManager())
|
||||
}
|
||||
storagePermissionRequest = null
|
||||
} else if (requestCode == selectFileCode) {
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
result.success(null)
|
||||
return
|
||||
}
|
||||
val uri = data?.data
|
||||
if (uri == null) {
|
||||
result.success(null)
|
||||
return
|
||||
}
|
||||
val contentResolver = context.contentResolver
|
||||
val file = DocumentFile.fromSingleUri(context, uri)
|
||||
if (file == null) {
|
||||
result.success(null)
|
||||
return
|
||||
}
|
||||
val fileName = file.name
|
||||
if (fileName == null) {
|
||||
result.success(null)
|
||||
return
|
||||
}
|
||||
// copy file to cache directory
|
||||
val cacheDir = context.cacheDir
|
||||
val newFile = File(cacheDir, fileName)
|
||||
val inputStream = contentResolver.openInputStream(uri)
|
||||
if (inputStream == null) {
|
||||
result.success(null)
|
||||
return
|
||||
}
|
||||
val outputStream = FileOutputStream(newFile)
|
||||
inputStream.copyTo(outputStream)
|
||||
inputStream.close()
|
||||
outputStream.close()
|
||||
// send file path to flutter
|
||||
result.success(newFile.absolutePath)
|
||||
}
|
||||
}
|
||||
|
||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||
GeneratedPluginRegistrant.registerWith(flutterEngine)
|
||||
MethodChannel(
|
||||
@@ -115,12 +49,30 @@ class MainActivity : FlutterActivity() {
|
||||
}
|
||||
res.success(null)
|
||||
}
|
||||
|
||||
"getDirectoryPath" -> {
|
||||
this.result = res
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
||||
startActivityForResult(intent, pickDirectoryCode)
|
||||
val launcher =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
|
||||
if (activityResult.resultCode != Activity.RESULT_OK) {
|
||||
result.success(null)
|
||||
}
|
||||
val pickedDirectoryUri = activityResult.data?.data
|
||||
if (pickedDirectoryUri == null)
|
||||
result.success(null)
|
||||
else
|
||||
Thread {
|
||||
try {
|
||||
result.success(onPickedDirectory(pickedDirectoryUri))
|
||||
} catch (e: Exception) {
|
||||
result.error("Failed to Copy Files", e.toString(), null)
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
launcher.launch(intent)
|
||||
}
|
||||
|
||||
else -> res.notImplemented()
|
||||
}
|
||||
}
|
||||
@@ -137,6 +89,7 @@ class MainActivity : FlutterActivity() {
|
||||
events.success(2)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancel(arguments: Any?) {
|
||||
listening = false
|
||||
}
|
||||
@@ -144,7 +97,7 @@ class MainActivity : FlutterActivity() {
|
||||
|
||||
val storageChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "venera/storage")
|
||||
storageChannel.setMethodCallHandler { _, res ->
|
||||
requestStoragePermission {result ->
|
||||
requestStoragePermission { result ->
|
||||
res.success(result)
|
||||
}
|
||||
}
|
||||
@@ -167,12 +120,13 @@ class MainActivity : FlutterActivity() {
|
||||
}
|
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||
if(listening){
|
||||
if (listening) {
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_VOLUME_DOWN -> {
|
||||
volumeListen.down()
|
||||
return true
|
||||
}
|
||||
|
||||
KeyEvent.KEYCODE_VOLUME_UP -> {
|
||||
volumeListen.up()
|
||||
return true
|
||||
@@ -184,8 +138,8 @@ class MainActivity : FlutterActivity() {
|
||||
|
||||
/// copy the directory to tmp directory, return copied directory
|
||||
private fun onPickedDirectory(uri: Uri): String {
|
||||
val contentResolver = context.contentResolver
|
||||
var tmp = context.cacheDir
|
||||
val contentResolver = contentResolver
|
||||
var tmp = cacheDir
|
||||
tmp = File(tmp, "getDirectoryPathTemp")
|
||||
tmp.mkdir()
|
||||
copyDirectory(contentResolver, uri, tmp)
|
||||
@@ -194,9 +148,9 @@ class MainActivity : FlutterActivity() {
|
||||
}
|
||||
|
||||
private fun copyDirectory(resolver: ContentResolver, srcUri: Uri, destDir: File) {
|
||||
val src = DocumentFile.fromTreeUri(context, srcUri) ?: return
|
||||
val src = DocumentFile.fromTreeUri(this, srcUri) ?: return
|
||||
for (file in src.listFiles()) {
|
||||
if(file.isDirectory) {
|
||||
if (file.isDirectory) {
|
||||
val newDir = File(destDir, file.name!!)
|
||||
newDir.mkdir()
|
||||
copyDirectory(resolver, file.uri, newDir)
|
||||
@@ -212,7 +166,7 @@ class MainActivity : FlutterActivity() {
|
||||
}
|
||||
|
||||
private fun requestStoragePermission(result: (Boolean) -> Unit) {
|
||||
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
val readPermission = ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
@@ -241,8 +195,11 @@ class MainActivity : FlutterActivity() {
|
||||
try {
|
||||
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
|
||||
intent.addCategory("android.intent.category.DEFAULT")
|
||||
intent.data = Uri.parse("package:" + context.packageName)
|
||||
startActivityForResult(intent, storageRequestCode)
|
||||
intent.data = Uri.parse("package:$packageName")
|
||||
val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { _ ->
|
||||
result(Environment.isExternalStorageManager())
|
||||
}
|
||||
launcher.launch(intent)
|
||||
} catch (e: Exception) {
|
||||
result(false)
|
||||
}
|
||||
@@ -258,7 +215,7 @@ class MainActivity : FlutterActivity() {
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if(requestCode == storageRequestCode) {
|
||||
if (requestCode == storageRequestCode) {
|
||||
storagePermissionRequest?.invoke(grantResults.all {
|
||||
it == PackageManager.PERMISSION_GRANTED
|
||||
})
|
||||
@@ -266,21 +223,57 @@ class MainActivity : FlutterActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
fun openFile() {
|
||||
private fun openFile() {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
intent.type = "*/*"
|
||||
startActivityForResult(intent, selectFileCode)
|
||||
val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
|
||||
if (activityResult.resultCode != Activity.RESULT_OK) {
|
||||
result.success(null)
|
||||
}
|
||||
val uri = activityResult.data?.data
|
||||
if (uri == null) {
|
||||
result.success(null)
|
||||
return@registerForActivityResult
|
||||
}
|
||||
val contentResolver = contentResolver
|
||||
val file = DocumentFile.fromSingleUri(this, uri)
|
||||
if (file == null) {
|
||||
result.success(null)
|
||||
return@registerForActivityResult
|
||||
}
|
||||
val fileName = file.name
|
||||
if (fileName == null) {
|
||||
result.success(null)
|
||||
return@registerForActivityResult
|
||||
}
|
||||
// copy file to cache directory
|
||||
val cacheDir = cacheDir
|
||||
val newFile = File(cacheDir, fileName)
|
||||
val inputStream = contentResolver.openInputStream(uri)
|
||||
if (inputStream == null) {
|
||||
result.success(null)
|
||||
return@registerForActivityResult
|
||||
}
|
||||
val outputStream = FileOutputStream(newFile)
|
||||
inputStream.copyTo(outputStream)
|
||||
inputStream.close()
|
||||
outputStream.close()
|
||||
// send file path to flutter
|
||||
result.success(newFile.absolutePath)
|
||||
}
|
||||
launcher.launch(intent)
|
||||
}
|
||||
}
|
||||
|
||||
class VolumeListen{
|
||||
class VolumeListen {
|
||||
var onUp = fun() {}
|
||||
var onDown = fun() {}
|
||||
fun up(){
|
||||
fun up() {
|
||||
onUp()
|
||||
}
|
||||
fun down(){
|
||||
|
||||
fun down() {
|
||||
onDown()
|
||||
}
|
||||
}
|
||||
|
@@ -210,7 +210,8 @@
|
||||
"Create Folder": "新建文件夹",
|
||||
"Select an image on screen": "选择屏幕上的图片",
|
||||
"Added @count comics to download queue.": "已添加 @count 本漫画到下载队列",
|
||||
"Ignore Certificate Errors": "忽略证书错误"
|
||||
"Ignore Certificate Errors": "忽略证书错误",
|
||||
"Authorization Required": "需要身份验证"
|
||||
},
|
||||
"zh_TW": {
|
||||
"Home": "首頁",
|
||||
@@ -423,6 +424,7 @@
|
||||
"Create Folder": "新建文件夾",
|
||||
"Select an image on screen": "選擇屏幕上的圖片",
|
||||
"Added @count comics to download queue.": "已添加 @count 本漫畫到下載隊列",
|
||||
"Ignore Certificate Errors": "忽略證書錯誤"
|
||||
"Ignore Certificate Errors": "忽略證書錯誤",
|
||||
"Authorization Required": "需要身份驗證"
|
||||
}
|
||||
}
|
@@ -51,5 +51,7 @@
|
||||
<true/>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<true/>
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>Ensure that the operation is being performed by the user themselves.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@@ -120,6 +120,7 @@ class _Settings with ChangeNotifier {
|
||||
'enableTurnPageByVolumeKey': true,
|
||||
'enableClockAndBatteryInfoInReader': true,
|
||||
'ignoreCertificateErrors': false,
|
||||
'authorizationRequired': false,
|
||||
};
|
||||
|
||||
operator [](String key) {
|
||||
|
@@ -5,7 +5,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:rhttp/rhttp.dart';
|
||||
import 'package:venera/foundation/log.dart';
|
||||
import 'package:venera/network/app_dio.dart';
|
||||
import 'package:venera/pages/auth_page.dart';
|
||||
import 'package:venera/pages/comic_source_page.dart';
|
||||
import 'package:venera/pages/main_page.dart';
|
||||
import 'package:venera/pages/settings/settings_page.dart';
|
||||
@@ -65,15 +65,59 @@ class MyApp extends StatefulWidget {
|
||||
State<MyApp> createState() => _MyAppState();
|
||||
}
|
||||
|
||||
class _MyAppState extends State<MyApp> {
|
||||
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
||||
@override
|
||||
void initState() {
|
||||
checkUpdates();
|
||||
App.registerForceRebuild(forceRebuild);
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
bool isAuthPageActive = false;
|
||||
|
||||
OverlayEntry? hideContentOverlay;
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if(!App.isMobile) {
|
||||
return;
|
||||
}
|
||||
if (state == AppLifecycleState.inactive && hideContentOverlay == null) {
|
||||
hideContentOverlay = OverlayEntry(
|
||||
builder: (context) {
|
||||
return Positioned.fill(
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
color: App.rootContext.colorScheme.surface,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
Overlay.of(App.rootContext).insert(hideContentOverlay!);
|
||||
} else if (hideContentOverlay != null &&
|
||||
state == AppLifecycleState.resumed) {
|
||||
hideContentOverlay!.remove();
|
||||
hideContentOverlay = null;
|
||||
}
|
||||
if (state == AppLifecycleState.hidden &&
|
||||
appdata.settings['authorizationRequired'] &&
|
||||
!isAuthPageActive) {
|
||||
isAuthPageActive = true;
|
||||
App.rootContext.to(
|
||||
() => AuthPage(
|
||||
onSuccessfulAuth: () {
|
||||
App.rootContext.pop();
|
||||
isAuthPageActive = false;
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
super.didChangeAppLifecycleState(state);
|
||||
}
|
||||
|
||||
void forceRebuild() {
|
||||
void rebuild(Element el) {
|
||||
el.markNeedsBuild();
|
||||
@@ -86,14 +130,25 @@ class _MyAppState extends State<MyApp> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget home;
|
||||
if (appdata.settings['authorizationRequired']) {
|
||||
home = AuthPage(
|
||||
onSuccessfulAuth: () {
|
||||
App.rootContext.toReplacement(() => const MainPage());
|
||||
},
|
||||
);
|
||||
} else {
|
||||
home = const MainPage();
|
||||
}
|
||||
return MaterialApp(
|
||||
home: const MainPage(),
|
||||
home: home,
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: App.mainColor,
|
||||
surface: Colors.white,
|
||||
primary: App.mainColor.shade600,
|
||||
// ignore: deprecated_member_use
|
||||
background: Colors.white,
|
||||
),
|
||||
fontFamily: App.isWindows ? "Microsoft YaHei" : null,
|
||||
@@ -105,6 +160,7 @@ class _MyAppState extends State<MyApp> {
|
||||
brightness: Brightness.dark,
|
||||
surface: Colors.black,
|
||||
primary: App.mainColor.shade400,
|
||||
// ignore: deprecated_member_use
|
||||
background: Colors.black,
|
||||
),
|
||||
fontFamily: App.isWindows ? "Microsoft YaHei" : null,
|
||||
@@ -171,12 +227,12 @@ class _MyAppState extends State<MyApp> {
|
||||
}
|
||||
|
||||
void checkUpdates() async {
|
||||
if(!appdata.settings['checkUpdateOnStart']) {
|
||||
if (!appdata.settings['checkUpdateOnStart']) {
|
||||
return;
|
||||
}
|
||||
var lastCheck = appdata.implicitData['lastCheckUpdate'] ?? 0;
|
||||
var now = DateTime.now().millisecondsSinceEpoch;
|
||||
if(now - lastCheck < 24 * 60 * 60 * 1000) {
|
||||
if (now - lastCheck < 24 * 60 * 60 * 1000) {
|
||||
return;
|
||||
}
|
||||
appdata.implicitData['lastCheckUpdate'] = now;
|
||||
|
60
lib/pages/auth_page.dart
Normal file
60
lib/pages/auth_page.dart
Normal file
@@ -0,0 +1,60 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:local_auth/local_auth.dart';
|
||||
import 'package:venera/utils/translations.dart';
|
||||
|
||||
class AuthPage extends StatefulWidget {
|
||||
const AuthPage({super.key, this.onSuccessfulAuth});
|
||||
|
||||
final void Function()? onSuccessfulAuth;
|
||||
|
||||
@override
|
||||
State<AuthPage> createState() => _AuthPageState();
|
||||
}
|
||||
|
||||
class _AuthPageState extends State<AuthPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvokedWithResult: (didPop, result) {
|
||||
if (!didPop) {
|
||||
SystemNavigator.pop();
|
||||
}
|
||||
},
|
||||
child: Material(
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.security, size: 36),
|
||||
const SizedBox(height: 16),
|
||||
Text("Authentication Required".tl),
|
||||
const SizedBox(height: 16),
|
||||
FilledButton(
|
||||
onPressed: auth,
|
||||
child: Text("Continue".tl),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void auth() async {
|
||||
var localAuth = LocalAuthentication();
|
||||
var canCheckBiometrics = await localAuth.canCheckBiometrics;
|
||||
if (!canCheckBiometrics && !await localAuth.isDeviceSupported()) {
|
||||
widget.onSuccessfulAuth?.call();
|
||||
return;
|
||||
}
|
||||
var isAuthorized = await localAuth.authenticate(
|
||||
localizedReason: "Please authenticate to continue".tl,
|
||||
);
|
||||
if (isAuthorized) {
|
||||
widget.onSuccessfulAuth?.call();
|
||||
}
|
||||
}
|
||||
}
|
@@ -36,12 +36,12 @@ class _AppSettingsState extends State<AppSettings> {
|
||||
if (App.isAndroid) {
|
||||
var channel = const MethodChannel("venera/storage");
|
||||
var permission = await channel.invokeMethod('');
|
||||
if(permission != true) {
|
||||
if (permission != true) {
|
||||
context.showMessage(message: "Permission denied".tl);
|
||||
return;
|
||||
}
|
||||
var path = await selectDirectory();
|
||||
if(path != null) {
|
||||
if (path != null) {
|
||||
// check if the path is writable
|
||||
var testFile = File(FilePath.join(path, "test"));
|
||||
try {
|
||||
@@ -177,6 +177,29 @@ class _AppSettingsState extends State<AppSettings> {
|
||||
App.forceRebuild();
|
||||
},
|
||||
).toSliver(),
|
||||
if (!App.isLinux)
|
||||
_SwitchSetting(
|
||||
title: "Authorization Required".tl,
|
||||
settingKey: "authorizationRequired",
|
||||
onChanged: () async {
|
||||
var current = appdata.settings['authorizationRequired'];
|
||||
if (current) {
|
||||
final auth = LocalAuthentication();
|
||||
final bool canAuthenticateWithBiometrics =
|
||||
await auth.canCheckBiometrics;
|
||||
final bool canAuthenticate = canAuthenticateWithBiometrics ||
|
||||
await auth.isDeviceSupported();
|
||||
if (!canAuthenticate) {
|
||||
context.showMessage(message: "Biometrics not supported".tl);
|
||||
setState(() {
|
||||
appdata.settings['authorizationRequired'] = false;
|
||||
});
|
||||
appdata.saveData();
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
).toSliver(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@@ -33,9 +33,10 @@ class _SwitchSettingState extends State<_SwitchSetting> {
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
appdata.settings[widget.settingKey] = value;
|
||||
appdata.saveData();
|
||||
});
|
||||
appdata.saveData().then((_) {
|
||||
widget.onChanged?.call();
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@@ -4,6 +4,7 @@ import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_reorderable_grid_view/widgets/reorderable_builder.dart';
|
||||
import 'package:local_auth/local_auth.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import 'package:venera/components/components.dart';
|
||||
import 'package:venera/foundation/app.dart';
|
||||
|
48
pubspec.lock
48
pubspec.lock
@@ -356,6 +356,14 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
sha256: "9b78450b89f059e96c9ebb355fa6b3df1d6b330436e0b885fb49594c41721398"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.23"
|
||||
flutter_qjs:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -512,6 +520,46 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.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: "6763aaf8965f21822624cb2fd3c03d2a8b3791037b5efb0fe4b13e110f5afc92"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.46"
|
||||
local_auth_darwin:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: local_auth_darwin
|
||||
sha256: "6d2950da311d26d492a89aeb247c72b4653ddc93601ea36a84924a396806d49c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.1"
|
||||
local_auth_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: local_auth_platform_interface
|
||||
sha256: "1b842ff177a7068442eae093b64abe3592f816afd2a533c0ebcdbe40f9d2075a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.10"
|
||||
local_auth_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: local_auth_windows
|
||||
sha256: bc4e66a29b0fdf751aafbec923b5bed7ad6ed3614875d8151afe2578520b2ab5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.11"
|
||||
lodepng_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@@ -64,6 +64,7 @@ dependencies:
|
||||
url: https://github.com/wgh136/webdav_client
|
||||
ref: 285f87f15bccd2d5d5ff443761348c6ee47b98d1
|
||||
battery_plus: ^6.2.0
|
||||
local_auth: ^2.3.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@@ -54,6 +54,7 @@ Source: "{#RootPath}\build\windows\x64\runner\Release\url_launcher_windows_plugi
|
||||
Source: "{#RootPath}\build\windows\x64\runner\Release\battery_plus_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "{#RootPath}\build\windows\x64\runner\Release\screen_retriever_windows_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "{#RootPath}\build\windows\x64\runner\Release\window_manager_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "{#RootPath}\build\windows\x64\runner\Release\local_auth_windows_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "{#RootPath}\build\windows\x64\runner\Release\zip_flutter.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "{#RootPath}\build\windows\x64\runner\Release\rhttp.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "{#RootPath}\build\windows\x64\runner\Release\lodepng_flutter.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
Reference in New Issue
Block a user