diff --git a/.metadata b/.metadata
index f206c92..ea4c51c 100644
--- a/.metadata
+++ b/.metadata
@@ -4,7 +4,7 @@
# This file should be version controlled and should not be manually edited.
version:
- revision: "67457e669f79e9f8d13d7a68fe09775fefbb79f4"
+ revision: "78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9"
channel: "stable"
project_type: app
@@ -13,11 +13,23 @@ project_type: app
migration:
platforms:
- platform: root
- create_revision: 67457e669f79e9f8d13d7a68fe09775fefbb79f4
- base_revision: 67457e669f79e9f8d13d7a68fe09775fefbb79f4
+ create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+ base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+ - platform: android
+ create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+ base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+ - platform: ios
+ create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+ base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
- platform: linux
- create_revision: 67457e669f79e9f8d13d7a68fe09775fefbb79f4
- base_revision: 67457e669f79e9f8d13d7a68fe09775fefbb79f4
+ create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+ base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+ - platform: macos
+ create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+ base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+ - platform: windows
+ create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+ base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
# User provided section
diff --git a/.vscode/settings.json b/.vscode/settings.json
index a01de61..b16d741 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,4 @@
{
- "cmake.sourceDirectory": "C:/Users/Yoyo/Documents/GitHub/Yolx/windows"
+ "cmake.sourceDirectory": "C:/Users/Yoyo/Documents/GitHub/Yolx/windows",
+ "java.configuration.updateBuildConfiguration": "interactive"
}
\ No newline at end of file
diff --git a/android/.gitignore b/android/.gitignore
new file mode 100644
index 0000000..6f56801
--- /dev/null
+++ b/android/.gitignore
@@ -0,0 +1,13 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
+key.properties
+**/*.keystore
+**/*.jks
diff --git a/android/app/build.gradle b/android/app/build.gradle
new file mode 100644
index 0000000..8d58a62
--- /dev/null
+++ b/android/app/build.gradle
@@ -0,0 +1,85 @@
+plugins {
+ id "com.android.application"
+ id "kotlin-android"
+ id "dev.flutter.flutter-gradle-plugin"
+}
+
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file('local.properties')
+if (localPropertiesFile.exists()) {
+ localPropertiesFile.withReader('UTF-8') { reader ->
+ localProperties.load(reader)
+ }
+}
+
+def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
+if (flutterVersionCode == null) {
+ flutterVersionCode = '1'
+}
+
+def flutterVersionName = localProperties.getProperty('flutter.versionName')
+if (flutterVersionName == null) {
+ flutterVersionName = '1.0'
+}
+
+android {
+ namespace "com.yoyo.yolx"
+ compileSdkVersion flutter.compileSdkVersion
+ ndkVersion flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+
+ sourceSets {
+ main {
+ java.srcDirs += 'src/main/kotlin'
+ jniLibs.srcDirs=['src/main/jniLibs']
+ }
+ }
+
+ repositories {
+ flatDir {
+ dirs 'libs'
+ }
+ }
+
+ defaultConfig {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId "com.yoyo.yolx"
+ // You can update the following values to match your application needs.
+ // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
+ minSdkVersion flutter.minSdkVersion
+ targetSdkVersion flutter.targetSdkVersion
+ versionCode flutterVersionCode.toInteger()
+ versionName flutterVersionName
+ ndk {}
+ }
+
+ buildTypes {
+ debug {
+ ndk {
+ // abiFilters "x86"
+ }
+ }
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig signingConfigs.debug
+ }
+ }
+}
+
+flutter {
+ source '../..'
+}
+
+dependencies {
+ implementation fileTree(include: ['*.jar','*.so'], dir: 'libs')
+ implementation 'org.bouncycastle:bcprov-jdk16:1.46'
+}
diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..50cfb13
--- /dev/null
+++ b/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/jniLibs/arm64-v8a/libaria2c.so b/android/app/src/main/jniLibs/arm64-v8a/libaria2c.so
new file mode 100644
index 0000000..25fe21d
Binary files /dev/null and b/android/app/src/main/jniLibs/arm64-v8a/libaria2c.so differ
diff --git a/android/app/src/main/jniLibs/armeabi-v7a/libaria2c.so b/android/app/src/main/jniLibs/armeabi-v7a/libaria2c.so
new file mode 100644
index 0000000..b3fa103
Binary files /dev/null and b/android/app/src/main/jniLibs/armeabi-v7a/libaria2c.so differ
diff --git a/android/app/src/main/jniLibs/x86/libaria2c.so b/android/app/src/main/jniLibs/x86/libaria2c.so
new file mode 100644
index 0000000..5f96e57
Binary files /dev/null and b/android/app/src/main/jniLibs/x86/libaria2c.so differ
diff --git a/android/app/src/main/jniLibs/x86_64/libaria2c.so b/android/app/src/main/jniLibs/x86_64/libaria2c.so
new file mode 100644
index 0000000..f25d50a
Binary files /dev/null and b/android/app/src/main/jniLibs/x86_64/libaria2c.so differ
diff --git a/android/app/src/main/kotlin/com/example/yolx/MainActivity.kt b/android/app/src/main/kotlin/com/example/yolx/MainActivity.kt
new file mode 100644
index 0000000..96ea081
--- /dev/null
+++ b/android/app/src/main/kotlin/com/example/yolx/MainActivity.kt
@@ -0,0 +1,51 @@
+package com.yoyo.yolx
+
+import android.content.Intent
+import android.net.Uri
+import android.os.Build
+import android.os.Environment
+import android.provider.Settings;
+import io.flutter.embedding.android.FlutterActivity
+import io.flutter.embedding.engine.FlutterEngine
+import io.flutter.plugin.common.MethodChannel
+import java.io.File
+
+class MainActivity: FlutterActivity() {
+ private val CHANNEL = "com.yoyo.flutter_native_channel/native_methods"
+ private var channelResult: MethodChannel.Result? =null;
+ override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
+ super.configureFlutterEngine(flutterEngine)
+ MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
+ channelResult=result;
+ if(call.method == "nativeLibraryDir"){
+ result.success(applicationInfo.nativeLibraryDir)
+ }else if(call.method == "requestPermission"){
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { //30
+ // 先判断有没有权限
+ if (!Environment.isExternalStorageManager()) {
+ //跳转到设置界面引导用户打开
+ val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
+ intent.data = Uri.parse("package:$packageName")
+ startActivityForResult(intent, 6666)
+ }else{
+ result.success(true)
+ }
+ }
+
+ } else {
+ result.notImplemented()
+ }
+ }
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ if (requestCode==6666){
+ if (Environment.isExternalStorageManager()){
+ channelResult?.success(true)
+ } else {
+ channelResult?.success(false);
+ }
+ }
+ }
+}
diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 0000000..f74085f
--- /dev/null
+++ b/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 0000000..304732f
--- /dev/null
+++ b/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..db77bb4
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..17987b7
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..09d4391
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..d5f1c8d
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4d6372e
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 0000000..06952be
--- /dev/null
+++ b/android/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..cb1ef88
--- /dev/null
+++ b/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/xml/network_security_config.xml b/android/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000..dca93c0
--- /dev/null
+++ b/android/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/xml/provider_paths.xml b/android/app/src/main/res/xml/provider_paths.xml
new file mode 100644
index 0000000..7825c0c
--- /dev/null
+++ b/android/app/src/main/res/xml/provider_paths.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/android/build.gradle b/android/build.gradle
new file mode 100644
index 0000000..7ea75a2
--- /dev/null
+++ b/android/build.gradle
@@ -0,0 +1,34 @@
+buildscript {
+ ext.kotlin_version = '1.9.10'
+ repositories {
+ // google()
+ // mavenCentral()
+ maven { url 'https://maven.aliyun.com/repository/google' }
+ maven { url 'https://maven.aliyun.com/repository/central' }
+ }
+
+ dependencies {
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+allprojects {
+ repositories {
+ // google()
+ // mavenCentral()
+ maven { url 'https://maven.aliyun.com/repository/google' }
+ maven { url 'https://maven.aliyun.com/repository/central' }
+ }
+}
+
+rootProject.buildDir = '../build'
+subprojects {
+ project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+ project.evaluationDependsOn(':app')
+}
+
+tasks.register("clean", Delete) {
+ delete rootProject.buildDir
+}
diff --git a/android/gradle.properties b/android/gradle.properties
new file mode 100644
index 0000000..598d13f
--- /dev/null
+++ b/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx4G
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..3c472b9
--- /dev/null
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
diff --git a/android/settings.gradle b/android/settings.gradle
new file mode 100644
index 0000000..7cd7128
--- /dev/null
+++ b/android/settings.gradle
@@ -0,0 +1,29 @@
+pluginManagement {
+ def flutterSdkPath = {
+ def properties = new Properties()
+ file("local.properties").withInputStream { properties.load(it) }
+ def flutterSdkPath = properties.getProperty("flutter.sdk")
+ assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+ return flutterSdkPath
+ }
+ settings.ext.flutterSdkPath = flutterSdkPath()
+
+ includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
+
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+
+ plugins {
+ id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
+ }
+}
+
+plugins {
+ id "dev.flutter.flutter-plugin-loader" version "1.0.0"
+ id "com.android.application" version "7.3.0" apply false
+}
+
+include ":app"
diff --git a/android/yolx_android.iml b/android/yolx_android.iml
new file mode 100644
index 0000000..1899969
--- /dev/null
+++ b/android/yolx_android.iml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/main.dart b/lib/main.dart
index ba6264d..7c92bb4 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -18,26 +18,14 @@ import 'package:system_theme/system_theme.dart';
import 'package:url_launcher/link.dart';
import 'package:window_manager/window_manager.dart';
import 'package:yolx/utils/aria2_manager.dart';
+import 'package:yolx/utils/common_utils.dart';
import 'package:yolx/utils/log.dart';
import 'theme.dart';
-/// Checks if the current environment is a desktop environment.
-bool get isDesktop {
- if (kIsWeb) return false;
- return [
- TargetPlatform.windows,
- TargetPlatform.linux,
- TargetPlatform.macOS,
- ].contains(defaultTargetPlatform);
-}
-
void main() async {
WidgetsFlutterBinding.ensureInitialized();
- if (!await FlutterSingleInstance.platform.isFirstInstance()) {
- Log.w("App is already running");
- exit(0);
- }
+
await Global.init();
if (!kIsWeb &&
[
@@ -48,6 +36,11 @@ void main() async {
}
if (isDesktop) {
+ if (!await FlutterSingleInstance.platform.isFirstInstance()) {
+ Log.w("App is already running");
+ exit(0);
+ }
+
await WindowManager.instance.ensureInitialized();
windowManager.waitUntilReadyToShow().then((_) async {
await windowManager.setTitleBarStyle(
@@ -61,7 +54,6 @@ void main() async {
await windowManager.setPreventClose(true);
await windowManager.setSkipTaskbar(false);
});
- Aria2Manager().startServer();
await trayManager.setIcon(
Platform.isWindows ? 'assets/logo.ico' : 'assets/logo.png',
);
@@ -82,6 +74,8 @@ void main() async {
);
await trayManager.setContextMenu(menu);
}
+ await Aria2Manager().initAria2Conf();
+ Aria2Manager().startServer();
runApp(
MultiProvider(
@@ -309,7 +303,7 @@ class _MyHomePageState extends State
appBar: NavigationAppBar(
automaticallyImplyLeading: false,
title: () {
- if (kIsWeb) {
+ if (!isDesktop) {
return const Align(
alignment: AlignmentDirectional.centerStart,
child: Text(appTitle),
@@ -322,8 +316,8 @@ class _MyHomePageState extends State
),
);
}(),
- actions: Row(mainAxisAlignment: MainAxisAlignment.end, children: const [
- if (!kIsWeb) WindowButtons(),
+ actions: Row(mainAxisAlignment: MainAxisAlignment.end, children: [
+ if (isDesktop) const WindowButtons(),
]),
),
paneBodyBuilder: (item, child) {
diff --git a/linux/bin/plugin/aria2/yolx_aria2.conf b/lib/resources/yolx_aria2.conf
similarity index 100%
rename from linux/bin/plugin/aria2/yolx_aria2.conf
rename to lib/resources/yolx_aria2.conf
diff --git a/lib/screens/downloading.dart b/lib/screens/downloading.dart
index 29304fc..c2f22f8 100644
--- a/lib/screens/downloading.dart
+++ b/lib/screens/downloading.dart
@@ -83,7 +83,9 @@ class _DownloadingPageState extends State with PageMixin {
assert(debugCheckHasFluentTheme(context));
var downloadList = Provider.of(context).downloadingList;
return Padding(
- padding: const EdgeInsets.all(24.0),
+ padding: EdgeInsets.all((MediaQuery.sizeOf(context).width < 640.0)
+ ? 12.0
+ : kPageDefaultVerticalPadding),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart
index c8de6ea..da2c4ea 100644
--- a/lib/screens/settings.dart
+++ b/lib/screens/settings.dart
@@ -9,6 +9,7 @@ import 'package:yolx/generated/l10n.dart';
import 'package:yolx/utils/aria2_manager.dart';
// ignore: library_prefixes
import 'package:yolx/utils/ariar2_http_utils.dart' as Aria2Http;
+import 'package:yolx/utils/common_utils.dart';
import 'package:yolx/utils/tracker_http_utils.dart';
import 'package:yolx/widgets/settings_card.dart';
import '../theme.dart';
@@ -123,6 +124,9 @@ class _SettingsState extends State with PageMixin {
context.findAncestorWidgetOfExactType()?.supportedLocales;
var currentLocale = appTheme.locale ?? Localizations.maybeLocaleOf(context);
return ScaffoldPage.scrollable(
+ padding: EdgeInsets.all((MediaQuery.sizeOf(context).width < 640.0)
+ ? 12.0
+ : kPageDefaultVerticalPadding),
header: PageHeader(title: Text(S.of(context).settings)),
children: [
Text(
@@ -197,32 +201,34 @@ class _SettingsState extends State with PageMixin {
),
),
spacer,
- SettingsCard(
- title: S.of(context).navigationMode,
- subtitle: S.of(context).setsTheDisplayModeOfTheNavigationPane,
- isExpander: true,
- content: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: List.generate(PaneDisplayMode.values.length, (index) {
- final mode = PaneDisplayMode.values[index];
- return Padding(
- padding: const EdgeInsetsDirectional.only(bottom: 8.0),
- child: RadioButton(
- checked: appTheme.displayMode == mode,
- onChanged: (value) async {
- if (value) appTheme.displayMode = mode;
+ if (isDesktop || isTablet(MediaQuery.of(context))) ...[
+ SettingsCard(
+ title: S.of(context).navigationMode,
+ subtitle: S.of(context).setsTheDisplayModeOfTheNavigationPane,
+ isExpander: true,
+ content: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: List.generate(PaneDisplayMode.values.length, (index) {
+ final mode = PaneDisplayMode.values[index];
+ return Padding(
+ padding: const EdgeInsetsDirectional.only(bottom: 8.0),
+ child: RadioButton(
+ checked: appTheme.displayMode == mode,
+ onChanged: (value) async {
+ if (value) appTheme.displayMode = mode;
- await Global.prefs.setInt('NavigationMode', mode.index);
- },
- content: Text(
- mode.toString().replaceAll('PaneDisplayMode.', ''),
+ await Global.prefs.setInt('NavigationMode', mode.index);
+ },
+ content: Text(
+ mode.toString().replaceAll('PaneDisplayMode.', ''),
+ ),
),
- ),
- );
- }),
+ );
+ }),
+ ),
),
- ),
- spacer,
+ spacer,
+ ],
SettingsCard(
title: S.of(context).navigationIndicator,
subtitle: S.of(context).setsTheStyleOfTheNavigationIndicator,
diff --git a/lib/screens/stopped.dart b/lib/screens/stopped.dart
index 2258029..13dd4d1 100644
--- a/lib/screens/stopped.dart
+++ b/lib/screens/stopped.dart
@@ -61,7 +61,9 @@ class _StoppedPageState extends State with PageMixin {
var downloadListModel = Provider.of(context);
var downloadList = downloadListModel.stoppedList;
return Padding(
- padding: const EdgeInsets.all(24.0),
+ padding: EdgeInsets.all((MediaQuery.sizeOf(context).width < 640.0)
+ ? 12.0
+ : kPageDefaultVerticalPadding),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
diff --git a/lib/screens/waiting.dart b/lib/screens/waiting.dart
index e2a7401..8b5b5bd 100644
--- a/lib/screens/waiting.dart
+++ b/lib/screens/waiting.dart
@@ -60,7 +60,9 @@ class _WaitingPageState extends State with PageMixin {
assert(debugCheckHasFluentTheme(context));
var downloadList = Provider.of(context).waitingList;
return Padding(
- padding: const EdgeInsets.all(24.0),
+ padding: EdgeInsets.all((MediaQuery.sizeOf(context).width < 640.0)
+ ? 12.0
+ : kPageDefaultVerticalPadding),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
diff --git a/lib/utils/aria2_manager.dart b/lib/utils/aria2_manager.dart
index d87dcfd..7cd652b 100644
--- a/lib/utils/aria2_manager.dart
+++ b/lib/utils/aria2_manager.dart
@@ -7,14 +7,12 @@ import 'package:yolx/common/global.dart';
import 'package:yolx/utils/common_utils.dart';
import 'package:yolx/utils/file_utils.dart';
import 'package:yolx/utils/log.dart';
+import 'package:yolx/utils/native_channel_utils.dart';
import 'ariar2_http_utils.dart' as Aria2Http;
class Aria2Manager {
late Future cmdProcess;
late int processPid = 0;
- getAria2rootPath() async {
- return await getPlugAssetsDir('aria2');
- }
getAria2ExePath() async {
if (Platform.isWindows || Platform.isLinux) {
@@ -24,15 +22,21 @@ class Aria2Manager {
ariaName = 'yolx_aria2c.exe';
}
return '$dir/$ariaName';
+ } else if (Platform.isAndroid) {
+ final libDir = await nativeLibraryDir();
+ var libPath = '$libDir/libaria2c.so';
+ File file = File(libPath);
+ if (!file.existsSync()) {
+ Log.e("aria2 not found:$libPath");
+ }
+ return libPath;
}
}
getAria2ConfPath() async {
- if (Platform.isWindows || Platform.isLinux) {
- String dir = await getPlugAssetsDir('aria2');
- String confName = 'yolx_aria2.conf';
- return '$dir${Global.pathSeparator}$confName';
- }
+ String dir = await getPlugAssetsDir('aria2');
+ String confName = 'yolx_aria2.conf';
+ return '$dir${Global.pathSeparator}$confName';
}
getAria2Session() async {
@@ -40,6 +44,12 @@ class Aria2Manager {
return '${appDocumentsCacheDirectory.path}${Global.pathSeparator}download.session';
}
+ initAria2Conf() async {
+ String confPath = await getAria2ConfPath();
+ List aria2ConfLines = await readDefAria2Conf();
+ writeLinesToFile(confPath, aria2ConfLines.join("\n"));
+ }
+
void startServer() async {
closeServer();
Global.rpcUrl = rpcURLValue.replaceAll('{port}', Global.rpcPort.toString());
@@ -110,7 +120,7 @@ class Aria2Manager {
final processResult =
Process.runSync('taskkill', ['/F', '/T', '/IM', 'yolx_aria2c.exe']);
killSuccess = processResult.exitCode == 0;
- } else if (Platform.isLinux) {
+ } else if (Platform.isLinux || Platform.isAndroid) {
final processResult = Process.runSync('killall', ['yolx_aria2c']);
killSuccess = processResult.exitCode == 0;
}
diff --git a/lib/utils/common_utils.dart b/lib/utils/common_utils.dart
index afc6c36..358f14d 100644
--- a/lib/utils/common_utils.dart
+++ b/lib/utils/common_utils.dart
@@ -1,9 +1,29 @@
import 'dart:io';
import 'dart:math';
+import 'package:fluent_ui/fluent_ui.dart';
+import 'package:flutter/foundation.dart';
import 'package:yolx/common/const.dart';
import 'package:yolx/model/download_item.dart';
+bool get isDesktop {
+ if (kIsWeb) return false;
+ return [
+ TargetPlatform.windows,
+ TargetPlatform.linux,
+ TargetPlatform.macOS,
+ ].contains(defaultTargetPlatform);
+}
+
+bool isTablet(MediaQueryData queryData) {
+ double devicePixelRatio = queryData.devicePixelRatio;
+ double screenWidth = queryData.size.shortestSide;
+
+ // 判断设备是否为平板
+ return (devicePixelRatio < 2.0 && screenWidth > 600) ||
+ (devicePixelRatio >= 2.0 && screenWidth > 960);
+}
+
permission777(filePath) {
Process.runSync('chmod', ['-R', '777', filePath]);
}
diff --git a/lib/utils/file_utils.dart b/lib/utils/file_utils.dart
index 5657134..bd14d97 100644
--- a/lib/utils/file_utils.dart
+++ b/lib/utils/file_utils.dart
@@ -1,5 +1,6 @@
import 'dart:io';
+import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
import 'package:yolx/common/global.dart';
import 'package:yolx/generated/l10n.dart';
@@ -9,6 +10,26 @@ Future getLocalFile(String filename) async {
return File('${directory.path}${Global.pathSeparator}$filename');
}
+Future> readDefAria2Conf() async {
+ String text = await rootBundle.loadString("lib/resources/yolx_aria2.conf");
+ return text.split('\n');
+}
+
+writeLinesToFile(String path, String text) {
+ File file = File(path);
+ if (!file.existsSync()) {
+ file.createSync(recursive: true);
+ }
+ file.writeAsStringSync(text, flush: true);
+}
+
+createDir(String dir) {
+ Directory directory = Directory(dir);
+ if (!directory.existsSync()) {
+ directory.create(recursive: true);
+ }
+}
+
getPlugAssetsDir(String plugName) async {
if (Platform.isWindows || Platform.isLinux) {
String plugDir =
@@ -18,6 +39,11 @@ getPlugAssetsDir(String plugName) async {
// String basename = path.basename(exePath);
pathList[pathList.length - 1] = plugDir;
return pathList.join(Global.pathSeparator);
+ } else if (Platform.isAndroid) {
+ Directory? cacheDir = await getExternalStorageDirectory();
+ String plugDir = '${cacheDir?.path}${Global.pathSeparator}$plugName';
+ createDir(plugDir);
+ return plugDir;
}
return null;
}
diff --git a/lib/utils/native_channel_utils.dart b/lib/utils/native_channel_utils.dart
new file mode 100644
index 0000000..9912115
--- /dev/null
+++ b/lib/utils/native_channel_utils.dart
@@ -0,0 +1,12 @@
+import 'package:flutter/services.dart';
+
+const MethodChannel _channel =
+ MethodChannel('com.yoyo.flutter_native_channel/native_methods');
+
+Future nativeLibraryDir() async {
+ return await _channel.invokeMethod('nativeLibraryDir');
+}
+
+requestPermission() async {
+ return await _channel.invokeMethod('requestPermission');
+}
diff --git a/lib/widgets/settings_card.dart b/lib/widgets/settings_card.dart
index 3bb2dc7..86e851f 100644
--- a/lib/widgets/settings_card.dart
+++ b/lib/widgets/settings_card.dart
@@ -1,4 +1,5 @@
import 'package:fluent_ui/fluent_ui.dart';
+import 'package:yolx/utils/common_utils.dart';
class SettingsCard extends StatelessWidget {
final String title;
@@ -26,20 +27,40 @@ class SettingsCard extends StatelessWidget {
child: Row(
children: [
const SizedBox(width: 4),
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- title,
- style: const TextStyle(
- fontWeight: FontWeight.bold,
- ),
+ if (isDesktop || isTablet(MediaQuery.of(context))) ...[
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ title,
+ style: const TextStyle(
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ Text(subtitle),
+ ],
),
- Text(subtitle),
- ],
- ),
- const Spacer(),
- content,
+ ),
+ const Spacer(),
+ content,
+ ] else ...[
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ title,
+ style: const TextStyle(
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ Text(subtitle),
+ content,
+ ],
+ ),
+ ),
+ ]
],
),
);
diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt
index 66400df..bd6a808 100644
--- a/linux/CMakeLists.txt
+++ b/linux/CMakeLists.txt
@@ -7,7 +7,7 @@ project(runner LANGUAGES CXX)
set(BINARY_NAME "yolx")
# The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
-set(APPLICATION_ID "com.example.yolx")
+set(APPLICATION_ID "com.yoyo.yolx")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
diff --git a/pubspec.yaml b/pubspec.yaml
index 99179f4..d611f3d 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -43,6 +43,7 @@ flutter:
uses-material-design: true
assets:
- assets/
+ - lib/resources/
flutter_native_splash:
color: "#000000"
diff --git a/windows/bin/plugin/aria2/yolx_aria2.conf b/windows/bin/plugin/aria2/yolx_aria2.conf
deleted file mode 100644
index 70653a0..0000000
--- a/windows/bin/plugin/aria2/yolx_aria2.conf
+++ /dev/null
@@ -1,92 +0,0 @@
-###############################
-# Yolx Windows Aria2 config file
-#
-# @see https://aria2.github.io/manual/en/html/aria2c.html
-#
-###############################
-
-
-################ RPC ################
-# Enable JSON-RPC/XML-RPC server.
-enable-rpc=true
-# Add Access-Control-Allow-Origin header field with value * to the RPC response.
-rpc-allow-origin-all=true
-# Listen incoming JSON-RPC/XML-RPC requests on all network interfaces.
-rpc-listen-all=true
-
-
-################ File system ################
-# Save a control file(*.aria2) every SEC seconds.
-auto-save-interval=10
-# Enable disk cache.
-disk-cache=64M
-# Specify file allocation method.
-file-allocation=falloc
-# No file allocation is made for files whose size is smaller than SIZE
-no-file-allocation-limit=64M
-# Save error/unfinished downloads to a file specified by --save-session option every SEC seconds.
-save-session-interval=10
-# Force save, even if the task is completed, to save information to the session file
-force-save=false
-
-################ Task ################
-# Exclude seed only downloads when counting concurrent active downloads
-bt-detach-seed-only=true
-# Verify the peer using certificates specified in --ca-certificate option.
-check-certificate=false
-# If aria2 receives "file not found" status from the remote HTTP/FTP servers NUM times
-# without getting a single byte, then force the download to fail.
-max-file-not-found=10
-# Set number of tries.
-max-tries=0
-# Set the seconds to wait between retries. When SEC > 0, aria2 will retry downloads when the HTTP server returns a 503 response.
-retry-wait=10
-# Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server. After the connection is established, this option makes no effect and --timeout option is used instead.
-connect-timeout=10
-# Set timeout in seconds.
-timeout=10
-# aria2 does not split less than 2*SIZE byte range.
-min-split-size=1M
-# Send Accept: deflate, gzip request header.
-http-accept-gzip=true
-# Retrieve timestamp of the remote file from the remote HTTP/FTP server and if it is available, apply it to the local file.
-remote-time=true
-# Set interval in seconds to output download progress summary. Setting 0 suppresses the output.
-summary-interval=0
-# Handle quoted string in Content-Disposition header as UTF-8 instead of ISO-8859-1, for example, the filename parameter, but not the extended version filename*.
-content-disposition-default-utf8=true
-
-
-################ BT Task ################
-# Enable Local Peer Discovery.
-bt-enable-lpd=true
-# Requires BitTorrent message payload encryption with arc4.
-# bt-force-encryption=true
-# If true is given, after hash check using --check-integrity option and file is complete, continue to seed file.
-bt-hash-check-seed=true
-# Specify the maximum number of peers per torrent.
-bt-max-peers=128
-# Try to download first and last pieces of each file first. This is useful for previewing files.
-bt-prioritize-piece=head
-# Removes the unselected files when download is completed in BitTorrent.
-bt-remove-unselected-file=true
-# Seed previously downloaded files without verifying piece hashes.
-bt-seed-unverified=false
-# Set the connect timeout in seconds to establish connection to tracker. After the connection is established, this option makes no effect and --bt-tracker-timeout option is used instead.
-bt-tracker-connect-timeout=10
-# Set timeout in seconds.
-bt-tracker-timeout=10
-# Set host and port as an entry point to IPv4 DHT network.
-dht-entry-point=dht.transmissionbt.com:6881
-# Set host and port as an entry point to IPv6 DHT network.
-dht-entry-point6=dht.transmissionbt.com:6881
-# Enable IPv4 DHT functionality. It also enables UDP tracker support.
-enable-dht=true
-# Enable IPv6 DHT functionality.
-enable-dht6=true
-# Enable Peer Exchange extension.
-enable-peer-exchange=true
-# Specify the string used during the bitorrent extended handshake for the peer's client version.
-peer-agent=Transmission/3.00
-# Specify the prefix of peer ID.
-peer-id-prefix=-TR3000-