├── ios
├── Runner
│ ├── Runner-Bridging-Header.h
│ ├── Assets.xcassets
│ │ ├── LaunchImage.imageset
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ ├── README.md
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ └── Info.plist
├── Flutter
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── AppFrameworkInfo.plist
├── Runner.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
├── .gitignore
├── Podfile
└── Podfile.lock
├── web
├── favicon.png
├── icons
│ ├── Icon-192.png
│ ├── Icon-512.png
│ ├── Icon-maskable-192.png
│ └── Icon-maskable-512.png
├── manifest.json
└── index.html
├── assets
├── icon
│ └── icon.png
└── readme_payloads
│ ├── 1.png
│ ├── 2.png
│ ├── 3.png
│ └── 4.png
├── lib
├── fonts
│ ├── Coda-Regular.ttf
│ ├── Coda-ExtraBold.ttf
│ └── OFL.txt
├── utils
│ ├── tools.dart
│ └── aria2_api.dart
├── components
│ ├── custom_snack_bar.dart
│ ├── speed_shower.dart
│ ├── task_list.dart
│ └── custom_drawer.dart
├── views
│ ├── global_setting.dart
│ ├── app_setting.dart
│ ├── aria2_global_option.dart
│ ├── edit_aria2_server_config.dart
│ └── task_detail.dart
├── l10n
│ ├── messages_all.dart
│ ├── messages_zh_Hans_CN.dart
│ ├── messages_messages.dart
│ └── localization_intl.dart
└── states
│ ├── aria2.dart
│ └── app.dart
├── android
├── gradle.properties
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── drawable
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable-v21
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── values
│ │ │ │ │ └── styles.xml
│ │ │ │ └── values-night
│ │ │ │ │ └── styles.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ └── aria_z
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── AndroidManifest.xml
│ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ └── profile
│ │ │ └── AndroidManifest.xml
│ └── build.gradle
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── .gitignore
├── settings.gradle
└── build.gradle
├── intl.sh
├── .metadata
├── .gitignore
├── test
└── widget_test.dart
├── analysis_options.yaml
├── README-CN.md
├── README.md
├── pubspec.yaml
└── pubspec.lock
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/web/favicon.png
--------------------------------------------------------------------------------
/assets/icon/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/assets/icon/icon.png
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/lib/fonts/Coda-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/lib/fonts/Coda-Regular.ttf
--------------------------------------------------------------------------------
/assets/readme_payloads/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/assets/readme_payloads/1.png
--------------------------------------------------------------------------------
/assets/readme_payloads/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/assets/readme_payloads/2.png
--------------------------------------------------------------------------------
/assets/readme_payloads/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/assets/readme_payloads/3.png
--------------------------------------------------------------------------------
/assets/readme_payloads/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/assets/readme_payloads/4.png
--------------------------------------------------------------------------------
/lib/fonts/Coda-ExtraBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/lib/fonts/Coda-ExtraBold.ttf
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/web/icons/Icon-maskable-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/web/icons/Icon-maskable-512.png
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengqiaozhu/aria_z/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/aria_z/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.aria_z
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/intl.sh:
--------------------------------------------------------------------------------
1 | flutter pub pub run intl_generator:extract_to_arb --output-dir=l10n-arb lib/l10n/localization_intl.dart
2 | flutter pub pub run intl_generator:generate_from_arb --output-dir=lib/l10n --no-use-deferred-loading lib/l10n/localization_intl.dart l10n-arb/intl_*.arb
3 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
7 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 18116933e77adc82f80866c928266a5b4f1ed645
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:4.1.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 9.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # Android Studio will place build artifacts here
44 | /android/app/debug
45 | /android/app/profile
46 | /android/app/release
47 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aria_z",
3 | "short_name": "aria_z",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "A new Flutter project.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | },
22 | {
23 | "src": "icons/Icon-maskable-192.png",
24 | "sizes": "192x192",
25 | "type": "image/png",
26 | "purpose": "maskable"
27 | },
28 | {
29 | "src": "icons/Icon-maskable-512.png",
30 | "sizes": "512x512",
31 | "type": "image/png",
32 | "purpose": "maskable"
33 | }
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | // import 'package:flutter/material.dart';
9 | // import 'package:flutter_test/flutter_test.dart';
10 |
11 | // import 'package:aria_z/main.dart';
12 |
13 | // void main() {
14 | // testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // // Build our app and trigger a frame.
16 | // await tester.pumpWidget(const MyApp());
17 |
18 | // // Verify that our counter starts at 0.
19 | // expect(find.text('0'), findsOneWidget);
20 | // expect(find.text('1'), findsNothing);
21 |
22 | // // Tap the '+' icon and trigger a frame.
23 | // await tester.tap(find.byIcon(Icons.add));
24 | // await tester.pump();
25 |
26 | // // Verify that our counter has incremented.
27 | // expect(find.text('0'), findsNothing);
28 | // expect(find.text('1'), findsOneWidget);
29 | // });
30 | // }
31 |
--------------------------------------------------------------------------------
/lib/utils/tools.dart:
--------------------------------------------------------------------------------
1 | class BitUnit {
2 | String bit;
3 |
4 | String unit;
5 |
6 | BitUnit(this.bit, this.unit);
7 | }
8 |
9 | BitUnit bitToUnit(int bitNum) {
10 | late BitUnit result;
11 | if (bitNum < 1024) {
12 | result = BitUnit(bitNum.toString(), '');
13 | } else if (bitNum < 1024 * 1024) {
14 | result = BitUnit((bitNum / 1024).toStringAsFixed(1), "K");
15 | } else if (bitNum < 1024 * 1024 * 1024) {
16 | result = BitUnit((bitNum / (1024 * 1024)).toStringAsFixed(1), 'M');
17 | } else if (bitNum < 1024 * 1024 * 1024 * 1024) {
18 | result = BitUnit((bitNum / (1024 * 1024 * 1024)).toStringAsFixed(1), 'G');
19 | } else {
20 | result =
21 | BitUnit((bitNum / (1024 * 1024 * 1024 * 1024)).toStringAsFixed(1), 'T');
22 | }
23 | return result;
24 | }
25 |
26 | double unitToBit(BitUnit ub) {
27 | int _u = 1;
28 | switch (ub.unit) {
29 | case 'K':
30 | _u = 1024;
31 | break;
32 | case 'M':
33 | _u = 1024 * 1024;
34 | break;
35 | case 'G':
36 | _u = 1024 * 1024 * 1024;
37 | break;
38 | case 'T':
39 | _u = 1024 * 1024 * 1024 * 1024;
40 | break;
41 | }
42 | return double.parse(ub.bit) * _u;
43 | }
44 |
45 | String formatFileSize(bitSpeed) {
46 | BitUnit bitUnit = bitToUnit(bitSpeed);
47 | return "${bitUnit.bit}${bitUnit.unit}B";
48 | }
49 |
50 | String formatSpeed(bitSpeed) => "${formatFileSize(bitSpeed)}/s";
51 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | end
36 |
37 | post_install do |installer|
38 | installer.pods_project.targets.each do |target|
39 | flutter_additional_ios_build_settings(target)
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # This file configures the analyzer, which statically analyzes Dart code to
2 | # check for errors, warnings, and lints.
3 | #
4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 | # invoked from the command line by running `flutter analyze`.
7 |
8 | # The following line activates a set of recommended lints for Flutter apps,
9 | # packages, and plugins designed to encourage good coding practices.
10 | include: package:flutter_lints/flutter.yaml
11 |
12 | linter:
13 | # The lint rules applied to this project can be customized in the
14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15 | # included above or to enable additional rules. A list of all available lints
16 | # and their documentation is published at
17 | # https://dart-lang.github.io/linter/lints/index.html.
18 | #
19 | # Instead of disabling a lint rule for the entire project in the
20 | # section below, it can also be suppressed for a single line of code
21 | # or a specific dart file by using the `// ignore: name_of_lint` and
22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file
23 | # producing the lint.
24 | rules:
25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule
26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
27 |
28 | # Additional information about this file can be found at
29 | # https://dart.dev/guides/language/analysis-options
30 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | aria_z
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/README-CN.md:
--------------------------------------------------------------------------------
1 | # AriaZ
2 |
3 |
4 |
5 |
6 |
7 | ## 跨平台Aria2客户端,支持安卓,ios平台,使用
框架编写;
8 |
9 | 
10 | [](https://github.com/fengqiaozhu/aria_z/releases)
11 | 
12 | 
13 | [](https://github.com/fengqiaozhu/aria_z/blob/master/LICENSE)
14 |
15 | 简体中文 | [English](./README.md)
16 |
17 | ## 功能截图
18 |
19 |
20 |

21 |
22 |

23 |
24 |

25 |
26 |

27 |
28 |
29 | ## 更新日志
30 | ### v0.0.1
31 | - 添加aria2服务器连接;
32 | - 添加下载任务,支持种子下载,磁力链下载,metalink下载,url(http,https,ftp,sftp等);
33 | - 自定义任务配置,包括下载目录,限速,覆盖下载;
34 | - 任务暂停,启动,删除等功能;
35 | - aria2全局配置,包括全局限速设置,默认下载地址,最多同时下载数,断点续传等;
36 | - app多语言支持
37 | - app主体色配置
38 | - aria2刷新频率配置
--------------------------------------------------------------------------------
/lib/components/custom_snack_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:aria_z/states/app.dart';
2 | import 'package:aria_z/utils/aria2_api.dart'
3 | show Aria2Client, Aria2Response, Aria2ResponseStatus;
4 | import 'package:flutter/material.dart';
5 | import 'package:provider/provider.dart';
6 |
7 | /// 底部提醒弹框
8 | /// level = 1:成功,2:失败,3:警告
9 | void showCustomSnackBar(BuildContext context, int level, Widget content,
10 | {int durationSecond = 2}) {
11 | Color bg = Colors.grey;
12 |
13 | switch (level) {
14 | case 1:
15 | bg = Colors.green;
16 | break;
17 | case 2:
18 | bg = Colors.red;
19 | break;
20 | case 3:
21 | bg = Colors.orange;
22 | break;
23 | }
24 |
25 | ScaffoldMessenger.of(context).showSnackBar(
26 | SnackBar(
27 | duration: Duration(seconds: durationSecond),
28 | content: content,
29 | backgroundColor: bg,
30 | ),
31 | );
32 | }
33 |
34 | checkAndUseConfig(BuildContext context, Aria2ConnectConfig config) async {
35 | AppState _appState = Provider.of(context, listen: false);
36 | _appState.clearCurrentServerAllState();
37 | handleAria2ApiResponse(
38 | context, await _appState.checkAria2ConnectConfig(config), (_client) {
39 | _appState.connectToAria2Server(_client);
40 | });
41 | }
42 |
43 | /// 处理 aria2 请求结果
44 | handleAria2ApiResponse(BuildContext context, Aria2Response requestResult,
45 | Function(T)? handler) {
46 | if (requestResult.status == Aria2ResponseStatus.error) {
47 | // 判断返回错误是否指定错误类型,如果未指定,责不予处理
48 | if(requestResult.error!=null){
49 | showCustomSnackBar(context, 2, Text(requestResult.message));
50 | }
51 | return;
52 | }
53 | if (handler != null) {
54 | handler(requestResult.data as T);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AriaZ
2 |
3 |
4 |
5 |
6 |
7 | ## A Cross-platform aria2 client on android or ios write with
;
8 |
9 | 
10 | [](https://github.com/fengqiaozhu/aria_z/releases)
11 | 
12 | 
13 | [](https://github.com/fengqiaozhu/aria_z/blob/master/LICENSE)
14 |
15 | English | [简体中文](./README-CN.md)
16 |
17 | ## Feature screen shot
18 |
19 |
20 |

21 |
22 |

23 |
24 |

25 |
26 |

27 |
28 |
29 | ## ChangeLog
30 | ### v0.0.1
31 | - Add new aria2 connection;
32 | - Add new download task, include torrent,magnet,metalink,url(http,https,ftp,sftp...);
33 | - Custom task option, include download path,download speed limit,overwrite;
34 | - Task pause, unparse, delete and so on;
35 | - Aria2 global option, include global speed limit, default download path, max current download number, broke-continue download ...;
36 | - App multiple language support;
37 | - App theme color;
38 | - Aria2 request delay setting;
39 | - Support android platform;
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 30
30 |
31 | compileOptions {
32 | sourceCompatibility JavaVersion.VERSION_1_8
33 | targetCompatibility JavaVersion.VERSION_1_8
34 | }
35 |
36 | kotlinOptions {
37 | jvmTarget = '1.8'
38 | }
39 |
40 | sourceSets {
41 | main.java.srcDirs += 'src/main/kotlin'
42 | }
43 |
44 | defaultConfig {
45 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
46 | applicationId "com.example.aria_z"
47 | minSdkVersion 16
48 | targetSdkVersion 30
49 | versionCode flutterVersionCode.toInteger()
50 | versionName flutterVersionName
51 | }
52 |
53 | buildTypes {
54 | release {
55 | // TODO: Add your own signing config for the release build.
56 | // Signing with the debug keys for now, so `flutter run --release` works.
57 | signingConfig signingConfigs.debug
58 | }
59 | }
60 | }
61 |
62 | flutter {
63 | source '../..'
64 | }
65 |
66 | dependencies {
67 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
68 | }
69 |
--------------------------------------------------------------------------------
/lib/views/global_setting.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: must_be_immutable
2 |
3 | import 'package:aria2/aria2.dart' show Aria2Option;
4 | import 'package:aria_z/l10n/localization_intl.dart';
5 | import 'package:aria_z/states/aria2.dart';
6 | import 'package:flutter/material.dart';
7 | import 'package:flutter/widgets.dart';
8 | import 'package:provider/provider.dart';
9 | import 'app_setting.dart';
10 | import 'aria2_global_option.dart';
11 | import '../components/custom_snack_bar.dart';
12 |
13 | class GlobalSetting extends StatelessWidget {
14 | const GlobalSetting({Key? key}) : super(key: key);
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | AriazLocalizations _l10n = AriazLocalizations.of(context);
19 | final List tabs = [
20 | Tab(text: _l10n.appSetting),
21 | Tab(text: _l10n.aria2Setting),
22 | ];
23 | Aria2Option? _globalOption = Provider.of(context).globalOption;
24 | return DefaultTabController(
25 | length: tabs.length,
26 | child: Builder(
27 | builder: (BuildContext context) {
28 | final TabController tabController =
29 | DefaultTabController.of(context)!;
30 | tabController.addListener(() {
31 | if (tabController.indexIsChanging &&
32 | tabController.index == 1 &&
33 | _globalOption == null) {
34 | tabController.index = 0;
35 | showCustomSnackBar(
36 | context, 3, Text(_l10n.aria2SettingWarning));
37 | }
38 | });
39 | return Scaffold(
40 | appBar: AppBar(
41 | title: Text(_l10n.setting),
42 | bottom: TabBar(tabs: tabs),
43 | ),
44 | body: TabBarView(
45 | physics: _globalOption == null
46 | ? const NeverScrollableScrollPhysics()
47 | : const AlwaysScrollableScrollPhysics(),
48 | children: const [
49 | AppSettingsWidgets(),
50 | Aria2GlobalOptionsWidgets()
51 | ]),
52 | );
53 | },
54 | ));
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lib/components/speed_shower.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: prefer_typing_uninitialized_variables
2 |
3 | import 'package:aria_z/utils/tools.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | class SpeedShower extends StatelessWidget {
7 | final int? downloadSpeed;
8 |
9 | final int? uploadSpeed;
10 |
11 | const SpeedShower(
12 | {Key? key, required this.downloadSpeed, required this.uploadSpeed})
13 | : super(key: key);
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return Text.rich(
18 | TextSpan(children: [
19 | downloadSpeed == null
20 | ? const WidgetSpan(child: SizedBox())
21 | : TextSpan(
22 | children: [
23 | const WidgetSpan(
24 | child: Icon(
25 | Icons.file_download_outlined,
26 | size: 18,
27 | color: Colors.green,
28 | )),
29 | TextSpan(text: formatSpeed(downloadSpeed ?? 0)),
30 | ],
31 | style: const TextStyle(
32 | fontFamily: 'Coda',
33 | fontSize: 14,
34 | )),
35 | downloadSpeed == null || uploadSpeed == null
36 | ? const WidgetSpan(child: SizedBox())
37 | : const WidgetSpan(
38 | child: SizedBox(
39 | height: 16,
40 | child: VerticalDivider(
41 | indent: 1,
42 | endIndent: 5,
43 | color: Colors.grey,
44 | thickness: 2,
45 | width: 20,
46 | ),
47 | )),
48 | uploadSpeed == null
49 | ? const WidgetSpan(child: SizedBox())
50 | : TextSpan(
51 | children: [
52 | const WidgetSpan(
53 | child: Icon(
54 | Icons.file_upload_outlined,
55 | size: 18,
56 | color: Colors.red,
57 | )),
58 | TextSpan(text: formatSpeed(uploadSpeed ?? 0)),
59 | ],
60 | style: const TextStyle(
61 | fontFamily: 'Coda',
62 | fontSize: 14,
63 | ))
64 | ]));
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
8 |
15 |
19 |
23 |
28 |
32 |
33 |
34 |
35 |
36 |
37 |
39 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/lib/l10n/messages_all.dart:
--------------------------------------------------------------------------------
1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
2 | // This is a library that looks up messages for specific locales by
3 | // delegating to the appropriate library.
4 |
5 | // Ignore issues from commonly used lints in this file.
6 | // ignore_for_file:implementation_imports, file_names
7 | // ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering
8 | // ignore_for_file:argument_type_not_assignable, invalid_assignment
9 | // ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases
10 | // ignore_for_file:comment_references
11 | // ignore_for_file:avoid_catches_without_on_clauses
12 |
13 | import 'dart:async';
14 |
15 | import 'package:intl/intl.dart';
16 | import 'package:intl/message_lookup_by_library.dart';
17 | import 'package:intl/src/intl_helpers.dart';
18 |
19 | import 'messages_messages.dart' as messages_messages;
20 | import 'messages_zh_Hans_CN.dart' as messages_zh_hans_cn;
21 |
22 | typedef Future LibraryLoader();
23 | Map _deferredLibraries = {
24 | 'messages': () => Future.value(null),
25 | 'zh_Hans_CN': () => Future.value(null),
26 | };
27 |
28 | MessageLookupByLibrary? _findExact(String localeName) {
29 | switch (localeName) {
30 | case 'messages':
31 | return messages_messages.messages;
32 | case 'zh_Hans_CN':
33 | return messages_zh_hans_cn.messages;
34 | default:
35 | return null;
36 | }
37 | }
38 |
39 | /// User programs should call this before using [localeName] for messages.
40 | Future initializeMessages(String localeName) async {
41 | final availableLocale = Intl.verifiedLocale(
42 | localeName,
43 | (locale) => _deferredLibraries[locale] != null,
44 | onFailure: (_) => null);
45 | if (availableLocale == null) {
46 | return Future.value(false);
47 | }
48 | final lib = _deferredLibraries[availableLocale];
49 | await (lib == null ? Future.value(false) : lib());
50 | initializeInternalMessageLookup(() => CompositeMessageLookup());
51 | messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor);
52 | return Future.value(true);
53 | }
54 |
55 | bool _messagesExistFor(String locale) {
56 | try {
57 | return _findExact(locale) != null;
58 | } catch (e) {
59 | return false;
60 | }
61 | }
62 |
63 | MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) {
64 | final actualLocale = Intl.verifiedLocale(locale, _messagesExistFor,
65 | onFailure: (_) => null);
66 | if (actualLocale == null) return null;
67 | return _findExact(actualLocale);
68 | }
69 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - DKImagePickerController/Core (4.3.2):
3 | - DKImagePickerController/ImageDataManager
4 | - DKImagePickerController/Resource
5 | - DKImagePickerController/ImageDataManager (4.3.2)
6 | - DKImagePickerController/PhotoGallery (4.3.2):
7 | - DKImagePickerController/Core
8 | - DKPhotoGallery
9 | - DKImagePickerController/Resource (4.3.2)
10 | - DKPhotoGallery (0.0.17):
11 | - DKPhotoGallery/Core (= 0.0.17)
12 | - DKPhotoGallery/Model (= 0.0.17)
13 | - DKPhotoGallery/Preview (= 0.0.17)
14 | - DKPhotoGallery/Resource (= 0.0.17)
15 | - SDWebImage
16 | - SwiftyGif
17 | - DKPhotoGallery/Core (0.0.17):
18 | - DKPhotoGallery/Model
19 | - DKPhotoGallery/Preview
20 | - SDWebImage
21 | - SwiftyGif
22 | - DKPhotoGallery/Model (0.0.17):
23 | - SDWebImage
24 | - SwiftyGif
25 | - DKPhotoGallery/Preview (0.0.17):
26 | - DKPhotoGallery/Model
27 | - DKPhotoGallery/Resource
28 | - SDWebImage
29 | - SwiftyGif
30 | - DKPhotoGallery/Resource (0.0.17):
31 | - SDWebImage
32 | - SwiftyGif
33 | - file_picker (0.0.1):
34 | - DKImagePickerController/PhotoGallery
35 | - Flutter
36 | - Flutter (1.0.0)
37 | - path_provider_ios (0.0.1):
38 | - Flutter
39 | - SDWebImage (5.12.1):
40 | - SDWebImage/Core (= 5.12.1)
41 | - SDWebImage/Core (5.12.1)
42 | - shared_preferences_ios (0.0.1):
43 | - Flutter
44 | - SwiftyGif (5.4.0)
45 |
46 | DEPENDENCIES:
47 | - file_picker (from `.symlinks/plugins/file_picker/ios`)
48 | - Flutter (from `Flutter`)
49 | - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
50 | - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
51 |
52 | SPEC REPOS:
53 | trunk:
54 | - DKImagePickerController
55 | - DKPhotoGallery
56 | - SDWebImage
57 | - SwiftyGif
58 |
59 | EXTERNAL SOURCES:
60 | file_picker:
61 | :path: ".symlinks/plugins/file_picker/ios"
62 | Flutter:
63 | :path: Flutter
64 | path_provider_ios:
65 | :path: ".symlinks/plugins/path_provider_ios/ios"
66 | shared_preferences_ios:
67 | :path: ".symlinks/plugins/shared_preferences_ios/ios"
68 |
69 | SPEC CHECKSUMS:
70 | DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d
71 | DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
72 | file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
73 | Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
74 | path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5
75 | SDWebImage: 4dc3e42d9ec0c1028b960a33ac6b637bb432207b
76 | shared_preferences_ios: aef470a42dc4675a1cdd50e3158b42e3d1232b32
77 | SwiftyGif: 5d4af95df24caf1c570dbbcb32a3b8a0763bc6d7
78 |
79 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
80 |
81 | COCOAPODS: 1.11.2
82 |
--------------------------------------------------------------------------------
/lib/states/aria2.dart:
--------------------------------------------------------------------------------
1 | import 'package:aria2/aria2.dart';
2 | import 'package:flutter/widgets.dart';
3 |
4 | enum TaskType { torrent, magnet, url, metaLink }
5 |
6 | class NewTaskOption {
7 | List params;
8 |
9 | TaskType taskType;
10 |
11 | Aria2Option option;
12 |
13 | NewTaskOption(this.taskType, this.params, this.option);
14 | }
15 |
16 | class Aria2States extends ChangeNotifier {
17 | List completedTasks = [];
18 |
19 | List downloadingTasks = [];
20 |
21 | List waittingTasks = [];
22 |
23 | Aria2GlobalStat? globalStatus;
24 |
25 | Aria2Option? globalOption;
26 |
27 | Aria2Version? versionInfo;
28 |
29 | final List _opratingGids = [];
30 |
31 | Aria2States();
32 |
33 | List get taskListOfNotComplete {
34 | List list = [...downloadingTasks, ...waittingTasks];
35 | list = list.map((t) {
36 | if (_opratingGids.contains(t.gid)) {
37 | switch (t.status) {
38 | case 'active':
39 | t.status = 'pausing';
40 | break;
41 | case 'paused':
42 | t.status = 'unparsing';
43 | break;
44 | }
45 | }
46 | return t;
47 | }).toList();
48 | return list;
49 | }
50 |
51 | List get opratingGids => _opratingGids;
52 |
53 | updateDownloadingTasks(List taskList) {
54 | downloadingTasks = taskList;
55 | notifyListeners();
56 | }
57 |
58 | updateWaittingTasks(List taskList) {
59 | waittingTasks = taskList;
60 | notifyListeners();
61 | }
62 |
63 | updateCompletedTasks(List taskList) {
64 | completedTasks = taskList;
65 | notifyListeners();
66 | }
67 |
68 | removeCompletedTaskFromLocalList(String gid) {
69 | completedTasks.removeWhere((element) => element.gid == gid);
70 | }
71 |
72 | updateGlobalStatus(Aria2GlobalStat stat) {
73 | globalStatus = stat;
74 | notifyListeners();
75 | }
76 |
77 | addOpratingGids(List gids) {
78 | for (var gid in gids) {
79 | if (!(_opratingGids.contains(gid))) {
80 | _opratingGids.add(gid);
81 | }
82 | }
83 | notifyListeners();
84 | }
85 |
86 | removeOpratingGids(List gids) {
87 | for (var gid in gids) {
88 | if (_opratingGids.contains(gid)) {
89 | _opratingGids.remove(gid);
90 | }
91 | }
92 | notifyListeners();
93 | }
94 |
95 | updateGlobalOption(Aria2Option options) {
96 | globalOption = options;
97 | notifyListeners();
98 | }
99 |
100 | updateVersion(version) {
101 | versionInfo = version;
102 | notifyListeners();
103 | }
104 |
105 | clearStates() {
106 | completedTasks = [];
107 | downloadingTasks = [];
108 | waittingTasks = [];
109 | globalStatus = null;
110 | globalOption = null;
111 | versionInfo = null;
112 | _opratingGids.removeRange(0, _opratingGids.length);
113 | notifyListeners();
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | aria_z
30 |
31 |
32 |
33 |
36 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: aria_z
2 | description: A new Flutter project.
3 |
4 | # The following line prevents the package from being accidentally published to
5 | # pub.dev using `flutter pub publish`. This is preferred for private packages.
6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev
7 |
8 | # The following defines the version and build number for your application.
9 | # A version number is three numbers separated by dots, like 1.2.43
10 | # followed by an optional build number separated by a +.
11 | # Both the version and the builder number may be overridden in flutter
12 | # build by specifying --build-name and --build-number, respectively.
13 | # In Android, build-name is used as versionName while build-number used as versionCode.
14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
16 | # Read more about iOS versioning at
17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
18 | version: 0.0.1
19 |
20 | environment:
21 | sdk: ">=2.12.0 <3.0.0"
22 |
23 | # Dependencies specify other packages that your package needs in order to work.
24 | # To automatically upgrade your package dependencies to the latest versions
25 | # consider running `flutter pub upgrade --major-versions`. Alternatively,
26 | # dependencies can be manually updated by changing the version numbers below to
27 | # the latest version available on pub.dev. To see which dependencies have newer
28 | # versions available, run `flutter pub outdated`.
29 | dependencies:
30 | flutter:
31 | sdk: flutter
32 | flutter_localizations:
33 | sdk: flutter
34 |
35 | # The following adds the Cupertino Icons font to your application.
36 | # Use with the CupertinoIcons class for iOS style icons.
37 | cupertino_icons: ^1.0.2
38 | provider: ^6.0.1
39 | hive: ^2.0.4
40 | hive_flutter: ^1.1.0
41 | tuple: ^2.0.0
42 | toggle_switch: ^1.3.0
43 | file_picker: ^4.2.4
44 | shared_preferences: ^2.0.9
45 | intl: ^0.17.0
46 | flutter_slidable: ^1.1.0
47 | flutter_spinkit: ^5.1.0
48 | aria2: ^0.1.3
49 |
50 | dev_dependencies:
51 | flutter_test:
52 | sdk: flutter
53 |
54 | # The "flutter_lints" package below contains a set of recommended lints to
55 | # encourage good coding practices. The lint set provided by the package is
56 | # activated in the `analysis_options.yaml` file located at the root of your
57 | # package. See that file for information about deactivating specific lint
58 | # rules and activating additional ones.
59 | flutter_lints: ^1.0.0
60 | intl_generator: ^0.2.1
61 | flutter_launcher_icons: "^0.9.2"
62 | # For information on the generic Dart part of this file, see the
63 | # following page: https://dart.dev/tools/pub/pubspec
64 |
65 | # The following section is specific to Flutter.
66 | flutter:
67 |
68 | # The following line ensures that the Material Icons font is
69 | # included with your application, so that you can use the icons in
70 | # the material Icons class.
71 | uses-material-design: true
72 |
73 | # To add assets to your application, add an assets section, like this:
74 | # assets:
75 | # - images/a_dot_burr.jpeg
76 | # - images/a_dot_ham.jpeg
77 |
78 | # An image asset can refer to one or more resolution-specific "variants", see
79 | # https://flutter.dev/assets-and-images/#resolution-aware.
80 |
81 | # For details regarding adding assets from package dependencies, see
82 | # https://flutter.dev/assets-and-images/#from-packages
83 |
84 | # To add custom fonts to your application, add a fonts section here,
85 | # in this "flutter" section. Each entry in this list should have a
86 | # "family" key with the font family name, and a "fonts" key with a
87 | # list giving the asset and other descriptors for the font. For
88 | # example:
89 | fonts:
90 | - family: Coda
91 | fonts:
92 | - asset: lib/fonts/Coda-Regular.ttf
93 | - asset: lib/fonts/Coda-ExtraBold.ttf
94 | weight: 800
95 | # - family: Trajan Pro
96 | # fonts:
97 | # - asset: fonts/TrajanPro.ttf
98 | # - asset: fonts/TrajanPro_Bold.ttf
99 | # weight: 700
100 | #
101 | # For details regarding fonts from package dependencies,
102 | # see https://flutter.dev/custom-fonts/#from-packages
103 |
104 |
105 | flutter_icons:
106 | android: true
107 | ios: true
108 | image_path: "assets/icon/icon.png"
109 | remove_alpha_ios: true
--------------------------------------------------------------------------------
/lib/fonts/OFL.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010, 2011 Vernon Adams (vern@newtypography.co.uk),
2 | with Reserved Font Name "Coda" and "Coda Caption".
3 |
4 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
5 | This license is copied below, and is also available with a FAQ at:
6 | http://scripts.sil.org/OFL
7 |
8 |
9 | -----------------------------------------------------------
10 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
11 | -----------------------------------------------------------
12 |
13 | PREAMBLE
14 | The goals of the Open Font License (OFL) are to stimulate worldwide
15 | development of collaborative font projects, to support the font creation
16 | efforts of academic and linguistic communities, and to provide a free and
17 | open framework in which fonts may be shared and improved in partnership
18 | with others.
19 |
20 | The OFL allows the licensed fonts to be used, studied, modified and
21 | redistributed freely as long as they are not sold by themselves. The
22 | fonts, including any derivative works, can be bundled, embedded,
23 | redistributed and/or sold with any software provided that any reserved
24 | names are not used by derivative works. The fonts and derivatives,
25 | however, cannot be released under any other type of license. The
26 | requirement for fonts to remain under this license does not apply
27 | to any document created using the fonts or their derivatives.
28 |
29 | DEFINITIONS
30 | "Font Software" refers to the set of files released by the Copyright
31 | Holder(s) under this license and clearly marked as such. This may
32 | include source files, build scripts and documentation.
33 |
34 | "Reserved Font Name" refers to any names specified as such after the
35 | copyright statement(s).
36 |
37 | "Original Version" refers to the collection of Font Software components as
38 | distributed by the Copyright Holder(s).
39 |
40 | "Modified Version" refers to any derivative made by adding to, deleting,
41 | or substituting -- in part or in whole -- any of the components of the
42 | Original Version, by changing formats or by porting the Font Software to a
43 | new environment.
44 |
45 | "Author" refers to any designer, engineer, programmer, technical
46 | writer or other person who contributed to the Font Software.
47 |
48 | PERMISSION & CONDITIONS
49 | Permission is hereby granted, free of charge, to any person obtaining
50 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
51 | redistribute, and sell modified and unmodified copies of the Font
52 | Software, subject to the following conditions:
53 |
54 | 1) Neither the Font Software nor any of its individual components,
55 | in Original or Modified Versions, may be sold by itself.
56 |
57 | 2) Original or Modified Versions of the Font Software may be bundled,
58 | redistributed and/or sold with any software, provided that each copy
59 | contains the above copyright notice and this license. These can be
60 | included either as stand-alone text files, human-readable headers or
61 | in the appropriate machine-readable metadata fields within text or
62 | binary files as long as those fields can be easily viewed by the user.
63 |
64 | 3) No Modified Version of the Font Software may use the Reserved Font
65 | Name(s) unless explicit written permission is granted by the corresponding
66 | Copyright Holder. This restriction only applies to the primary font name as
67 | presented to the users.
68 |
69 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
70 | Software shall not be used to promote, endorse or advertise any
71 | Modified Version, except to acknowledge the contribution(s) of the
72 | Copyright Holder(s) and the Author(s) or with their explicit written
73 | permission.
74 |
75 | 5) The Font Software, modified or unmodified, in part or in whole,
76 | must be distributed entirely under this license, and must not be
77 | distributed under any other license. The requirement for fonts to
78 | remain under this license does not apply to any document created
79 | using the Font Software.
80 |
81 | TERMINATION
82 | This license becomes null and void if any of the above conditions are
83 | not met.
84 |
85 | DISCLAIMER
86 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
87 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
88 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
89 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
90 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
91 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
92 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
93 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
94 | OTHER DEALINGS IN THE FONT SOFTWARE.
95 |
--------------------------------------------------------------------------------
/lib/components/task_list.dart:
--------------------------------------------------------------------------------
1 | import 'package:aria2/models/aria2Task.dart';
2 | import 'package:aria_z/components/custom_snack_bar.dart';
3 | import 'package:aria_z/components/speed_shower.dart';
4 | import 'package:aria_z/l10n/localization_intl.dart';
5 | import 'package:flutter/material.dart';
6 | import 'package:flutter_slidable/flutter_slidable.dart';
7 |
8 | import '../states/app.dart' show AppState;
9 | import '../states/aria2.dart' show Aria2States, TaskType;
10 | import '../utils/tools.dart';
11 |
12 | List taskListTileWidget(BuildContext context, AppState app,
13 | Aria2States aria2States, List taskList) {
14 | AriazLocalizations _l10n = AriazLocalizations.of(context);
15 | Widget trailingOption(String gid, String status) {
16 | late Widget w = Text(status);
17 | switch (status) {
18 | case 'active':
19 | w = IconButton(
20 | color: Colors.redAccent,
21 | icon: const Icon(Icons.pause),
22 | onPressed: () async {
23 | if (gid != "") {
24 | await app.aria2?.pauseTask(gid);
25 | }
26 | });
27 | break;
28 | case 'paused':
29 | w = IconButton(
30 | color: Colors.lightGreen,
31 | icon: const Icon(Icons.play_arrow),
32 | onPressed: () async {
33 | if (gid != "") {
34 | await app.aria2?.unPauseTask(gid);
35 | }
36 | },
37 | );
38 | break;
39 | case 'waiting':
40 | w = Text(_l10n.waiting);
41 | break;
42 | case 'pausing':
43 | w = Text(_l10n.pausing);
44 | break;
45 | case 'unparsing':
46 | w = Text(_l10n.unparsing);
47 | break;
48 | case 'complete':
49 | w = Text(_l10n.complete);
50 | break;
51 | }
52 | return w;
53 | }
54 |
55 | return taskList
56 | // .where((element) => element.bittorrent?["info"] != null)
57 | .map((task) {
58 | late TaskType _taskType;
59 | late String _taskName;
60 |
61 | if (task.bittorrent == null) {
62 | String uri = task.files?[0]['uris'][0]['uri'] as String;
63 | _taskType = TaskType.url;
64 | _taskName = uri.split('/').last;
65 | } else if (task.bittorrent != null) {
66 | if (task.bittorrent!.containsKey('info')) {
67 | _taskType = TaskType.torrent;
68 | _taskName = task.bittorrent?["info"]["name"] ?? '';
69 | } else {
70 | _taskType = TaskType.magnet;
71 | _taskName = '[METADATA]${task.infoHash}';
72 | }
73 | } else {
74 | _taskType = TaskType.metaLink;
75 | _taskName = '==========metaLink============';
76 | }
77 |
78 | return Padding(
79 | padding: const EdgeInsets.all(10.0),
80 | child: Card(
81 | child: Column(
82 | mainAxisSize: MainAxisSize.min,
83 | children: [
84 | Slidable(
85 | startActionPane: ActionPane(
86 | motion: const ScrollMotion(),
87 | children: [
88 | SlidableAction(
89 | onPressed: (BuildContext context) async {
90 | handleAria2ApiResponse(
91 | context,
92 | await app.aria2!
93 | .removeTask(task.gid!, task.status!), (res) {
94 | if (res == 'OK') {
95 | aria2States
96 | .removeCompletedTaskFromLocalList(task.gid!);
97 | }
98 | // showCustomSnackBar(context, 1, Text(res));
99 | });
100 | },
101 | backgroundColor: const Color(0xFFFE4A49),
102 | foregroundColor: Colors.white,
103 | icon: Icons.delete,
104 | label: _l10n.deleteText,
105 | ),
106 | ],
107 | ),
108 | child: ListTile(
109 | onTap: () async {
110 | var gid = task.gid!;
111 | Navigator.of(context).pushNamed('/task_detail',
112 | arguments: [gid, _taskName, _taskType]);
113 | },
114 | leading: Icon(app.aria2TaskTypes
115 | .where((att) => att.taskType == _taskType)
116 | .first
117 | .icon),
118 | title: Text(
119 | _taskName,
120 | overflow: TextOverflow.ellipsis,
121 | maxLines: 2,
122 | // softWrap: false,
123 | ),
124 | trailing:
125 | trailingOption(task.gid ?? '', task.status ?? ''))),
126 | Padding(
127 | padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
128 | child: Flex(
129 | direction: Axis.horizontal,
130 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
131 | children: [
132 | Expanded(
133 | child: Text(
134 | "${formatFileSize(task.completedLength ?? 0)} / ${formatFileSize(task.totalLength ?? 0)}",
135 | style: TextStyle(
136 | color: Theme.of(context).colorScheme.onSurface,
137 | fontSize: 14,
138 | fontFamily: 'Coda'),
139 | )),
140 | Expanded(
141 | flex: 1,
142 | child: Container(
143 | alignment: Alignment.centerRight,
144 | child: task.status == 'paused'
145 | ? Text(_l10n.paused)
146 | : DefaultTextStyle(
147 | textAlign: TextAlign.end,
148 | style: TextStyle(
149 | color: Theme.of(context)
150 | .colorScheme
151 | .onSurface,
152 | fontSize: 14,
153 | fontFamily: 'Coda'),
154 | child: SpeedShower(
155 | downloadSpeed: task.downloadSpeed,
156 | uploadSpeed: _taskType != TaskType.torrent
157 | ? null
158 | : task.uploadSpeed)),
159 | ))
160 | ],
161 | )),
162 | LinearProgressIndicator(
163 | value: (task.completedLength ?? 0) /
164 | (task.totalLength == 0 ? 1 : task.totalLength ?? 1)),
165 | ],
166 | ),
167 | ),
168 | );
169 | }).toList();
170 | }
171 |
--------------------------------------------------------------------------------
/lib/views/app_setting.dart:
--------------------------------------------------------------------------------
1 | import 'package:aria_z/l10n/localization_intl.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:provider/provider.dart';
4 | import '../states/app.dart';
5 |
6 | GlobalKey _globalOptionKey = GlobalKey();
7 |
8 | class AppSettingsWidgets extends StatefulWidget {
9 | const AppSettingsWidgets({Key? key}) : super(key: key);
10 |
11 | @override
12 | State createState() => _AppSettingsStates();
13 | }
14 |
15 | class _AppSettingsStates extends State
16 | with AutomaticKeepAliveClientMixin {
17 | late String language;
18 |
19 | @override
20 | void initState() {
21 | super.initState();
22 | language = '简体中文';
23 | }
24 |
25 | Widget _settingGroupWidget(List innerWidgets) {
26 | return Container(
27 | width: double.infinity,
28 | decoration: BoxDecoration(
29 | color: Colors.grey.withOpacity(0.2),
30 | borderRadius: const BorderRadius.all(Radius.circular(12)),
31 | ),
32 | child: Padding(
33 | padding: const EdgeInsets.fromLTRB(10, 12, 10, 12),
34 | child: Column(children: innerWidgets),
35 | ));
36 | }
37 |
38 | @override
39 | Widget build(BuildContext context) {
40 | super.build(context);
41 | AriazLocalizations _l10n = AriazLocalizations.of(context);
42 | TextStyle _labelTextStyle =
43 | const TextStyle(fontSize: 17, fontWeight: FontWeight.bold);
44 | AppState appState = Provider.of(context);
45 | return Form(
46 | key: _globalOptionKey,
47 | autovalidateMode: AutovalidateMode.onUserInteraction,
48 | child: Padding(
49 | padding: const EdgeInsets.fromLTRB(10, 20, 10, 20),
50 | child: Column(
51 | children: [
52 | _settingGroupWidget([
53 | Flex(
54 | direction: Axis.horizontal,
55 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
56 | children: [
57 | Expanded(
58 | flex: 1,
59 | child: Text(
60 | _l10n.language,
61 | style: _labelTextStyle,
62 | ),
63 | ),
64 | Expanded(
65 | flex: 3,
66 | child: DropdownButtonHideUnderline(
67 | child: DropdownButton(
68 | isExpanded: true,
69 | value: appState.selectedLocale?.toLanguageTag(),
70 | borderRadius:
71 | const BorderRadius.all(Radius.circular(8)),
72 | onChanged: (String? newValue) {
73 | appState.changeLocale(newValue ?? '');
74 | },
75 | items: appState.localeItems
76 | .map>((LocaleItem lc) {
77 | return DropdownMenuItem(
78 | value: lc.locale?.toLanguageTag(),
79 | child: Text(lc.label),
80 | );
81 | }).toList(),
82 | ),
83 | ),
84 | )
85 | ]),
86 | Flex(
87 | direction: Axis.horizontal,
88 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
89 | children: [
90 | Expanded(
91 | flex: 1,
92 | child: Text(_l10n.themeColor, style: _labelTextStyle),
93 | ),
94 | Expanded(
95 | flex: 3,
96 | child: DropdownButtonHideUnderline(
97 | child: DropdownButton(
98 | isExpanded: true,
99 | value: appState.appUsingColorName,
100 | borderRadius:
101 | const BorderRadius.all(Radius.circular(8)),
102 | onChanged: (String? newValue) {
103 | setState(() {
104 | appState.changeTheme(appState.appThemeColors
105 | .where((_th) => _th.name == newValue)
106 | .first
107 | .name);
108 | });
109 | },
110 | items: appState.appThemeColors
111 | .map>(
112 | (CustomMateriaColor _theme) {
113 | return DropdownMenuItem(
114 | value: _theme.name,
115 | child: Row(
116 | children: [
117 | Text(_theme.desc),
118 | const SizedBox(width: 8),
119 | Container(
120 | width: 80,
121 | height: 16,
122 | decoration: BoxDecoration(
123 | color: _theme.color,
124 | borderRadius: const BorderRadius.all(
125 | Radius.circular(5))),
126 | )
127 | ],
128 | ),
129 | );
130 | }).toList(),
131 | ),
132 | ),
133 | )
134 | ])
135 | ]),
136 | const SizedBox(
137 | height: 10,
138 | ),
139 | _settingGroupWidget([
140 | Flex(
141 | direction: Axis.horizontal,
142 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
143 | children: [
144 | Expanded(
145 | flex: 1,
146 | child: Text(_l10n.refreshDelay, style: _labelTextStyle),
147 | ),
148 | Expanded(
149 | flex: 3,
150 | child: DropdownButtonHideUnderline(
151 | child: DropdownButton(
152 | borderRadius:
153 | const BorderRadius.all(Radius.circular(8)),
154 | isExpanded: true,
155 | value: appState.intervalSecond.toString(),
156 | onChanged: (String? newValue) {
157 | if (newValue != null) {
158 | appState.updateIntervalSecond(newValue);
159 | }
160 | },
161 | items: ['1', '3', '5', '10', '15']
162 | .map>((String value) {
163 | return DropdownMenuItem(
164 | value: value,
165 | child: Text('$value ${_l10n.second}'),
166 | );
167 | }).toList(),
168 | ),
169 | ),
170 | )
171 | ],
172 | )
173 | ])
174 | ],
175 | ),
176 | ));
177 | }
178 |
179 | @override
180 | bool get wantKeepAlive => true;
181 | }
182 |
--------------------------------------------------------------------------------
/lib/views/aria2_global_option.dart:
--------------------------------------------------------------------------------
1 | import 'package:aria2/models/index.dart';
2 | import 'package:aria_z/components/custom_snack_bar.dart';
3 | import 'package:aria_z/l10n/localization_intl.dart';
4 | import 'package:aria_z/states/app.dart';
5 | import 'package:aria_z/states/aria2.dart';
6 | import 'package:flutter/material.dart';
7 | import 'package:provider/provider.dart';
8 |
9 | class Aria2GlobalOptionsWidgets extends StatefulWidget {
10 | const Aria2GlobalOptionsWidgets({Key? key}) : super(key: key);
11 |
12 | @override
13 | State createState() => _Aria2GlobalOptionsStates();
14 | }
15 |
16 | class _Aria2GlobalOptionsStates extends State
17 | with AutomaticKeepAliveClientMixin {
18 | static Aria2Option _newOption = Aria2Option();
19 |
20 | late bool _optionChanged;
21 | late AriazLocalizations _l10n;
22 |
23 | _checkOptionChange(Map _ooMap) {
24 | Map _noMap = _newOption.toJson();
25 | List _toRemoveKeys = [];
26 | for (var _k in _noMap.keys) {
27 | if (_ooMap.containsKey(_k) && _noMap[_k] != _ooMap[_k]) {
28 | setState(() {
29 | _optionChanged = true;
30 | });
31 | } else {
32 | _toRemoveKeys.add(_k);
33 | }
34 | }
35 | for (String _k in _toRemoveKeys) {
36 | _noMap.remove(_k);
37 | }
38 | if (_noMap.keys.isEmpty) {
39 | _optionChanged = false;
40 | }
41 | _newOption = Aria2Option.fromJson(_noMap);
42 | }
43 |
44 | _submitOptionChange() async {
45 | handleAria2ApiResponse(
46 | context,
47 | await Provider.of(context, listen: false)
48 | .aria2!
49 | .updateTheGlobalOption(_newOption), (res) async {
50 | handleAria2ApiResponse(
51 | context,
52 | await Provider.of(context, listen: false)
53 | .aria2!
54 | .getAria2GlobalOption(),
55 | null);
56 | showCustomSnackBar(context, 1, Text(_l10n.changeGlobalOptionSuccessTip));
57 | });
58 |
59 | _optionChanged = false;
60 | _newOption = Aria2Option();
61 | }
62 |
63 | @override
64 | void initState() {
65 | super.initState();
66 | _optionChanged = false;
67 | }
68 |
69 | @override
70 | Widget build(BuildContext context) {
71 | super.build(context);
72 |
73 | _l10n = AriazLocalizations.of(context);
74 | Aria2Option _oldOption = Provider.of(context).globalOption!;
75 |
76 | return Stack(
77 | children: [
78 | !_optionChanged
79 | ? const SizedBox()
80 | : Card(
81 | child: Padding(
82 | padding: const EdgeInsets.fromLTRB(8, 0, 6, 0),
83 | child: Row(
84 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
85 | children: [
86 | Text(_l10n.optionChangedTip),
87 | TextButton.icon(
88 | onPressed: _submitOptionChange,
89 | icon: const Icon(Icons.send),
90 | label: Text(_l10n.submit)),
91 | ],
92 | ),
93 | )),
94 | Form(
95 | autovalidateMode: AutovalidateMode.onUserInteraction,
96 | child: Padding(
97 | padding:
98 | EdgeInsets.fromLTRB(10, _optionChanged ? 70 : 20, 10, 20),
99 | child: ListView(
100 | children: [
101 | TextFormField(
102 | initialValue: _oldOption.dir,
103 | onChanged: (v) {
104 | _newOption.dir = v.trim();
105 | _checkOptionChange(_oldOption.toJson());
106 | },
107 | validator: (v) => v == null || v.isEmpty
108 | ? _l10n.dirInputValidatorText
109 | : null,
110 | decoration: InputDecoration(
111 | border: const OutlineInputBorder(),
112 | labelText: _l10n.dirInputLabel,
113 | contentPadding: const EdgeInsets.all(8)),
114 | ),
115 | const SizedBox(height: 10),
116 | TextFormField(
117 | initialValue: _oldOption.maxConcurrentDownloads?.toString(),
118 | onChanged: (v) {
119 | _newOption.maxConcurrentDownloads = int.parse(v.trim());
120 | _checkOptionChange(_oldOption.toJson());
121 | },
122 | validator: (v) {
123 | v = v ?? '';
124 | if (v.isEmpty) {
125 | return _l10n.maxCurrentDownloadValidator_1;
126 | }
127 | if (v.length > 1 && v.startsWith('0')) {
128 | return _l10n.maxCurrentDownloadValidator_2;
129 | }
130 |
131 | if (int.tryParse(v) == null) {
132 | return _l10n.maxCurrentDownloadValidator_3;
133 | }
134 |
135 | if (int.parse(v) < 0) {
136 | return _l10n.maxCurrentDownloadValidator_4;
137 | }
138 | },
139 | decoration: InputDecoration(
140 | border: const OutlineInputBorder(),
141 | labelText: _l10n.maxCurrentDownload4,
142 | contentPadding: const EdgeInsets.all(8)),
143 | ),
144 | const SizedBox(height: 10),
145 | SwitchListTile(
146 | contentPadding: EdgeInsets.zero,
147 | title: Text(_l10n.ariaContinue),
148 | value: _newOption.continue_ == null
149 | ? _oldOption.continue_!
150 | : _newOption.continue_!,
151 | onChanged: (newVal) {
152 | setState(() {
153 | _newOption.continue_ = newVal;
154 | _checkOptionChange(_oldOption.toJson());
155 | });
156 | }),
157 | const SizedBox(height: 10),
158 | SwitchListTile(
159 | contentPadding: EdgeInsets.zero,
160 | title: Text(_l10n.checkIntegrity),
161 | value: _newOption.checkIntegrity == null
162 | ? _oldOption.checkIntegrity!
163 | : _newOption.checkIntegrity!,
164 | onChanged: (newVal) {
165 | setState(() {
166 | _newOption.checkIntegrity = newVal;
167 | _checkOptionChange(_oldOption.toJson());
168 | });
169 | }),
170 | const SizedBox(height: 10),
171 | SwitchListTile(
172 | contentPadding: EdgeInsets.zero,
173 | title: Text(_l10n.optimizeConcurrentDownloads),
174 | value: _newOption.optimizeConcurrentDownloads == null
175 | ? _oldOption.optimizeConcurrentDownloads!
176 | : _newOption.optimizeConcurrentDownloads!,
177 | onChanged: (newVal) {
178 | setState(() {
179 | _newOption.optimizeConcurrentDownloads = newVal;
180 | _checkOptionChange(_oldOption.toJson());
181 | });
182 | }),
183 | ],
184 | ),
185 | ))
186 | ],
187 | );
188 | }
189 |
190 | @override
191 | bool get wantKeepAlive => true;
192 | }
193 |
194 |
195 | // dir 默认下载地址
196 |
197 | // max-concurrent-downloads 最大同时下载任务数量
198 |
199 | // max-overall-download-limit 下载速度上限
200 |
201 | // max-overall-upload-limit 上传速度上限
202 |
203 | // continue 断点续传
204 |
205 | // check-integrity 检查完整性
206 |
207 | // optimize-concurrent-downloads 优化并行下载
208 |
209 | // log 日志文件下载地址
210 |
211 | // log-level 日志等级
212 |
--------------------------------------------------------------------------------
/lib/states/app.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: avoid_init_to_null
2 | import 'package:aria_z/l10n/localization_intl.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter/widgets.dart';
5 | import 'package:hive_flutter/adapters.dart';
6 | import 'package:shared_preferences/shared_preferences.dart';
7 |
8 | import '../utils/aria2_api.dart';
9 | import 'aria2.dart';
10 |
11 | class Aria2ConnectConfig {
12 | String host;
13 |
14 | String port;
15 |
16 | String secret;
17 |
18 | String protocol;
19 |
20 | String type;
21 |
22 | String path;
23 |
24 | String configName;
25 |
26 | Aria2ConnectConfig({
27 | required this.protocol,
28 | required this.host,
29 | required this.port,
30 | required this.path,
31 | required this.type,
32 | required this.configName,
33 | this.secret = '',
34 | });
35 |
36 | factory Aria2ConnectConfig.fromJson(Map parsedJson) {
37 | return Aria2ConnectConfig(
38 | protocol: parsedJson['protocol'],
39 | host: parsedJson['host'],
40 | port: parsedJson['port'],
41 | path: parsedJson['path'],
42 | type: parsedJson['type'],
43 | configName: parsedJson['configName'],
44 | secret: parsedJson['secret'],
45 | );
46 | }
47 |
48 | Map toJson() {
49 | return {
50 | 'protocol': protocol,
51 | 'host': host,
52 | 'port': port,
53 | 'path': path,
54 | 'type': type,
55 | 'secret': secret,
56 | 'configName': configName
57 | };
58 | }
59 | }
60 |
61 | class Aria2TaskType {
62 | String desc;
63 |
64 | IconData icon;
65 |
66 | String name;
67 |
68 | TaskType taskType;
69 |
70 | Aria2TaskType(this.name, this.desc, this.icon, this.taskType);
71 | }
72 |
73 | class CustomMateriaColor {
74 | MaterialColor color;
75 |
76 | String desc;
77 |
78 | String name;
79 |
80 | CustomMateriaColor(this.name, this.color, this.desc);
81 | }
82 |
83 | class LocaleItem {
84 | String label;
85 |
86 | Locale? locale;
87 |
88 | LocaleItem(this.locale, this.label);
89 | }
90 |
91 | class AppState extends ChangeNotifier {
92 | AriazLocalizations _l10n = AriazLocalizations();
93 |
94 | AppState(this.aria2ConnectConfigBox, this.prefs);
95 |
96 | /// hiveBox容器
97 | Box aria2ConnectConfigBox;
98 |
99 | /// shared_preferences容器
100 | SharedPreferences prefs;
101 |
102 | /// 选择连接的服务器配置
103 | Aria2ConnectConfig? _selectedAria2ConnectConfig = null;
104 |
105 | /// aria2连接实例化
106 | Aria2Client? _client = null;
107 |
108 | /// aria2 请求结构缓存状态
109 | late final Aria2States states;
110 |
111 | /// 是否正在检查服务器配置
112 | bool checkingConfig = false;
113 |
114 | /// 是否正在连接服务器
115 | bool connectingServer = false;
116 |
117 | //getters
118 | /// 本地化
119 | Locale? get selectedLocale {
120 | String? _l = prefs.getString('userSelectedLocaleLanguageTag');
121 | if (_l != null) {
122 | List languageTag = _l.split('-');
123 | return Locale.fromSubtags(
124 | languageCode: languageTag.first,
125 | scriptCode: languageTag.length == 3 ? languageTag[1] : null,
126 | countryCode: languageTag.last);
127 | }
128 | }
129 |
130 | String get appUsingColorName => prefs.getString('primaryColor') ?? 'green';
131 |
132 | int get intervalSecond => prefs.getInt('intervalSecond') ?? 3;
133 |
134 | ThemeData get brightTheme => ThemeData(
135 | primarySwatch: appThemeColors
136 | .where((_color) => _color.name == appUsingColorName)
137 | .first
138 | .color,
139 | brightness: Brightness.light);
140 | ThemeData get darkTheme => ThemeData(
141 | primarySwatch: appThemeColors
142 | .where((_color) => _color.name == appUsingColorName)
143 | .first
144 | .color,
145 | brightness: Brightness.dark);
146 |
147 | Aria2Client? get aria2 => _client;
148 |
149 | Aria2ConnectConfig? get selectedAria2ConnectConfig {
150 | Map? _config =
151 | prefs.getString('lastConnectedAria2ConfigName')?.isNotEmpty == true
152 | ? Map.from(aria2ConnectConfigBox
153 | .toMap()
154 | .values
155 | .firstWhere((element) =>
156 | element['configName'] ==
157 | prefs.getString('lastConnectedAria2ConfigName')))
158 | : null;
159 |
160 | return _selectedAria2ConnectConfig ??
161 | (_config?.isNotEmpty == true
162 | ? Aria2ConnectConfig.fromJson(_config!)
163 | : null);
164 | }
165 |
166 | List get aria2ConnectConfigs {
167 | // aria2ConnectConfigBox.deleteAt(0);
168 | List tmpList = [];
169 | aria2ConnectConfigBox.toMap().forEach((key, value) {
170 | tmpList.add(Aria2ConnectConfig.fromJson(value));
171 | });
172 | return tmpList;
173 | }
174 |
175 | List get aria2TaskTypes => [
176 | Aria2TaskType(_l10n.taskTypeNameTorrent, _l10n.taskTypeDescTorrent,
177 | Icons.file_present, TaskType.torrent),
178 | Aria2TaskType(_l10n.taskTypeNameMagnet, _l10n.taskTypeDescMagnet,
179 | Icons.link, TaskType.magnet),
180 | Aria2TaskType(_l10n.taskTypeNameUrl, _l10n.taskTypeDescUrl, Icons.web,
181 | TaskType.url),
182 | Aria2TaskType(_l10n.taskTypeNameMetalink, _l10n.taskTypeDescMetalink,
183 | Icons.all_inclusive, TaskType.metaLink),
184 | ];
185 |
186 | List get appThemeColors => [
187 | CustomMateriaColor('blue', Colors.blue, _l10n.colorBlue),
188 | CustomMateriaColor('red', Colors.red, _l10n.colorRed),
189 | CustomMateriaColor('green', Colors.green, _l10n.colorGreen),
190 | CustomMateriaColor('purple', Colors.purple, _l10n.colorPurple),
191 | ];
192 |
193 | List get localeItems => [
194 | LocaleItem(null, _l10n.systemLanguage),
195 | LocaleItem(const Locale('en', 'US'), 'English'),
196 | LocaleItem(
197 | const Locale.fromSubtags(
198 | languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'),
199 | '简体中文')
200 | ];
201 | //*********************************************************************************************//
202 |
203 | void bindAria2States(Aria2States state) {
204 | states = state;
205 | }
206 |
207 | void bindL10n(AriazLocalizations l10n) {
208 | _l10n = l10n;
209 | }
210 |
211 | ///连接到aria2服务器
212 | connectToAria2Server(Aria2Client? newClient) async {
213 | updateConnectingStatus(true);
214 | _client = newClient;
215 | if (_client != null) {
216 | _client?.getAria2GlobalOption();
217 | _client?.getVersionInfo();
218 | _client?.getInfosInterval(intervalSecond, this);
219 | }
220 | notifyListeners();
221 | }
222 |
223 | updateConnectingStatus(bool status) {
224 | connectingServer = status;
225 | notifyListeners();
226 | }
227 |
228 | // 清理当前服务器所有的状态
229 | clearCurrentServerAllState() {
230 | _client?.clearGIInterval();
231 | states.clearStates();
232 | _client = null;
233 | }
234 |
235 | /// 添加连接配置
236 | bool addAria2ConnectConfig(Aria2ConnectConfig config) {
237 | bool isExist = false;
238 | aria2ConnectConfigBox.toMap().forEach((key, value) {
239 | if (value['configName'] == config.configName) {
240 | isExist = true;
241 | }
242 | });
243 | if (isExist) {
244 | return false;
245 | }
246 | aria2ConnectConfigBox.add(config.toJson());
247 | return true;
248 | }
249 |
250 | Future> checkAria2ConnectConfig(
251 | Aria2ConnectConfig config) async {
252 | _selectedAria2ConnectConfig = config;
253 | prefs.setString('lastConnectedAria2ConfigName', config.configName);
254 | checkingConfig = true;
255 | notifyListeners();
256 | Aria2Client __client = Aria2Client(
257 | '${config.protocol}://${config.host}:${config.port}${config.path}',
258 | config.type,
259 | config.secret,
260 | states,
261 | _l10n);
262 | Aria2Response checkResult =
263 | await __client.checkServerConnection();
264 | checkingConfig = false;
265 | notifyListeners();
266 | return checkResult;
267 | }
268 |
269 | /// 删除连接配置
270 | removeAria2ConnectConfig(Aria2ConnectConfig config) {
271 | aria2ConnectConfigBox.toMap().forEach((key, value) {
272 | if (value['configName'] == config.configName) {
273 | if (config.configName == selectedAria2ConnectConfig?.configName) {
274 | clearCurrentServerAllState();
275 | // _client = null;
276 | }
277 | aria2ConnectConfigBox.delete(key);
278 | }
279 | });
280 | notifyListeners();
281 | }
282 |
283 | /// 更新连接配置
284 | updateAria2ConnectConfig(Aria2ConnectConfig config, int idx) {
285 | aria2ConnectConfigBox.putAt(idx, config.toJson());
286 | notifyListeners();
287 | }
288 |
289 | changeTheme(String _colorName) {
290 | prefs.setString('primaryColor', _colorName);
291 | notifyListeners();
292 | }
293 |
294 | /// 更新刷新aria2服务访问频率
295 | void updateIntervalSecond(String second) {
296 | int _intervalSecond = int.parse(second);
297 | _client?.clearGIInterval();
298 | _client?.getInfosInterval(_intervalSecond, this);
299 | prefs.setInt('intervalSecond', _intervalSecond);
300 | notifyListeners();
301 | }
302 |
303 | void changeLocale(String languageCode) {
304 | if (languageCode.isEmpty) {
305 | prefs.remove('userSelectedLocaleLanguageTag');
306 | } else {
307 | prefs.setString('userSelectedLocaleLanguageTag', languageCode);
308 | }
309 | notifyListeners();
310 | }
311 | }
312 |
--------------------------------------------------------------------------------
/lib/components/custom_drawer.dart:
--------------------------------------------------------------------------------
1 | import 'package:aria2/aria2.dart';
2 | import 'package:aria2/models/aria2GlobalStat.dart';
3 | import 'package:aria_z/components/custom_snack_bar.dart';
4 | import 'package:aria_z/components/speed_shower.dart';
5 | import 'package:aria_z/l10n/localization_intl.dart';
6 | import 'package:flutter/material.dart';
7 | import 'package:flutter/rendering.dart';
8 | import 'package:flutter/widgets.dart';
9 | import 'package:provider/provider.dart';
10 | import 'package:tuple/tuple.dart';
11 |
12 | import '../states/aria2.dart';
13 | import '../states/app.dart';
14 | import '../views/edit_aria2_server_config.dart'
15 | show Aria2ConnectConfigArguments;
16 |
17 | Widget customDrawer(BuildContext _parentContext) {
18 | AriazLocalizations _l10n = AriazLocalizations.of(_parentContext);
19 | _deleteServerConfig(BuildContext context, Aria2ConnectConfig config) {
20 | showDialog(
21 | context: context,
22 | builder: (BuildContext context) {
23 | return AlertDialog(
24 | title: Text(_l10n.deleteDialogTitle),
25 | content: Text(_l10n.deleteDialogContent),
26 | actions: [
27 | TextButton(
28 | child: Text(_l10n.cancelBtnText),
29 | onPressed: () {
30 | Navigator.of(context).pop();
31 | },
32 | ),
33 | TextButton(
34 | child: Text(_l10n.confirmBtnText),
35 | onPressed: () {
36 | Provider.of(context, listen: false)
37 | .removeAria2ConnectConfig(config);
38 | Navigator.of(context).pop();
39 | },
40 | ),
41 | ],
42 | );
43 | },
44 | );
45 | }
46 |
47 | return Selector, Aria2ConnectConfig?>>(
49 | selector: (BuildContext context, AppState app) =>
50 | Tuple2(app.aria2ConnectConfigs, app.selectedAria2ConnectConfig),
51 | builder: (context, app, _) {
52 | return Drawer(
53 | child: Column(
54 | children: [
55 | Builder(builder: (context) {
56 | return Selector>(
58 | selector: (BuildContext context, Aria2States aria2State) =>
59 | Tuple2(aria2State.globalStatus, aria2State.versionInfo),
60 | builder: (context, serverInfo, _) {
61 | return DrawerHeader(
62 | decoration:
63 | BoxDecoration(color: Theme.of(context).primaryColor),
64 | child: DefaultTextStyle(
65 | style: TextStyle(
66 | color: Theme.of(context).colorScheme.onPrimary,
67 | fontSize: 12),
68 | child: Container(
69 | alignment: Alignment.topLeft,
70 | child: Column(
71 | crossAxisAlignment: CrossAxisAlignment.start,
72 | children: [
73 | const Text("AriaZ",
74 | style: TextStyle(
75 | fontFamily: 'Coda', fontSize: 32)),
76 | const SizedBox(height: 4),
77 | Text(
78 | app.item2 != null
79 | ? "${_l10n.connectedText} ${app.item2?.host}:${app.item2?.port}"
80 | : _l10n.notConnectTip,
81 | style: const TextStyle()),
82 | serverInfo.item2 != null
83 | ? Text(
84 | "${_l10n.aria2VersionLabel} ${serverInfo.item2?.version ?? ''}",
85 | style: const TextStyle())
86 | : const SizedBox(),
87 | serverInfo.item1 == null
88 | ? const SizedBox()
89 | : Chip(
90 | backgroundColor:
91 | Theme.of(context).backgroundColor,
92 | avatar: const Icon(Icons.speed),
93 | label: DefaultTextStyle(
94 | textAlign: TextAlign.center,
95 | style: TextStyle(
96 | color: Theme.of(context)
97 | .colorScheme
98 | .onBackground,
99 | fontSize: 12),
100 | child: SpeedShower(
101 | downloadSpeed: serverInfo
102 | .item1!.downloadSpeed,
103 | uploadSpeed: serverInfo
104 | .item1!.uploadSpeed)))
105 | ],
106 | ),
107 | )));
108 | });
109 | }),
110 | Container(
111 | constraints: const BoxConstraints(maxHeight: 400),
112 | // 使用 scrollbar 在滚动时显示滚动条
113 | child: Scrollbar(
114 | child: ListView.builder(
115 | // listview 和父组件 scrollBar 都有 scrollController,此处需要指定 listview 独立的scrollController,否则在滑动时会触发多个scrollController同时触发的错误
116 | controller: ScrollController(),
117 | // listView 高度在列表中内容减少时自动收缩,默认为false,也就是列表高度在渲染完毕之后不会因为内容的减少而收缩
118 | shrinkWrap: true,
119 | itemCount: app.item1.length,
120 | itemBuilder: (context, idx) {
121 | Aria2ConnectConfig acc = app.item1[idx];
122 | return ListTile(
123 | minLeadingWidth: 10,
124 | leading: acc.toJson().toString() ==
125 | app.item2?.toJson().toString()
126 | ? const Icon(Icons.check)
127 | : const Icon(Icons.link),
128 | title: Text(
129 | acc.configName,
130 | overflow: TextOverflow.fade,
131 | maxLines: 1,
132 | softWrap: false,
133 | style: const TextStyle(
134 | fontSize: 16, fontWeight: FontWeight.w600),
135 | ),
136 | subtitle: Text(
137 | '${acc.host}:${acc.port}',
138 | overflow: TextOverflow.fade,
139 | maxLines: 1,
140 | softWrap: false,
141 | style: const TextStyle(fontSize: 12),
142 | ),
143 | trailing: PopupMenuButton(
144 | child: const Icon(Icons.more_vert),
145 | itemBuilder: (context) => [
146 | PopupMenuItem(
147 | value: 'edit',
148 | child: Text(_l10n.editText),
149 | ),
150 | PopupMenuItem(
151 | value: 'delete',
152 | child: Text(_l10n.deleteText),
153 | ),
154 | ],
155 | onSelected: (value) {
156 | if (value == 'edit') {
157 | Navigator.of(context).popAndPushNamed(
158 | "/update_aria2_server",
159 | arguments: [
160 | Aria2ConnectConfigArguments(acc, idx),
161 | _parentContext
162 | ]);
163 | // Navigator.of(context).pushNamed('/editServer',arguments: acc);
164 | } else if (value == 'delete') {
165 | _deleteServerConfig(context, acc);
166 | }
167 | },
168 | ),
169 | selected: acc.toJson().toString() ==
170 | app.item2?.toJson().toString(),
171 | onTap: () {
172 | Navigator.pop(context);
173 | if (acc.configName != app.item2?.configName) {
174 | checkAndUseConfig(_parentContext, acc);
175 | }
176 | },
177 | );
178 | })),
179 | ),
180 | Expanded(
181 | child: ListView(
182 | physics: const NeverScrollableScrollPhysics(),
183 | padding: EdgeInsets.zero,
184 | children: [
185 | Builder(builder: (context) {
186 | return ListTile(
187 | minLeadingWidth: 10,
188 | leading: const Icon(Icons.add),
189 | title: Text(_l10n.addNewServerConfig),
190 | onTap: () => Navigator.of(context).popAndPushNamed(
191 | "/add_new_aria2_server",
192 | arguments: [null, _parentContext]));
193 | }),
194 | Builder(builder: (context) {
195 | return ListTile(
196 | minLeadingWidth: 10,
197 | leading: const Icon(Icons.settings),
198 | title: Text(_l10n.setting),
199 | onTap: () =>
200 | Navigator.of(context).popAndPushNamed("/global_setting"),
201 | );
202 | })
203 | ],
204 | ))
205 | ],
206 | ));
207 | },
208 | );
209 | }
210 |
--------------------------------------------------------------------------------
/lib/l10n/messages_zh_Hans_CN.dart:
--------------------------------------------------------------------------------
1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
2 | // This is a library that provides messages for a zh_Hans_CN locale. All the
3 | // messages from the main program should be duplicated here with the same
4 | // function name.
5 |
6 | // Ignore issues from commonly used lints in this file.
7 | // ignore_for_file:unnecessary_brace_in_string_interps
8 | // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering
9 | // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases
10 | // ignore_for_file:unused_import, file_names, always_declare_return_types
11 |
12 | import 'package:intl/intl.dart';
13 | import 'package:intl/message_lookup_by_library.dart';
14 |
15 | final messages = MessageLookup();
16 |
17 | typedef String MessageIfAbsent(String? messageStr, List