mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
support setting new download path on android
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<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"/>
|
||||
<application
|
||||
android:label="venera"
|
||||
android:name="${applicationName}"
|
||||
|
@@ -3,8 +3,16 @@ package com.github.wgh136.venera
|
||||
import android.app.Activity
|
||||
import android.content.ContentResolver
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.view.KeyEvent
|
||||
import android.Manifest
|
||||
import android.os.Environment
|
||||
import android.provider.Settings
|
||||
import androidx.annotation.RequiresApi
|
||||
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.engine.FlutterEngine
|
||||
@@ -23,6 +31,9 @@ class MainActivity : FlutterActivity() {
|
||||
|
||||
private lateinit var result: MethodChannel.Result
|
||||
|
||||
private val storageRequestCode = 0x10
|
||||
private var storagePermissionRequest: ((Boolean) -> Unit)? = null
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == pickDirectoryCode) {
|
||||
@@ -43,6 +54,11 @@ class MainActivity : FlutterActivity() {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +105,13 @@ class MainActivity : FlutterActivity() {
|
||||
listening = false
|
||||
}
|
||||
})
|
||||
|
||||
val storageChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "venera/storage")
|
||||
storageChannel.setMethodCallHandler { _, res ->
|
||||
requestStoragePermission {result ->
|
||||
res.success(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getProxy(): String {
|
||||
@@ -145,6 +168,61 @@ class MainActivity : FlutterActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestStoragePermission(result: (Boolean) -> Unit) {
|
||||
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
val readPermission = ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
|
||||
val writePermission = ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
|
||||
if (!readPermission || !writePermission) {
|
||||
storagePermissionRequest = result
|
||||
ActivityCompat.requestPermissions(
|
||||
this,
|
||||
arrayOf(
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
),
|
||||
storageRequestCode
|
||||
)
|
||||
} else {
|
||||
result(true)
|
||||
}
|
||||
} else {
|
||||
if (!Environment.isExternalStorageManager()) {
|
||||
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)
|
||||
} catch (e: Exception) {
|
||||
result(false)
|
||||
}
|
||||
} else {
|
||||
result(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<out String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if(requestCode == storageRequestCode) {
|
||||
storagePermissionRequest?.invoke(grantResults.all {
|
||||
it == PackageManager.PERMISSION_GRANTED
|
||||
})
|
||||
storagePermissionRequest = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VolumeListen{
|
||||
|
@@ -5,6 +5,7 @@ import 'package:path_provider/path_provider.dart';
|
||||
import 'package:sqlite3/sqlite3.dart';
|
||||
import 'package:venera/foundation/comic_source/comic_source.dart';
|
||||
import 'package:venera/foundation/comic_type.dart';
|
||||
import 'package:venera/foundation/log.dart';
|
||||
import 'package:venera/network/download.dart';
|
||||
import 'package:venera/pages/reader/reader.dart';
|
||||
import 'package:venera/utils/ext.dart';
|
||||
@@ -158,12 +159,13 @@ class LocalManager with ChangeNotifier {
|
||||
return "Directory is not empty";
|
||||
}
|
||||
try {
|
||||
await copyDirectory(
|
||||
await copyDirectoryIsolate(
|
||||
Directory(path),
|
||||
newDir,
|
||||
);
|
||||
await File(FilePath.join(App.dataPath, 'local_path')).writeAsString(path);
|
||||
} catch (e) {
|
||||
} catch (e, s) {
|
||||
Log.error("IO", e, s);
|
||||
return e.toString();
|
||||
}
|
||||
await Directory(path).deleteIgnoreError(recursive:true);
|
||||
|
@@ -32,12 +32,28 @@ class _AppSettingsState extends State<AppSettings> {
|
||||
title: "Set New Storage Path".tl,
|
||||
actionTitle: "Set".tl,
|
||||
callback: () async {
|
||||
var result;
|
||||
String? result;
|
||||
if (App.isAndroid) {
|
||||
context.showMessage(message: "Not supported".tl);
|
||||
return;
|
||||
}
|
||||
else if (App.isIOS) {
|
||||
var channel = const MethodChannel("venera/storage");
|
||||
var permission = await channel.invokeMethod('');
|
||||
if(permission != true) {
|
||||
context.showMessage(message: "Permission denied".tl);
|
||||
return;
|
||||
}
|
||||
var path = await selectDirectory();
|
||||
if(path != null) {
|
||||
// check if the path is writable
|
||||
var testFile = File(FilePath.join(path, "test"));
|
||||
try {
|
||||
await testFile.writeAsBytes([1]);
|
||||
await testFile.delete();
|
||||
} catch (e) {
|
||||
context.showMessage(message: "Permission denied".tl);
|
||||
return;
|
||||
}
|
||||
result = path;
|
||||
}
|
||||
} else if (App.isIOS) {
|
||||
result = await selectDirectoryIOS();
|
||||
} else {
|
||||
result = await selectDirectory();
|
||||
|
@@ -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:permission_handler/permission_handler.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import 'package:venera/components/components.dart';
|
||||
import 'package:venera/foundation/app.dart';
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_file_dialog/flutter_file_dialog.dart';
|
||||
@@ -113,6 +114,12 @@ Future<void> copyDirectory(Directory source, Directory destination) async {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> copyDirectoryIsolate(Directory source, Directory destination) async {
|
||||
await Isolate.run(() {
|
||||
copyDirectory(source, destination);
|
||||
});
|
||||
}
|
||||
|
||||
String findValidDirectoryName(String path, String directory) {
|
||||
var name = sanitizeFileName(directory);
|
||||
var dir = Directory("$path/$name");
|
||||
|
48
pubspec.lock
48
pubspec.lock
@@ -593,6 +593,54 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
permission_handler:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: permission_handler
|
||||
sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.3.1"
|
||||
permission_handler_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_android
|
||||
sha256: "71bbecfee799e65aff7c744761a57e817e73b738fedf62ab7afd5593da21f9f1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "12.0.13"
|
||||
permission_handler_apple:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_apple
|
||||
sha256: e6f6d73b12438ef13e648c4ae56bd106ec60d17e90a59c4545db6781229082a0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.4.5"
|
||||
permission_handler_html:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_html
|
||||
sha256: af26edbbb1f2674af65a8f4b56e1a6f526156bc273d0e65dd8075fab51c78851
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.3+2"
|
||||
permission_handler_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_platform_interface
|
||||
sha256: e9c8eadee926c4532d0305dff94b85bf961f16759c3af791486613152af4b4f9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.3"
|
||||
permission_handler_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_windows
|
||||
sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.1"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@@ -63,6 +63,7 @@ dependencies:
|
||||
git:
|
||||
url: https://github.com/wgh136/webdav_client
|
||||
ref: 285f87f15bccd2d5d5ff443761348c6ee47b98d1
|
||||
permission_handler: ^11.3.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h>
|
||||
#include <flutter_qjs/flutter_qjs_plugin.h>
|
||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||
#include <screen_retriever_windows/screen_retriever_windows_plugin_c_api.h>
|
||||
#include <share_plus/share_plus_windows_plugin_c_api.h>
|
||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||
@@ -28,6 +29,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi"));
|
||||
FlutterQjsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterQjsPlugin"));
|
||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||
ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi"));
|
||||
SharePlusWindowsPluginCApiRegisterWithRegistrar(
|
||||
|
@@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_selector_windows
|
||||
flutter_inappwebview_windows
|
||||
flutter_qjs
|
||||
permission_handler_windows
|
||||
screen_retriever_windows
|
||||
share_plus
|
||||
sqlite3_flutter_libs
|
||||
|
Reference in New Issue
Block a user