├── .fvm ├── flutter_sdk └── fvm_config.json ├── .gitignore ├── .metadata ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── alist │ │ │ │ ├── App.kt │ │ │ │ ├── DownloadingNotificationService.kt │ │ │ │ ├── activity │ │ │ │ ├── MainActivity.kt │ │ │ │ └── PlayerActivity.kt │ │ │ │ ├── bean │ │ │ │ ├── ExternalPlayer.kt │ │ │ │ ├── FindVideoRecordResp.kt │ │ │ │ └── VideoItem.kt │ │ │ │ ├── fileprovider │ │ │ │ └── AListFileProvider.kt │ │ │ │ ├── plugin │ │ │ │ └── AlistPlugin.kt │ │ │ │ ├── utils │ │ │ │ ├── FileProviderUtils.java │ │ │ │ ├── FlutterMethods.kt │ │ │ │ ├── GsonUtils.kt │ │ │ │ └── PackageManagerUtils.kt │ │ │ │ └── widget │ │ │ │ └── AlistClientVideoPlayer.java │ │ └── res │ │ │ ├── drawable-xxhdpi │ │ │ └── ic_ffwd.png │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── layout │ │ │ ├── activity_player.xml │ │ │ └── video_layout_alist_client.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_splash_android.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_splash_android.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_splash_android.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_splash_android.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_splash_android.png │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ ├── values-zh │ │ │ └── strings.xml │ │ │ ├── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ │ └── xml │ │ │ └── alist_file_paths.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets └── images │ ├── 2.0x │ ├── account_icon.png │ ├── account_icon_choosed.png │ ├── file_type_apk.png │ ├── file_type_audio.png │ ├── file_type_code.png │ ├── file_type_docment.png │ ├── file_type_excel.png │ ├── file_type_folder.png │ ├── file_type_image.png │ ├── file_type_md.png │ ├── file_type_pdf.png │ ├── file_type_ppt.png │ ├── file_type_unknow.png │ ├── file_type_video.png │ ├── file_type_word.png │ ├── file_type_zip.png │ ├── icon_arrow_right.png │ ├── icon_ffwd.png │ ├── login_screen_account.png │ ├── login_screen_password.png │ ├── login_screen_server_url.png │ ├── logo.png │ ├── settings_screen_about.png │ ├── settings_screen_account.png │ ├── settings_screen_cache_manager.png │ ├── settings_screen_donate.png │ ├── settings_screen_download.png │ ├── settings_screen_player.png │ └── settings_screen_privacy_policy.png │ ├── 3.0x │ ├── account_icon.png │ ├── account_icon_choosed.png │ ├── file_type_apk.png │ ├── file_type_audio.png │ ├── file_type_code.png │ ├── file_type_docment.png │ ├── file_type_excel.png │ ├── file_type_folder.png │ ├── file_type_image.png │ ├── file_type_md.png │ ├── file_type_pdf.png │ ├── file_type_ppt.png │ ├── file_type_unknow.png │ ├── file_type_video.png │ ├── file_type_word.png │ ├── file_type_zip.png │ ├── icon_arrow_right.png │ ├── icon_ffwd.png │ ├── login_screen_account.png │ ├── login_screen_password.png │ ├── login_screen_server_url.png │ ├── logo.png │ ├── settings_screen_about.png │ ├── settings_screen_account.png │ ├── settings_screen_cache_manager.png │ ├── settings_screen_donate.png │ ├── settings_screen_download.png │ ├── settings_screen_player.png │ └── settings_screen_privacy_policy.png │ ├── account_icon.png │ ├── account_icon_choosed.png │ ├── file_type_apk.png │ ├── file_type_audio.png │ ├── file_type_code.png │ ├── file_type_docment.png │ ├── file_type_excel.png │ ├── file_type_folder.png │ ├── file_type_image.png │ ├── file_type_md.png │ ├── file_type_pdf.png │ ├── file_type_ppt.png │ ├── file_type_unknow.png │ ├── file_type_video.png │ ├── file_type_word.png │ ├── file_type_zip.png │ ├── ic_infuse.png │ ├── ic_launcher.png │ ├── ic_nplayer.png │ ├── ic_vlc.png │ ├── icon_arrow_right.png │ ├── icon_ffwd.png │ ├── login_screen_account.png │ ├── login_screen_password.png │ ├── login_screen_server_url.png │ ├── logo.png │ ├── settings_screen_about.png │ ├── settings_screen_account.png │ ├── settings_screen_cache_manager.png │ ├── settings_screen_donate.png │ ├── settings_screen_download.png │ ├── settings_screen_player.png │ └── settings_screen_privacy_policy.png ├── generateKeys ├── github ├── android_github.png ├── appstore.png └── banner.jpg ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── AppSupportFiles │ └── license.crt │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── 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-83.5x83.5@2x.png │ │ └── Icon-App-iTunes.png │ ├── Contents.json │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── README.md │ │ ├── ic_splash_ios.png │ │ ├── ic_splash_ios@2x.png │ │ └── ic_splash_ios@3x.png │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ ├── Runner-Bridging-Header.h │ ├── Runner.entitlements │ ├── en.lproj │ └── InfoPlist.strings │ └── zh-Hans.lproj │ ├── InfoPlist.strings │ ├── LaunchScreen.strings │ └── Main.strings ├── lib ├── database │ ├── alist_database.dart │ ├── alist_database.g.dart │ ├── alist_database_controller.dart │ ├── dao │ │ ├── favorite_dao.dart │ │ ├── file_download_record_dao.dart │ │ ├── file_password_dao.dart │ │ ├── file_viewing_record_dao.dart │ │ ├── server_dao.dart │ │ └── video_viewing_record_dao.dart │ └── table │ │ ├── favorite.dart │ │ ├── file_download_record.dart │ │ ├── file_password.dart │ │ ├── file_viewing_record.dart │ │ ├── server.dart │ │ └── video_viewing_record.dart ├── entity │ ├── app_version_resp.dart │ ├── copy_move_req.dart │ ├── donate_config_entity.dart │ ├── downloads_info.dart │ ├── file_info_resp_entity.dart │ ├── file_list_resp_entity.dart │ ├── file_remove_req.dart │ ├── file_rename_req.dart │ ├── file_search_resp.dart │ ├── http_result.dart │ ├── login_resp_entity.dart │ ├── mkdir_req.dart │ ├── my_info_resp.dart │ ├── player_resolve_info_entity.dart │ └── public_settings_resp.dart ├── generated │ ├── color_schemes.g.dart │ ├── images.dart │ └── json │ │ ├── app_version_resp.g.dart │ │ ├── base │ │ ├── json_convert_content.dart │ │ └── json_field.dart │ │ ├── copy_move_req.g.dart │ │ ├── donate_config_entity.g.dart │ │ ├── downloads_info.g.dart │ │ ├── file_info_resp_entity.g.dart │ │ ├── file_list_resp_entity.g.dart │ │ ├── file_remove_req.g.dart │ │ ├── file_rename_req.g.dart │ │ ├── file_search_resp.g.dart │ │ ├── login_resp_entity.g.dart │ │ ├── mkdir_req.g.dart │ │ ├── my_info_resp.g.dart │ │ ├── player_resolve_info_entity.g.dart │ │ └── public_settings_resp.g.dart ├── l10n │ ├── alist_translations.dart │ ├── intl_en_us.dart │ ├── intl_keys.dart │ └── intl_zh_cn.dart ├── main.dart ├── net │ ├── base_entity.dart │ ├── dio_utils.dart │ ├── intercept.dart │ ├── json_parse_error.dart │ ├── net.dart │ ├── net_error_handler.dart │ └── redirect_exception.dart ├── router.dart ├── screen │ ├── aboute_screen.dart │ ├── account_screen.dart │ ├── audio_player_screen.dart │ ├── cache_manager.dart │ ├── donate_screen.dart │ ├── download_manager_screen.dart │ ├── favorite_screen.dart │ ├── file_list │ │ ├── director_password_dialog.dart │ │ ├── file_copy_move_dialog.dart │ │ ├── file_list_menu_anchor.dart │ │ ├── file_list_navigator.dart │ │ ├── file_list_screen.dart │ │ ├── file_rename_dialog.dart │ │ └── mkdir_dialog.dart │ ├── file_reader_screen.dart │ ├── file_search_screen.dart │ ├── gallery_screen.dart │ ├── home_screen.dart │ ├── login_screen.dart │ ├── pdf_reader_screen.dart │ ├── player_settings_screen.dart │ ├── recents_screen.dart │ ├── settings_screen.dart │ ├── splash_screen.dart │ ├── uploading_files_screen.dart │ ├── video_player_screen.dart │ └── web_screen.dart ├── util │ ├── alist_plugin.dart │ ├── constant.dart │ ├── download │ │ ├── download_http_client.dart │ │ ├── download_manager.dart │ │ ├── download_task.dart │ │ └── download_task_status.dart │ ├── file_password_helper.dart │ ├── file_type.dart │ ├── file_utils.dart │ ├── focus_node_utils.dart │ ├── global.dart │ ├── iterator.dart │ ├── keyboard_utils.dart │ ├── lock_caching_audio_source.dart │ ├── log_utils.dart │ ├── markdown_utils.dart │ ├── method_call_handler.dart │ ├── named_router.dart │ ├── nature_sort.dart │ ├── proxy.dart │ ├── string_utils.dart │ ├── user_controller.dart │ ├── video_player_util.dart │ └── widget_utils.dart └── widget │ ├── alist_checkbox.dart │ ├── alist_scaffold.dart │ ├── alist_will_pop_scope.dart │ ├── bottom_navigation_bar.dart │ ├── config_file_name_max_lines_dialog.dart │ ├── file_details_dialog.dart │ ├── file_list_item_view.dart │ ├── loading_status_widget.dart │ ├── overflow_text.dart │ ├── player_selector_dialog.dart │ ├── player_skin.dart │ ├── slider.dart │ └── update_dialog.dart ├── linux ├── .gitignore ├── CMakeLists.txt ├── flutter │ ├── CMakeLists.txt │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake ├── main.cc ├── my_application.cc └── my_application.h ├── macos ├── .gitignore ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── app_icon_1024.png │ │ ├── app_icon_128.png │ │ ├── app_icon_16.png │ │ ├── app_icon_256.png │ │ ├── app_icon_32.png │ │ ├── app_icon_512.png │ │ └── app_icon_64.png │ ├── Base.lproj │ └── MainMenu.xib │ ├── Configs │ ├── AppInfo.xcconfig │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── Warnings.xcconfig │ ├── DebugProfile.entitlements │ ├── Info.plist │ ├── MainFlutterWindow.swift │ └── Release.entitlements ├── pubspec.lock ├── pubspec.yaml ├── test └── widget_test.dart ├── web ├── favicon.png ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png ├── index.html └── manifest.json └── windows ├── .gitignore ├── CMakeLists.txt ├── flutter ├── CMakeLists.txt ├── generated_plugin_registrant.cc ├── generated_plugin_registrant.h └── generated_plugins.cmake └── runner ├── CMakeLists.txt ├── Runner.rc ├── flutter_window.cpp ├── flutter_window.h ├── main.cpp ├── resource.h ├── resources └── app_icon.ico ├── runner.exe.manifest ├── utils.cpp ├── utils.h ├── win32_window.cpp └── win32_window.h /.fvm/flutter_sdk: -------------------------------------------------------------------------------- 1 | /Users/tangrui/.fvm/versions/3.13.8 -------------------------------------------------------------------------------- /.fvm/fvm_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "flutterSdkVersion": "3.13.8", 3 | "flavors": {} 4 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .build/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | .swiftpm/ 13 | migrate_working_dir/ 14 | 15 | # IntelliJ related 16 | *.iml 17 | *.ipr 18 | *.iws 19 | .idea/ 20 | 21 | # The .vscode folder contains launch configuration and tasks you configure in 22 | # VS Code which you may wish to be included in version control, so this line 23 | # is commented out by default. 24 | #.vscode/ 25 | 26 | # Flutter/Dart/Pub related 27 | **/doc/api/ 28 | **/ios/Flutter/.last_build_id 29 | .dart_tool/ 30 | .flutter-plugins 31 | .flutter-plugins-dependencies 32 | .packages 33 | .pub-cache/ 34 | .pub/ 35 | /build/ 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 | -------------------------------------------------------------------------------- /.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. 5 | 6 | version: 7 | revision: f72efea43c3013323d1b95cff571f3c1caa37583 8 | channel: stable 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 17 | base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 18 | - platform: android 19 | create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 20 | base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 21 | - platform: ios 22 | create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 23 | base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 24 | - platform: linux 25 | create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 26 | base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 27 | - platform: macos 28 | create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 29 | base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 30 | - platform: web 31 | create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 32 | base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 33 | - platform: windows 34 | create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 35 | base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ALClient 2 | 3 | ![banner](https://raw.githubusercontent.com/BFWXKJGS/AlistClient/main/github/banner.jpg) 4 | 5 | ## AppStore 6 | ![banner](https://raw.githubusercontent.com/BFWXKJGS/AlistClient/main/github/appstore.png) 7 | 8 | ## Android(蓝奏云下载) 9 | https://wwxv.lanzoul.com/b002uv0t2b 10 | 密码:alist 11 | 12 | ## Android 13 | ![banner](https://raw.githubusercontent.com/BFWXKJGS/AlistClient/main/github/android_github.png) 14 | 15 | ALClient is a mobile application developed using Flutter based on [the AList project](https://github.com/alist-org/alist), supporting both Android and IOS platforms. It provides various functions, including online browsing of files, online viewing of videos, audios, and browsing of documents in the AList project. It also supports file uploading (to be developed) and file management (to be developed). Users can easily access and watch various types of media files in the AList project through ALClient. -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | privacy.gradle 15 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 8 | 9 | 10 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/github/alist/App.kt: -------------------------------------------------------------------------------- 1 | package com.github.alist 2 | 3 | import android.content.Context 4 | import androidx.multidex.MultiDex 5 | import com.shuyu.gsyvideoplayer.GSYVideoManager 6 | import com.shuyu.gsyvideoplayer.model.VideoOptionModel 7 | import io.flutter.app.FlutterApplication 8 | import tv.danmaku.ijk.media.player.IjkMediaPlayer 9 | 10 | 11 | class App : FlutterApplication() { 12 | override fun onCreate() { 13 | super.onCreate() 14 | 15 | val gsyOptionModelList = mutableListOf() 16 | // 丢帧解决音视频不同步的文 17 | val videoOptionMode01 = VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1) 18 | val videoOptionMode02 = 19 | VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 0) 20 | 21 | // url切换400/404(http与https域名共用等) 22 | val videoOptionMode03 = 23 | VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_clear", 1) 24 | val videoOptionMode04 = 25 | VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_timeout", -1) 26 | gsyOptionModelList.add(videoOptionMode01) 27 | gsyOptionModelList.add(videoOptionMode02) 28 | gsyOptionModelList.add(videoOptionMode03) 29 | gsyOptionModelList.add(videoOptionMode04) 30 | GSYVideoManager.instance().optionModelList = gsyOptionModelList 31 | } 32 | 33 | override fun attachBaseContext(base: Context?) { 34 | super.attachBaseContext(base) 35 | MultiDex.install(this) 36 | } 37 | } -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/github/alist/DownloadingNotificationService.kt: -------------------------------------------------------------------------------- 1 | package com.github.alist 2 | 3 | import android.app.NotificationChannel 4 | import android.app.NotificationManager 5 | import android.app.Service 6 | import android.content.Context 7 | import android.content.Intent 8 | import android.os.Build 9 | import androidx.core.app.NotificationCompat 10 | import com.github.alist.client.R 11 | 12 | class DownloadingNotificationService : Service() { 13 | companion object { 14 | const val channelId = "com.github.alist.client.download" 15 | const val channelName = "Download" 16 | } 17 | 18 | override fun onBind(intent: Intent?) = null 19 | 20 | override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { 21 | val notificationManager = 22 | getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 23 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 24 | val channel = 25 | NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH) 26 | notificationManager.createNotificationChannel(channel) 27 | } 28 | val notification = NotificationCompat.Builder(this, channelId) 29 | .setSmallIcon(R.mipmap.ic_launcher) 30 | .setContentTitle(getString(R.string.downloading_notification_title)) 31 | .setContentText(getString(R.string.downloading_notification_content)) 32 | .setAutoCancel(false) 33 | .setOngoing(true) 34 | .build() 35 | startForeground(1, notification) 36 | return super.onStartCommand(intent, flags, startId) 37 | } 38 | } -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/github/alist/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.github.alist.activity 2 | 3 | import android.content.Intent 4 | import com.github.alist.plugin.AlistPlugin 5 | import com.ryanheise.audioservice.AudioServiceFragmentActivity 6 | import io.flutter.embedding.engine.FlutterEngine 7 | import kotlinx.coroutines.CoroutineScope 8 | import kotlinx.coroutines.MainScope 9 | import kotlinx.coroutines.cancel 10 | 11 | class MainActivity : AudioServiceFragmentActivity() { 12 | private val coroutineScope: CoroutineScope = MainScope() 13 | private val alistPlugin = AlistPlugin(this, coroutineScope) 14 | 15 | override fun configureFlutterEngine(flutterEngine: FlutterEngine) { 16 | super.configureFlutterEngine(flutterEngine) 17 | flutterEngine.plugins.add(alistPlugin) 18 | } 19 | 20 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 21 | super.onActivityResult(requestCode, resultCode, data) 22 | alistPlugin.onActivityResult(requestCode, resultCode, data) 23 | } 24 | 25 | override fun onDestroy() { 26 | coroutineScope.cancel() 27 | super.onDestroy() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/github/alist/bean/ExternalPlayer.kt: -------------------------------------------------------------------------------- 1 | package com.github.alist.bean 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | class ExternalPlayer( 6 | @SerializedName("packageName") 7 | val packageName: String, 8 | @SerializedName("activity") 9 | val activity: String, 10 | @SerializedName("label") 11 | val label: String, 12 | @SerializedName("icon") 13 | val icon: String 14 | ) -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/github/alist/bean/FindVideoRecordResp.kt: -------------------------------------------------------------------------------- 1 | package com.github.alist.bean 2 | 3 | class FindVideoRecordResp( 4 | val videoCurrentPosition: Long?, 5 | val videoDuration: Long? 6 | ) -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/github/alist/bean/VideoItem.kt: -------------------------------------------------------------------------------- 1 | package com.github.alist.bean 2 | 3 | class VideoItem( 4 | val name: String, 5 | val localPath: String?, 6 | val remotePath: String, 7 | val sign: String?, 8 | val provider: String?, 9 | val thumb: String?, 10 | val url: String, 11 | val modifiedMilliseconds: String?, 12 | val size: String? 13 | ) -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/github/alist/fileprovider/AListFileProvider.kt: -------------------------------------------------------------------------------- 1 | package com.github.alist.fileprovider 2 | 3 | import androidx.core.content.FileProvider 4 | 5 | class AListFileProvider : FileProvider() -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/github/alist/utils/FileProviderUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.alist.utils; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.os.Build; 7 | 8 | import androidx.core.content.FileProvider; 9 | 10 | import java.io.File; 11 | 12 | public class FileProviderUtils { 13 | public static Uri getUriFromFile(Context context, File file) { 14 | Uri uri; 15 | if (Build.VERSION.SDK_INT >= 24) { 16 | uri = getUriForFile24(context, file); 17 | } else { 18 | uri = Uri.fromFile(file); 19 | } 20 | return uri; 21 | } 22 | 23 | public static Uri getUriForFile24(Context context, File file) { 24 | return FileProvider.getUriForFile(context, 25 | String.format("%s.alist_file_provider", context.getPackageName()), file); 26 | } 27 | 28 | public static void setIntentDataAndType(Context context, 29 | Intent intent, 30 | String type, 31 | File file, 32 | boolean writeAble) { 33 | if (Build.VERSION.SDK_INT >= 24) { 34 | intent.setDataAndType(getUriForFile24(context, file), type); 35 | intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 36 | if (writeAble) { 37 | intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 38 | } 39 | } else { 40 | intent.setDataAndType(Uri.fromFile(file), type); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/github/alist/utils/FlutterMethods.kt: -------------------------------------------------------------------------------- 1 | package com.github.alist.utils 2 | 3 | import com.github.alist.bean.FindVideoRecordResp 4 | import com.github.alist.bean.VideoItem 5 | import io.flutter.plugin.common.MethodChannel 6 | 7 | object FlutterMethods { 8 | lateinit var channel: MethodChannel 9 | 10 | fun findVideoRecordByPath(path: String, callback: (FindVideoRecordResp) -> Unit) { 11 | channel.invokeMethod( 12 | "findVideoRecordByPath", 13 | mutableMapOf("path" to path), 14 | object : MethodChannel.Result { 15 | 16 | override fun success(result: Any?) { 17 | if (result is String) { 18 | callback(GsonUtils.parseObject(result)) 19 | } 20 | } 21 | 22 | override fun error(p0: String, p1: String?, p2: Any?) { 23 | } 24 | 25 | override fun notImplemented() { 26 | } 27 | }) 28 | } 29 | 30 | fun deleteVideoRecord(path: String) { 31 | channel.invokeMethod( 32 | "deleteVideoRecord", 33 | mutableMapOf("path" to path) 34 | ) 35 | } 36 | 37 | fun insertOrUpdateVideoRecord( 38 | path: String, 39 | videoCurrentPosition: Long, 40 | videoDuration: Long, 41 | sign: String? 42 | ) { 43 | channel.invokeMethod( 44 | "insertOrUpdateVideoRecord", 45 | mutableMapOf( 46 | "path" to path, 47 | "videoCurrentPosition" to videoCurrentPosition, 48 | "videoDuration" to videoDuration, 49 | "sign" to sign 50 | ) 51 | ) 52 | } 53 | 54 | fun onPayerDestroyed() { 55 | channel.invokeMethod("onPayerDestroyed", "") 56 | } 57 | 58 | fun addFileViewingRecord(video: VideoItem) { 59 | channel.invokeMethod( 60 | "addFileViewingRecord", 61 | mutableMapOf( 62 | "path" to video.remotePath, 63 | "name" to video.name, 64 | "sign" to video.sign, 65 | "size" to video.size, 66 | "thumb" to video.thumb, 67 | "modifiedMilliseconds" to video.modifiedMilliseconds, 68 | "provider" to video.provider 69 | ) 70 | ) 71 | } 72 | } -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/github/alist/utils/GsonUtils.kt: -------------------------------------------------------------------------------- 1 | package com.github.alist.utils 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.reflect.TypeToken 5 | 6 | object GsonUtils { 7 | val gson = Gson() 8 | 9 | inline fun parseMap(jsonText: String): Map { 10 | val resultType = 11 | TypeToken.getParameterized(MutableMap::class.java, K::class.java, V::class.java) 12 | return gson.fromJson(jsonText, resultType) as Map 13 | } 14 | 15 | inline fun parseList(jsonText: String): List { 16 | val resultType = TypeToken.getParameterized(List::class.java, T::class.java) 17 | return gson.fromJson(jsonText, resultType) as List 18 | } 19 | 20 | inline fun parseObject(jsonText: String): T { 21 | return gson.fromJson(jsonText, T::class.java) 22 | } 23 | 24 | fun toJsonString(jsonObj: Any): String { 25 | return gson.toJson(jsonObj) 26 | } 27 | } -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/github/alist/utils/PackageManagerUtils.kt: -------------------------------------------------------------------------------- 1 | package com.github.alist.utils 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.content.pm.PackageManager 6 | import android.graphics.Bitmap 7 | import android.net.Uri 8 | import android.os.Build 9 | import androidx.core.graphics.drawable.toBitmap 10 | import com.github.alist.bean.ExternalPlayer 11 | import kotlinx.coroutines.Dispatchers 12 | import kotlinx.coroutines.withContext 13 | import java.io.ByteArrayOutputStream 14 | import java.io.File 15 | 16 | object PackageManagerUtils { 17 | suspend fun loadExternalPlayerList(context: Context): List { 18 | return withContext(Dispatchers.IO) { 19 | val packageManager: PackageManager = context.packageManager 20 | val intent = Intent(Intent.ACTION_VIEW) 21 | intent.setDataAndType(Uri.parse("http://a.com/test.mp4"), "video/*") 22 | val resolveInfos = packageManager.queryIntentActivities(intent, 0) 23 | 24 | val resultList = mutableListOf() 25 | for (resolveInfo in resolveInfos) { 26 | val label = resolveInfo.activityInfo.loadLabel(packageManager) 27 | 28 | val file = 29 | File(context.cacheDir, "appIcon/${resolveInfo.activityInfo.packageName}.webp") 30 | if (!file.exists()) { 31 | file.parentFile?.mkdirs() 32 | val appIcon = resolveInfo.loadIcon(packageManager) 33 | val bitmap = appIcon.toBitmap() 34 | val byteArrayOutputStream = ByteArrayOutputStream() 35 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 36 | bitmap.compress( 37 | Bitmap.CompressFormat.WEBP_LOSSLESS, 38 | 100, 39 | byteArrayOutputStream 40 | ) 41 | } else { 42 | bitmap.compress(Bitmap.CompressFormat.WEBP, 100, byteArrayOutputStream) 43 | } 44 | val byteArray = byteArrayOutputStream.toByteArray() 45 | 46 | val tmpFile = File("${file.absolutePath}.tmp") 47 | tmpFile.writeBytes(byteArray) 48 | tmpFile.renameTo(file) 49 | } 50 | 51 | resultList.add( 52 | ExternalPlayer( 53 | packageName = resolveInfo.activityInfo.packageName, 54 | activity = resolveInfo.activityInfo.name, 55 | label = label.toString(), 56 | icon = file.absolutePath 57 | ) 58 | ) 59 | } 60 | resultList 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/ic_ffwd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/android/app/src/main/res/drawable-xxhdpi/ic_ffwd.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/layout/activity_player.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_splash_android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/android/app/src/main/res/mipmap-hdpi/ic_splash_android.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_splash_android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/android/app/src/main/res/mipmap-mdpi/ic_splash_android.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_splash_android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/android/app/src/main/res/mipmap-xhdpi/ic_splash_android.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_splash_android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/android/app/src/main/res/mipmap-xxhdpi/ic_splash_android.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_splash_android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/android/app/src/main/res/mipmap-xxxhdpi/ic_splash_android.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 17 | 22 | 23 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 文件下载中... 4 | 文件下载正在后台中... 5 | 倍速播放中 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Downloading... 4 | Files download is in the background. 5 | Playing at double speed 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 17 | 22 | 23 | 35 | 36 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/alist_file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 8 | 9 | 10 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.9.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.2.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | maven { url 'https://jitpack.io' } 19 | maven { url "https://maven.aliyun.com/repository/public" } 20 | } 21 | } 22 | 23 | rootProject.buildDir = '../build' 24 | subprojects { 25 | project.buildDir = "${rootProject.buildDir}/${project.name}" 26 | } 27 | subprojects { 28 | project.evaluationDependsOn(':app') 29 | } 30 | 31 | tasks.register("clean", Delete) { 32 | delete rootProject.buildDir 33 | } 34 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip 6 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /assets/images/2.0x/account_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/account_icon.png -------------------------------------------------------------------------------- /assets/images/2.0x/account_icon_choosed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/account_icon_choosed.png -------------------------------------------------------------------------------- /assets/images/2.0x/file_type_apk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/file_type_apk.png -------------------------------------------------------------------------------- /assets/images/2.0x/file_type_audio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/file_type_audio.png -------------------------------------------------------------------------------- /assets/images/2.0x/file_type_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/file_type_code.png -------------------------------------------------------------------------------- /assets/images/2.0x/file_type_docment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/file_type_docment.png -------------------------------------------------------------------------------- /assets/images/2.0x/file_type_excel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/file_type_excel.png -------------------------------------------------------------------------------- /assets/images/2.0x/file_type_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/file_type_folder.png -------------------------------------------------------------------------------- /assets/images/2.0x/file_type_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/file_type_image.png -------------------------------------------------------------------------------- /assets/images/2.0x/file_type_md.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/file_type_md.png -------------------------------------------------------------------------------- /assets/images/2.0x/file_type_pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/file_type_pdf.png -------------------------------------------------------------------------------- /assets/images/2.0x/file_type_ppt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/file_type_ppt.png -------------------------------------------------------------------------------- /assets/images/2.0x/file_type_unknow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/file_type_unknow.png -------------------------------------------------------------------------------- /assets/images/2.0x/file_type_video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/file_type_video.png -------------------------------------------------------------------------------- /assets/images/2.0x/file_type_word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/file_type_word.png -------------------------------------------------------------------------------- /assets/images/2.0x/file_type_zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/file_type_zip.png -------------------------------------------------------------------------------- /assets/images/2.0x/icon_arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/icon_arrow_right.png -------------------------------------------------------------------------------- /assets/images/2.0x/icon_ffwd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/icon_ffwd.png -------------------------------------------------------------------------------- /assets/images/2.0x/login_screen_account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/login_screen_account.png -------------------------------------------------------------------------------- /assets/images/2.0x/login_screen_password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/login_screen_password.png -------------------------------------------------------------------------------- /assets/images/2.0x/login_screen_server_url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/login_screen_server_url.png -------------------------------------------------------------------------------- /assets/images/2.0x/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/logo.png -------------------------------------------------------------------------------- /assets/images/2.0x/settings_screen_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/settings_screen_about.png -------------------------------------------------------------------------------- /assets/images/2.0x/settings_screen_account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/settings_screen_account.png -------------------------------------------------------------------------------- /assets/images/2.0x/settings_screen_cache_manager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/settings_screen_cache_manager.png -------------------------------------------------------------------------------- /assets/images/2.0x/settings_screen_donate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/settings_screen_donate.png -------------------------------------------------------------------------------- /assets/images/2.0x/settings_screen_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/settings_screen_download.png -------------------------------------------------------------------------------- /assets/images/2.0x/settings_screen_player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/settings_screen_player.png -------------------------------------------------------------------------------- /assets/images/2.0x/settings_screen_privacy_policy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/2.0x/settings_screen_privacy_policy.png -------------------------------------------------------------------------------- /assets/images/3.0x/account_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/account_icon.png -------------------------------------------------------------------------------- /assets/images/3.0x/account_icon_choosed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/account_icon_choosed.png -------------------------------------------------------------------------------- /assets/images/3.0x/file_type_apk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/file_type_apk.png -------------------------------------------------------------------------------- /assets/images/3.0x/file_type_audio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/file_type_audio.png -------------------------------------------------------------------------------- /assets/images/3.0x/file_type_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/file_type_code.png -------------------------------------------------------------------------------- /assets/images/3.0x/file_type_docment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/file_type_docment.png -------------------------------------------------------------------------------- /assets/images/3.0x/file_type_excel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/file_type_excel.png -------------------------------------------------------------------------------- /assets/images/3.0x/file_type_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/file_type_folder.png -------------------------------------------------------------------------------- /assets/images/3.0x/file_type_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/file_type_image.png -------------------------------------------------------------------------------- /assets/images/3.0x/file_type_md.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/file_type_md.png -------------------------------------------------------------------------------- /assets/images/3.0x/file_type_pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/file_type_pdf.png -------------------------------------------------------------------------------- /assets/images/3.0x/file_type_ppt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/file_type_ppt.png -------------------------------------------------------------------------------- /assets/images/3.0x/file_type_unknow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/file_type_unknow.png -------------------------------------------------------------------------------- /assets/images/3.0x/file_type_video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/file_type_video.png -------------------------------------------------------------------------------- /assets/images/3.0x/file_type_word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/file_type_word.png -------------------------------------------------------------------------------- /assets/images/3.0x/file_type_zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/file_type_zip.png -------------------------------------------------------------------------------- /assets/images/3.0x/icon_arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/icon_arrow_right.png -------------------------------------------------------------------------------- /assets/images/3.0x/icon_ffwd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/icon_ffwd.png -------------------------------------------------------------------------------- /assets/images/3.0x/login_screen_account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/login_screen_account.png -------------------------------------------------------------------------------- /assets/images/3.0x/login_screen_password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/login_screen_password.png -------------------------------------------------------------------------------- /assets/images/3.0x/login_screen_server_url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/login_screen_server_url.png -------------------------------------------------------------------------------- /assets/images/3.0x/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/logo.png -------------------------------------------------------------------------------- /assets/images/3.0x/settings_screen_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/settings_screen_about.png -------------------------------------------------------------------------------- /assets/images/3.0x/settings_screen_account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/settings_screen_account.png -------------------------------------------------------------------------------- /assets/images/3.0x/settings_screen_cache_manager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/settings_screen_cache_manager.png -------------------------------------------------------------------------------- /assets/images/3.0x/settings_screen_donate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/settings_screen_donate.png -------------------------------------------------------------------------------- /assets/images/3.0x/settings_screen_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/settings_screen_download.png -------------------------------------------------------------------------------- /assets/images/3.0x/settings_screen_player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/settings_screen_player.png -------------------------------------------------------------------------------- /assets/images/3.0x/settings_screen_privacy_policy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/3.0x/settings_screen_privacy_policy.png -------------------------------------------------------------------------------- /assets/images/account_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/account_icon.png -------------------------------------------------------------------------------- /assets/images/account_icon_choosed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/account_icon_choosed.png -------------------------------------------------------------------------------- /assets/images/file_type_apk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/file_type_apk.png -------------------------------------------------------------------------------- /assets/images/file_type_audio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/file_type_audio.png -------------------------------------------------------------------------------- /assets/images/file_type_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/file_type_code.png -------------------------------------------------------------------------------- /assets/images/file_type_docment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/file_type_docment.png -------------------------------------------------------------------------------- /assets/images/file_type_excel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/file_type_excel.png -------------------------------------------------------------------------------- /assets/images/file_type_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/file_type_folder.png -------------------------------------------------------------------------------- /assets/images/file_type_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/file_type_image.png -------------------------------------------------------------------------------- /assets/images/file_type_md.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/file_type_md.png -------------------------------------------------------------------------------- /assets/images/file_type_pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/file_type_pdf.png -------------------------------------------------------------------------------- /assets/images/file_type_ppt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/file_type_ppt.png -------------------------------------------------------------------------------- /assets/images/file_type_unknow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/file_type_unknow.png -------------------------------------------------------------------------------- /assets/images/file_type_video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/file_type_video.png -------------------------------------------------------------------------------- /assets/images/file_type_word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/file_type_word.png -------------------------------------------------------------------------------- /assets/images/file_type_zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/file_type_zip.png -------------------------------------------------------------------------------- /assets/images/ic_infuse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/ic_infuse.png -------------------------------------------------------------------------------- /assets/images/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/ic_launcher.png -------------------------------------------------------------------------------- /assets/images/ic_nplayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/ic_nplayer.png -------------------------------------------------------------------------------- /assets/images/ic_vlc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/ic_vlc.png -------------------------------------------------------------------------------- /assets/images/icon_arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/icon_arrow_right.png -------------------------------------------------------------------------------- /assets/images/icon_ffwd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/icon_ffwd.png -------------------------------------------------------------------------------- /assets/images/login_screen_account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/login_screen_account.png -------------------------------------------------------------------------------- /assets/images/login_screen_password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/login_screen_password.png -------------------------------------------------------------------------------- /assets/images/login_screen_server_url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/login_screen_server_url.png -------------------------------------------------------------------------------- /assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/logo.png -------------------------------------------------------------------------------- /assets/images/settings_screen_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/settings_screen_about.png -------------------------------------------------------------------------------- /assets/images/settings_screen_account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/settings_screen_account.png -------------------------------------------------------------------------------- /assets/images/settings_screen_cache_manager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/settings_screen_cache_manager.png -------------------------------------------------------------------------------- /assets/images/settings_screen_donate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/settings_screen_donate.png -------------------------------------------------------------------------------- /assets/images/settings_screen_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/settings_screen_download.png -------------------------------------------------------------------------------- /assets/images/settings_screen_player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/settings_screen_player.png -------------------------------------------------------------------------------- /assets/images/settings_screen_privacy_policy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/assets/images/settings_screen_privacy_policy.png -------------------------------------------------------------------------------- /generateKeys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/generateKeys -------------------------------------------------------------------------------- /github/android_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/github/android_github.png -------------------------------------------------------------------------------- /github/appstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/github/appstore.png -------------------------------------------------------------------------------- /github/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/github/banner.jpg -------------------------------------------------------------------------------- /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 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '12.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 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.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.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ios/Runner/AppSupportFiles/license.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN ALI VIDEO CERT----- 2 | LmlsQS5jaUwAAWRjY2FhYTU1OTAxNzE0NDg2OWJlOGJkNzczZTc5ZjAzM2YwMDhiO 3 | WY5ODUwNTc5MGY4NDEyOTRiMzNjMmZiYjg1NGUxZThlNjAwNzRmNTgxZTU0MDY2Mj 4 | RiMGFiM2JkNWVmOTE3ZDE0MDJlNDQ0ZDUwNmExMTc5ZjFlYjYyODQ2MDRiYzdiYjA 5 | zOTI2ZjYyOTE1OWVjYjY0ZDk1ZDhhN2Q5ZWZlOTRjOTdkMTA0Yzc1MWU5OGEwNGY3 6 | OTdkOTdiYTAzMWEyMDFlMzc2Mjg0NGI1MTEyYWRkZDQzNTgyZDA2NTJkYTk0MDk1Y 7 | TIxYjY2NWJmYjY0ZTkwMWQyZGNjNmVjMjY1ODFkYmJjZjBhY2ZmZjFhNDU3NTJjND 8 | QwNTMzZmJlZDk3YTIzMmMyOWQ4YWVkZDY0YmZhZDc2ZDY1MTRiZGU5MmM3YTdjMGZ 9 | iYjI3OTNhNjZiMDEzMjBkODgxYzBhMjA1YTExN2Q1YmU3ZTgyMzYyYzI5MDJhZDNk 10 | MmFiZTcxNTQ5NzI2YzI4NTVjOTc5MWVmZDVjMGU4NDZmMDZlZDhlYTY1MjgzYWUzM 11 | 2JkOTYzOWJiZTkwOGU4ZTBmY2QwNDc1OWQ5N2U3OTk1NDNhMzdkNDQ2YzZlMDJhMj 12 | BkODI2YTUzZGIzNTNjNWU3MDVjYmJmYzg5ODVjYjRkMWIxAAABj06iJAA/+Gshl5B 13 | eEiWwHuBRORrQ9Nifz09+LrM1FjMpjew1Sb4g/9DXPrpbbPp/Um6uSb+TOl9ZchoT 14 | rckfqr2AgEomg1oH2WTy5teWsYBX2dSFCWzr+qFGqtLZWFjvAID+dkh4J1zt/2GGQ 15 | Cy0ah1fJZXYdkzVK/NmRn8dL4sJnaGrr46iPTKlUvQAZZw4VRDtcYjepMWCGuUJFn 16 | WLS5uIIjYBVX7cOATAJpd+At64LG5Pvnq9NnqSo5KY/zh4p6UitA7wyOAMyzwRaEw 17 | qpo+rtR/uKVau0gGrXz+Z19ZiqFJXoOxkLJDhjXiAUzi5FjAOZmYkiuYZ57gtGcXW 18 | WrBsrfbOAAABQH18wrod6jHXVoSNhov+rpNnu59d4F1BwyVBObUfH99fA5iEJZ1AQ 19 | I1Zuu6q/98lQkRNj+iTeuFSUo8s+DYk3dkzeEsy247nzwlVjBC5/eahiOGUhTtVOV 20 | W2RmcpuuoylqDs4qhDC7on6QPJ9v3qwudKM3W+77AM2RRqpLYH87IC1JzppfTV3Ve 21 | oUzFd/e4UEANVSSJ9WgvvuGQ3cOnY+eA6ScHPGqteIL1BW3FzC06jH3E2QQ+cQqUK 22 | 1d83qTCyJ+wtXuXAxgT2qJXS/b3pP3e4MCeO+AUD8TMBzDECkPsVH4QtWvLsvEVPs 23 | AYuxy48qymnOPinlMfg5CS7/pqa5h8AAAGH9lAVYAAAAHYAAAAgZ2U3YjUyY2M3MT 24 | BmNDcwYTk5MTMyMzVmNTY4ZmRiNzYAAAACAAAAIwAAAAAAAAACAAAAF2NvbS5naXR 25 | odWIuYWxpc3QuY2xpZW50AAAAIwAAAAAAAAABAAAAF2NvbS5naXRodWIuYWxpc3Qu 26 | Y2xpZW50AAAAAgAAAF0AAAACAAAAAAAAAAEAACPxAAABj1PIgAAAAAAAQAAAAAEAA 27 | AACAAAAGAAATiEAAAGH9lAMsAAAAY9TyIAAAAAAAAAAABgAAE4iAAABh/ZQDLAAAA 28 | GPU8iAAAAAAAAAAABdAAAAAgAAAAAAAAACAAAj8QAAAY9TyIAAAAAAAEAAAAABAAA 29 | AAgAAABgAAE4hAAABh/ZQDLAAAAGPU8iAAAAAAAAAAAAYAABOIgAAAYf2UAywAAAB 30 | j1PIgAAAAAAA 31 | -----END ALI VIDEO CERT----- -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/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/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/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/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/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/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/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/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/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/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/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/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/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/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/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/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/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/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/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/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/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/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/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/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-iTunes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-iTunes.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_splash_ios.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "ic_splash_ios@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "ic_splash_ios@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /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/Assets.xcassets/LaunchImage.imageset/ic_splash_ios.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/ios/Runner/Assets.xcassets/LaunchImage.imageset/ic_splash_ios.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/ic_splash_ios@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/ios/Runner/Assets.xcassets/LaunchImage.imageset/ic_splash_ios@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/ic_splash_ios@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/ios/Runner/Assets.xcassets/LaunchImage.imageset/ic_splash_ios@3x.png -------------------------------------------------------------------------------- /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 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AlivcLicenseFile 6 | license.crt 7 | AlivcLicenseKey 8 | 7od4xPYaUwm4scy4t57cd70e56f2d4196aed4167e6e4174c9 9 | CADisableMinimumFrameDurationOnPhone 10 | 11 | CFBundleSignature 12 | ???? 13 | LSHasLocalizedDisplayName 14 | 15 | NSAppTransportSecurity 16 | 17 | NSAllowsArbitraryLoads 18 | 19 | 20 | UIViewControllerBasedStatusBarAppearance 21 | 22 | io.flutter.embedded_views_preview 23 | 24 | UIApplicationSupportsIndirectInputEvents 25 | 26 | NSPhotoLibraryUsageDescription 27 | ALClient needs permission to access photos on your device 28 | NSPhotoLibraryAddUsageDescription 29 | ALClient needs permission to add photos to your device 30 | NSCameraUsageDescription> 31 | Photo/video upload function requires you to grant camera access 32 | NSMicrophoneUsageDescription 33 | The video/recording upload feature requires you to grant microphone access 34 | UIBackgroundModes 35 | 36 | audio 37 | 38 | UIFileSharingEnabled 39 | 40 | LSSupportsOpeningDocumentsInPlace 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ios/Runner/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | InfoPlist.strings 3 | Runner 4 | 5 | Created by tangrui on 2023/6/15. 6 | 7 | */ 8 | NSPhotoLibraryUsageDescription = "Uploading pictures/videos requires you to grant access to the album"; 9 | NSCameraUsageDescription = "Photo/video upload function requires you to grant camera access"; 10 | NSMicrophoneUsageDescription = "The video/recording upload feature requires you to grant microphone access"; 11 | -------------------------------------------------------------------------------- /ios/Runner/zh-Hans.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | InfoPlist.strings 3 | Runner 4 | 5 | Created by tangrui on 2023/6/15. 6 | 7 | */ 8 | NSPhotoLibraryUsageDescription = "上传图片/视频功能需要您授予相册访问权限"; 9 | NSCameraUsageDescription = "拍照/拍视频上传功能需要您授予相机权限"; 10 | NSMicrophoneUsageDescription = "录视频/录音上传功能需要您授予麦克风权限"; 11 | -------------------------------------------------------------------------------- /ios/Runner/zh-Hans.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ios/Runner/zh-Hans.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/database/alist_database.dart: -------------------------------------------------------------------------------- 1 | // database.dart 2 | 3 | import 'dart:async'; 4 | 5 | import 'package:alist/database/dao/favorite_dao.dart'; 6 | import 'package:alist/database/dao/file_download_record_dao.dart'; 7 | import 'package:alist/database/dao/file_password_dao.dart'; 8 | import 'package:alist/database/dao/file_viewing_record_dao.dart'; 9 | import 'package:alist/database/dao/server_dao.dart'; 10 | import 'package:alist/database/table/favorite.dart'; 11 | import 'package:alist/database/table/file_download_record.dart'; 12 | import 'package:alist/database/table/file_password.dart'; 13 | import 'package:alist/database/table/file_viewing_record.dart'; 14 | import 'package:alist/database/table/server.dart'; 15 | import 'package:floor/floor.dart'; 16 | import 'package:sqflite/sqflite.dart' as sqflite; 17 | 18 | import 'dao/video_viewing_record_dao.dart'; 19 | import 'table/video_viewing_record.dart'; 20 | 21 | part 'alist_database.g.dart'; // the generated code will be there 22 | 23 | @Database(version: 5, entities: [ 24 | VideoViewingRecord, 25 | FileDownloadRecord, 26 | FilePassword, 27 | Server, 28 | FileViewingRecord, 29 | Favorite, 30 | ]) 31 | abstract class AlistDatabase extends FloorDatabase { 32 | VideoViewingRecordDao get videoViewingRecordDao; 33 | 34 | FileDownloadRecordRecordDao get downloadRecordRecordDao; 35 | 36 | FilePasswordDao get filePasswordDao; 37 | 38 | ServerDao get serverDao; 39 | 40 | FileViewingRecordDao get fileViewingRecordDao; 41 | 42 | FavoriteDao get favoriteDao; 43 | } 44 | -------------------------------------------------------------------------------- /lib/database/dao/favorite_dao.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/database/table/favorite.dart'; 2 | import 'package:floor/floor.dart'; 3 | 4 | @dao 5 | abstract class FavoriteDao { 6 | @insert 7 | Future insertRecord(Favorite favorite); 8 | 9 | @update 10 | Future updateRecord(Favorite favorite); 11 | 12 | @update 13 | Future updateRecords(List favorite); 14 | 15 | @delete 16 | Future deleteRecord(Favorite favorite); 17 | 18 | @Query( 19 | "SELECT * FROM favorite WHERE server_url = :serverUrl AND user_id=:userId AND path=:path LIMIT 1") 20 | Future findByPath( 21 | String serverUrl, 22 | String userId, 23 | String path, 24 | ); 25 | 26 | @Query( 27 | "SELECT * FROM favorite WHERE server_url = :serverUrl AND user_id=:userId ORDER BY id DESC") 28 | Stream?> list( 29 | String serverUrl, 30 | String userId, 31 | ); 32 | 33 | @Query("SELECT COUNT(id) FROM favorite") 34 | Stream countStream(); 35 | 36 | @Query( 37 | "DELETE FROM favorite WHERE server_url = :serverUrl AND user_id=:userId AND remote_path=:remotePath") 38 | Future deleteByPath( 39 | String serverUrl, 40 | String userId, 41 | String remotePath, 42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /lib/database/dao/file_download_record_dao.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/database/table/file_download_record.dart'; 2 | import 'package:floor/floor.dart'; 3 | 4 | @dao 5 | abstract class FileDownloadRecordRecordDao { 6 | @insert 7 | Future insertRecord(FileDownloadRecord record); 8 | 9 | @update 10 | Future updateRecord(FileDownloadRecord record); 11 | 12 | @delete 13 | Future deleteRecord(FileDownloadRecord record); 14 | 15 | @Query("DELETE FROM file_download_record WHERE id = :id") 16 | Future deleteById(int id); 17 | 18 | @Query( 19 | "SELECT * FROM file_download_record WHERE server_url = :serverUrl AND user_id=:userId AND sign=:sign LIMIT 1") 20 | Future findRecordBySign( 21 | String serverUrl, 22 | String userId, 23 | String sign, 24 | ); 25 | 26 | @Query( 27 | "SELECT * FROM file_download_record WHERE server_url = :serverUrl AND user_id=:userId AND remote_path=:remotePath LIMIT 1") 28 | Future findRecordByRemotePath( 29 | String serverUrl, 30 | String userId, 31 | String remotePath, 32 | ); 33 | 34 | @Query( 35 | "SELECT * FROM file_download_record WHERE server_url = :serverUrl AND user_id=:userId ORDER BY id DESC") 36 | Future?> findAll(String serverUrl, String userId); 37 | 38 | @Query( 39 | "UPDATE file_download_record SET local_path = :newLocalPath WHERE id = :id") 40 | Future updateLocalPath(int id, String newLocalPath); 41 | } 42 | -------------------------------------------------------------------------------- /lib/database/dao/file_password_dao.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/database/table/file_download_record.dart'; 2 | import 'package:alist/database/table/file_password.dart'; 3 | import 'package:floor/floor.dart'; 4 | 5 | @dao 6 | abstract class FilePasswordDao { 7 | @insert 8 | Future insertFilePassword(FilePassword filePassword); 9 | 10 | @update 11 | Future updateFilePassword(FilePassword filePassword); 12 | 13 | @delete 14 | Future deleteFilePassword(FilePassword filePassword); 15 | 16 | @Query("DELETE FROM file_password WHERE server_url = :serverUrl AND user_id=:userId AND remote_path=:remotePath") 17 | Future deleteByPath(String serverUrl, String userId, String remotePath); 18 | 19 | @Query( 20 | "SELECT * FROM file_password WHERE server_url = :serverUrl AND user_id=:userId AND remote_path=:remotePath ORDER BY id DESC LIMIT 1") 21 | Future findPasswordByPath( 22 | String serverUrl, 23 | String userId, 24 | String remotePath, 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /lib/database/dao/file_viewing_record_dao.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/database/table/file_viewing_record.dart'; 2 | import 'package:floor/floor.dart'; 3 | 4 | @dao 5 | abstract class FileViewingRecordDao { 6 | @insert 7 | Future insertRecord(FileViewingRecord record); 8 | 9 | @update 10 | Future updateRecord(FileViewingRecord record); 11 | 12 | @update 13 | Future updateRecords(List record); 14 | 15 | @delete 16 | Future deleteRecord(FileViewingRecord record); 17 | 18 | @Query( 19 | "SELECT * FROM file_viewing_record WHERE server_url = :serverUrl AND user_id=:userId ORDER BY id DESC LIMIT 100") 20 | Stream?> recordList( 21 | String serverUrl, 22 | String userId, 23 | ); 24 | 25 | @Query( 26 | "DELETE FROM file_viewing_record WHERE server_url = :serverUrl AND user_id=:userId AND remote_path=:remotePath") 27 | Future deleteByPath( 28 | String serverUrl, 29 | String userId, 30 | String remotePath, 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /lib/database/dao/server_dao.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/database/table/server.dart'; 2 | import 'package:floor/floor.dart'; 3 | 4 | @dao 5 | abstract class ServerDao { 6 | @insert 7 | Future insertServer(Server server); 8 | 9 | @update 10 | Future updateServer(Server server); 11 | 12 | @delete 13 | Future deleteServer(Server server); 14 | 15 | @Query( 16 | "SELECT * FROM server WHERE server_url = :serverUrl AND user_id=:userId LIMIT 1") 17 | Future findServer(String serverUrl, String userId); 18 | 19 | @Query("SELECT * FROM server ORDER BY id desc LIMIT 100") 20 | Stream?> serverList(); 21 | } 22 | -------------------------------------------------------------------------------- /lib/database/dao/video_viewing_record_dao.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/database/table/video_viewing_record.dart'; 2 | import 'package:floor/floor.dart'; 3 | 4 | @dao 5 | abstract class VideoViewingRecordDao { 6 | @insert 7 | Future insertRecord(VideoViewingRecord record); 8 | 9 | @update 10 | Future updateRecord(VideoViewingRecord record); 11 | 12 | @delete 13 | Future deleteRecord(VideoViewingRecord record); 14 | 15 | @Query( 16 | "SELECT * FROM video_viewing_record WHERE server_url = :serverUrl AND user_id=:userId AND path=:path LIMIT 1") 17 | Future findRecordByPath( 18 | String serverUrl, 19 | String userId, 20 | String path, 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /lib/database/table/favorite.dart: -------------------------------------------------------------------------------- 1 | import 'package:floor/floor.dart'; 2 | 3 | @Entity(tableName: "favorite") 4 | class Favorite { 5 | @PrimaryKey(autoGenerate: true) 6 | final int? id; 7 | 8 | @ColumnInfo(name: 'is_dir') 9 | final bool isDir; 10 | 11 | @ColumnInfo(name: 'server_url') 12 | final String serverUrl; 13 | 14 | @ColumnInfo(name: 'user_id') 15 | final String userId; 16 | 17 | @ColumnInfo(name: 'remote_path') 18 | final String remotePath; 19 | 20 | @ColumnInfo(name: 'name') 21 | final String name; 22 | 23 | @ColumnInfo(name: 'size') 24 | final int size; 25 | 26 | @ColumnInfo(name: 'sign') 27 | final String? sign; 28 | 29 | @ColumnInfo(name: 'thumb') 30 | final String? thumb; 31 | 32 | @ColumnInfo(name: 'modified') 33 | final int modified; 34 | 35 | @ColumnInfo(name: 'provider') 36 | final String provider; 37 | 38 | @ColumnInfo(name: 'create_time') 39 | final int createTime; 40 | 41 | @ColumnInfo(name: 'path') 42 | final String path; 43 | 44 | Favorite({ 45 | this.id, 46 | required this.isDir, 47 | required this.serverUrl, 48 | required this.userId, 49 | required this.remotePath, 50 | required this.name, 51 | required this.path, 52 | required this.size, 53 | required this.sign, 54 | required this.thumb, 55 | required this.modified, 56 | required this.provider, 57 | required this.createTime, 58 | }); 59 | } 60 | -------------------------------------------------------------------------------- /lib/database/table/file_download_record.dart: -------------------------------------------------------------------------------- 1 | import 'package:floor/floor.dart'; 2 | 3 | @Entity(tableName: "file_download_record") 4 | class FileDownloadRecord { 5 | @PrimaryKey(autoGenerate: true) 6 | int? id; 7 | 8 | @ColumnInfo(name: 'server_url') 9 | final String serverUrl; 10 | 11 | @ColumnInfo(name: 'user_id') 12 | final String userId; 13 | 14 | @ColumnInfo(name: 'remote_path') 15 | final String remotePath; 16 | 17 | @ColumnInfo(name: 'sign') 18 | final String sign; 19 | 20 | @ColumnInfo(name: 'name') 21 | final String name; 22 | 23 | @ColumnInfo(name: 'local_path') 24 | final String localPath; 25 | 26 | @ColumnInfo(name: 'create_time') 27 | final int createTime; 28 | 29 | @ColumnInfo(name: 'thumbnail') 30 | final String? thumbnail; 31 | 32 | @ColumnInfo(name: 'request_headers') 33 | final String? requestHeaders; 34 | 35 | // 下载频率限制,单位 秒 36 | @ColumnInfo(name: 'limit_frequency') 37 | final int? limitFrequency; 38 | 39 | @ColumnInfo(name: 'finished') 40 | bool? finished; 41 | 42 | FileDownloadRecord({ 43 | this.id, 44 | required this.serverUrl, 45 | required this.userId, 46 | required this.remotePath, 47 | required this.sign, 48 | required this.name, 49 | required this.localPath, 50 | required this.createTime, 51 | required this.thumbnail, 52 | required this.requestHeaders, 53 | required this.limitFrequency, 54 | this.finished 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /lib/database/table/file_password.dart: -------------------------------------------------------------------------------- 1 | import 'package:floor/floor.dart'; 2 | 3 | @Entity(tableName: "file_password") 4 | class FilePassword { 5 | @PrimaryKey(autoGenerate: true) 6 | final int? id; 7 | 8 | @ColumnInfo(name: 'server_url') 9 | final String serverUrl; 10 | 11 | @ColumnInfo(name: 'user_id') 12 | final String userId; 13 | 14 | @ColumnInfo(name: 'remote_path') 15 | final String remotePath; 16 | 17 | @ColumnInfo(name: 'password') 18 | final String password; 19 | 20 | @ColumnInfo(name: 'create_time') 21 | final int createTime; 22 | 23 | FilePassword({ 24 | this.id, 25 | required this.serverUrl, 26 | required this.userId, 27 | required this.remotePath, 28 | required this.password, 29 | required this.createTime, 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /lib/database/table/file_viewing_record.dart: -------------------------------------------------------------------------------- 1 | import 'package:floor/floor.dart'; 2 | 3 | @Entity(tableName: "file_viewing_record") 4 | class FileViewingRecord { 5 | @PrimaryKey(autoGenerate: true) 6 | final int? id; 7 | 8 | @ColumnInfo(name: 'server_url') 9 | final String serverUrl; 10 | 11 | @ColumnInfo(name: 'user_id') 12 | final String userId; 13 | 14 | @ColumnInfo(name: 'remote_path') 15 | final String remotePath; 16 | 17 | @ColumnInfo(name: 'name') 18 | final String name; 19 | 20 | @ColumnInfo(name: 'size') 21 | final int size; 22 | 23 | @ColumnInfo(name: 'sign') 24 | final String? sign; 25 | 26 | @ColumnInfo(name: 'thumb') 27 | final String? thumb; 28 | 29 | @ColumnInfo(name: 'modified') 30 | final int modified; 31 | 32 | @ColumnInfo(name: 'provider') 33 | final String provider; 34 | 35 | @ColumnInfo(name: 'create_time') 36 | final int createTime; 37 | 38 | @ColumnInfo(name: 'path') 39 | final String path; 40 | 41 | FileViewingRecord({ 42 | this.id, 43 | required this.serverUrl, 44 | required this.userId, 45 | required this.remotePath, 46 | required this.name, 47 | required this.path, 48 | required this.size, 49 | required this.sign, 50 | required this.thumb, 51 | required this.modified, 52 | required this.provider, 53 | required this.createTime, 54 | }); 55 | } 56 | -------------------------------------------------------------------------------- /lib/database/table/server.dart: -------------------------------------------------------------------------------- 1 | import 'package:floor/floor.dart'; 2 | 3 | @Entity(tableName: "server") 4 | class Server { 5 | @PrimaryKey(autoGenerate: true) 6 | final int? id; 7 | 8 | @ColumnInfo(name: 'name') 9 | final String name; 10 | 11 | @ColumnInfo(name: 'server_url') 12 | final String serverUrl; 13 | 14 | @ColumnInfo(name: 'user_id') 15 | final String userId; 16 | 17 | @ColumnInfo(name: 'password') 18 | final String password; 19 | 20 | @ColumnInfo(name: 'token') 21 | final String token; 22 | 23 | @ColumnInfo(name: 'guest') 24 | final bool guest; 25 | 26 | @ColumnInfo(name: 'ignore_ssl_error') 27 | final bool ignoreSSLError; 28 | 29 | @ColumnInfo(name: 'create_time') 30 | final int createTime; 31 | 32 | @ColumnInfo(name: 'update_time') 33 | final int updateTime; 34 | 35 | Server({ 36 | this.id, 37 | required this.name, 38 | required this.serverUrl, 39 | required this.userId, 40 | required this.password, 41 | required this.token, 42 | required this.guest, 43 | required this.ignoreSSLError, 44 | required this.createTime, 45 | required this.updateTime, 46 | }); 47 | } 48 | -------------------------------------------------------------------------------- /lib/database/table/video_viewing_record.dart: -------------------------------------------------------------------------------- 1 | import 'package:floor/floor.dart'; 2 | 3 | @Entity(tableName: "video_viewing_record") 4 | class VideoViewingRecord { 5 | @PrimaryKey(autoGenerate: true) 6 | final int? id; 7 | 8 | @ColumnInfo(name: 'server_url') 9 | final String serverUrl; 10 | 11 | @ColumnInfo(name: 'user_id') 12 | final String userId; 13 | 14 | @ColumnInfo(name: 'video_sign') 15 | final String videoSign; 16 | 17 | @ColumnInfo(name: 'path') 18 | final String path; 19 | 20 | @ColumnInfo(name: 'video_duration') 21 | final int videoDuration; 22 | 23 | @ColumnInfo(name: 'video_current_position') 24 | final int videoCurrentPosition; 25 | 26 | VideoViewingRecord({ 27 | this.id, 28 | required this.serverUrl, 29 | required this.userId, 30 | required this.videoSign, 31 | required this.path, 32 | required this.videoDuration, 33 | required this.videoCurrentPosition, 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /lib/entity/app_version_resp.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_field.dart'; 2 | import 'package:alist/generated/json/app_version_resp.g.dart'; 3 | import 'dart:convert'; 4 | 5 | @JsonSerializable() 6 | class AppVersionResp { 7 | late String updates; 8 | late AppVersionRespAndroid android; 9 | late AppVersionRespIos ios; 10 | 11 | AppVersionResp(); 12 | 13 | factory AppVersionResp.fromJson(Map json) => $AppVersionRespFromJson(json); 14 | 15 | Map toJson() => $AppVersionRespToJson(this); 16 | 17 | @override 18 | String toString() { 19 | return jsonEncode(this); 20 | } 21 | } 22 | 23 | @JsonSerializable() 24 | class AppVersionRespAndroid { 25 | late String version; 26 | late String githubUrl; 27 | late String googlePlayUrl; 28 | 29 | AppVersionRespAndroid(); 30 | 31 | factory AppVersionRespAndroid.fromJson(Map json) => $AppVersionRespAndroidFromJson(json); 32 | 33 | Map toJson() => $AppVersionRespAndroidToJson(this); 34 | 35 | @override 36 | String toString() { 37 | return jsonEncode(this); 38 | } 39 | } 40 | 41 | @JsonSerializable() 42 | class AppVersionRespIos { 43 | late String version; 44 | late String appStoreUrl; 45 | 46 | AppVersionRespIos(); 47 | 48 | factory AppVersionRespIos.fromJson(Map json) => $AppVersionRespIosFromJson(json); 49 | 50 | Map toJson() => $AppVersionRespIosToJson(this); 51 | 52 | @override 53 | String toString() { 54 | return jsonEncode(this); 55 | } 56 | } -------------------------------------------------------------------------------- /lib/entity/copy_move_req.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_field.dart'; 2 | import 'package:alist/generated/json/copy_move_req.g.dart'; 3 | import 'dart:convert'; 4 | 5 | @JsonSerializable() 6 | class CopyMoveReq { 7 | @JSONField(name: "src_dir") 8 | late String srcDir; 9 | @JSONField(name: "dst_dir") 10 | late String dstDir; 11 | late List names; 12 | 13 | CopyMoveReq(); 14 | 15 | factory CopyMoveReq.fromJson(Map json) => $CopyMoveReqFromJson(json); 16 | 17 | Map toJson() => $CopyMoveReqToJson(this); 18 | 19 | @override 20 | String toString() { 21 | return jsonEncode(this); 22 | } 23 | } -------------------------------------------------------------------------------- /lib/entity/donate_config_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_field.dart'; 2 | import 'package:alist/generated/json/donate_config_entity.g.dart'; 3 | import 'dart:convert'; 4 | 5 | @JsonSerializable() 6 | class DonateConfigEntity { 7 | late String wechat; 8 | @JSONField(name: "wechat_small") 9 | late String wechatSmall; 10 | late String alipay; 11 | @JSONField(name: "alipay_small") 12 | late String alipaySmall; 13 | 14 | DonateConfigEntity(); 15 | 16 | factory DonateConfigEntity.fromJson(Map json) => $DonateConfigEntityFromJson(json); 17 | 18 | Map toJson() => $DonateConfigEntityToJson(this); 19 | 20 | @override 21 | String toString() { 22 | return jsonEncode(this); 23 | } 24 | } -------------------------------------------------------------------------------- /lib/entity/downloads_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_field.dart'; 2 | import 'package:alist/generated/json/downloads_info.g.dart'; 3 | import 'dart:convert'; 4 | 5 | @JsonSerializable() 6 | class DownloadsInfo { 7 | late bool isSupportRange; 8 | late bool decompress; 9 | String? lastModified; 10 | String? etag; 11 | int? contentLength; 12 | 13 | DownloadsInfo(); 14 | 15 | factory DownloadsInfo.fromJson(Map json) => 16 | $DownloadsInfoFromJson(json); 17 | 18 | Map toJson() => $DownloadsInfoToJson(this); 19 | 20 | @override 21 | String toString() { 22 | return jsonEncode(this); 23 | } 24 | } -------------------------------------------------------------------------------- /lib/entity/file_info_resp_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_field.dart'; 2 | import 'package:alist/generated/json/file_info_resp_entity.g.dart'; 3 | import 'dart:convert'; 4 | 5 | @JsonSerializable() 6 | class FileInfoRespEntity { 7 | late String name; 8 | late int size; 9 | @JSONField(name: "is_dir") 10 | late bool isDir; 11 | late String modified; 12 | late String sign; 13 | late String thumb; 14 | late int type; 15 | @JSONField(name: "raw_url") 16 | late String rawUrl; 17 | late String readme; 18 | late String provider; 19 | dynamic related; 20 | 21 | FileInfoRespEntity(); 22 | 23 | factory FileInfoRespEntity.fromJson(Map json) => $FileInfoRespEntityFromJson(json); 24 | 25 | Map toJson() => $FileInfoRespEntityToJson(this); 26 | 27 | @override 28 | String toString() { 29 | return jsonEncode(this); 30 | } 31 | } -------------------------------------------------------------------------------- /lib/entity/file_list_resp_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_field.dart'; 2 | import 'package:alist/generated/json/file_list_resp_entity.g.dart'; 3 | import 'dart:convert'; 4 | 5 | @JsonSerializable() 6 | class FileListRespEntity { 7 | List? content; 8 | late int total; 9 | late String readme; 10 | late bool write; 11 | late String provider; 12 | 13 | FileListRespEntity(); 14 | 15 | factory FileListRespEntity.fromJson(Map json) => $FileListRespEntityFromJson(json); 16 | 17 | Map toJson() => $FileListRespEntityToJson(this); 18 | 19 | @override 20 | String toString() { 21 | return jsonEncode(this); 22 | } 23 | } 24 | 25 | @JsonSerializable() 26 | class FileListRespContent { 27 | late String name; 28 | int? size; 29 | @JSONField(name: "is_dir") 30 | late bool isDir; 31 | late String modified; 32 | late String sign; 33 | late String thumb; 34 | late int type; 35 | String? readme; 36 | 37 | FileListRespContent(); 38 | 39 | factory FileListRespContent.fromJson(Map json) => $FileListRespContentFromJson(json); 40 | 41 | Map toJson() => $FileListRespContentToJson(this); 42 | 43 | @override 44 | String toString() { 45 | return jsonEncode(this); 46 | } 47 | } -------------------------------------------------------------------------------- /lib/entity/file_remove_req.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_field.dart'; 2 | import 'package:alist/generated/json/file_remove_req.g.dart'; 3 | import 'dart:convert'; 4 | 5 | @JsonSerializable() 6 | class FileRemoveReq { 7 | late String dir; 8 | late List names; 9 | 10 | FileRemoveReq(); 11 | 12 | factory FileRemoveReq.fromJson(Map json) => $FileRemoveReqFromJson(json); 13 | 14 | Map toJson() => $FileRemoveReqToJson(this); 15 | 16 | @override 17 | String toString() { 18 | return jsonEncode(this); 19 | } 20 | } -------------------------------------------------------------------------------- /lib/entity/file_rename_req.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_field.dart'; 2 | import 'package:alist/generated/json/file_rename_req.g.dart'; 3 | import 'dart:convert'; 4 | 5 | @JsonSerializable() 6 | class FileRenameReq { 7 | late String path; 8 | late String name; 9 | 10 | FileRenameReq(); 11 | 12 | factory FileRenameReq.fromJson(Map json) => $FileRenameReqFromJson(json); 13 | 14 | Map toJson() => $FileRenameReqToJson(this); 15 | 16 | @override 17 | String toString() { 18 | return jsonEncode(this); 19 | } 20 | } -------------------------------------------------------------------------------- /lib/entity/file_search_resp.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_field.dart'; 2 | import 'package:alist/generated/json/file_search_resp.g.dart'; 3 | import 'dart:convert'; 4 | export 'package:alist/generated/json/file_search_resp.g.dart'; 5 | 6 | @JsonSerializable() 7 | class FileSearchResp { 8 | List? content; 9 | int? total; 10 | 11 | FileSearchResp(); 12 | 13 | factory FileSearchResp.fromJson(Map json) => $FileSearchRespFromJson(json); 14 | 15 | Map toJson() => $FileSearchRespToJson(this); 16 | 17 | @override 18 | String toString() { 19 | return jsonEncode(this); 20 | } 21 | } 22 | 23 | @JsonSerializable() 24 | class FileSearchRespContent { 25 | String? parent; 26 | String? name; 27 | @JSONField(name: "is_dir") 28 | bool? isDir; 29 | int? size; 30 | int? type; 31 | 32 | FileSearchRespContent(); 33 | 34 | factory FileSearchRespContent.fromJson(Map json) => $FileSearchRespContentFromJson(json); 35 | 36 | Map toJson() => $FileSearchRespContentToJson(this); 37 | 38 | @override 39 | String toString() { 40 | return jsonEncode(this); 41 | } 42 | } -------------------------------------------------------------------------------- /lib/entity/http_result.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_convert_content.dart'; 2 | 3 | class HttpResult { 4 | late int code; 5 | late String message; 6 | T? data; 7 | 8 | HttpResult(this.code, this.message, this.data); 9 | 10 | HttpResult.fromJson(Map json) { 11 | code = json["code"] as int; 12 | message = json["message"] as String; 13 | if (json.containsKey("data")) { 14 | data = _generateData(json["data"]); 15 | } 16 | } 17 | 18 | T? _generateData(dynamic json) { 19 | if (json == null) { 20 | return null; 21 | } else if (T.toString() == 'String') { 22 | return json.toString() as T; 23 | } else if (T.toString() == 'Map') { 24 | return json as T; 25 | } else { 26 | return JsonConvert.fromJsonAsT(json); 27 | } 28 | } 29 | 30 | bool isSuccessful() { 31 | return code == 200; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/entity/login_resp_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_field.dart'; 2 | import 'package:alist/generated/json/login_resp_entity.g.dart'; 3 | import 'dart:convert'; 4 | 5 | @JsonSerializable() 6 | class LoginRespEntity { 7 | late String token; 8 | 9 | LoginRespEntity(); 10 | 11 | factory LoginRespEntity.fromJson(Map json) => $LoginRespEntityFromJson(json); 12 | 13 | Map toJson() => $LoginRespEntityToJson(this); 14 | 15 | @override 16 | String toString() { 17 | return jsonEncode(this); 18 | } 19 | } -------------------------------------------------------------------------------- /lib/entity/mkdir_req.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_field.dart'; 2 | import 'package:alist/generated/json/mkdir_req.g.dart'; 3 | import 'dart:convert'; 4 | 5 | @JsonSerializable() 6 | class MkdirReq { 7 | late String path; 8 | 9 | MkdirReq(); 10 | 11 | factory MkdirReq.fromJson(Map json) => $MkdirReqFromJson(json); 12 | 13 | Map toJson() => $MkdirReqToJson(this); 14 | 15 | @override 16 | String toString() { 17 | return jsonEncode(this); 18 | } 19 | } -------------------------------------------------------------------------------- /lib/entity/my_info_resp.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_field.dart'; 2 | import 'package:alist/generated/json/my_info_resp.g.dart'; 3 | import 'dart:convert'; 4 | 5 | @JsonSerializable() 6 | class MyInfoResp { 7 | late int id; 8 | late String username; 9 | late String password; 10 | @JSONField(name: "base_path") 11 | String basePath = ""; 12 | int role = 0; 13 | bool disabled = false; 14 | int permission = -1; 15 | @JSONField(name: "sso_id") 16 | String ssoId = ""; 17 | bool otp = false; 18 | 19 | MyInfoResp(); 20 | 21 | factory MyInfoResp.fromJson(Map json) => $MyInfoRespFromJson(json); 22 | 23 | Map toJson() => $MyInfoRespToJson(this); 24 | 25 | @override 26 | String toString() { 27 | return jsonEncode(this); 28 | } 29 | } -------------------------------------------------------------------------------- /lib/entity/player_resolve_info_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_field.dart'; 2 | import 'package:alist/generated/json/player_resolve_info_entity.g.dart'; 3 | import 'dart:convert'; 4 | export 'package:alist/generated/json/player_resolve_info_entity.g.dart'; 5 | 6 | @JsonSerializable() 7 | class ExternalPlayerEntity { 8 | late String packageName; 9 | late String activity; 10 | late String label; 11 | late String icon; 12 | 13 | ExternalPlayerEntity(); 14 | 15 | factory ExternalPlayerEntity.fromJson(Map json) => $ExternalPlayerEntityFromJson(json); 16 | 17 | Map toJson() => $ExternalPlayerEntityToJson(this); 18 | 19 | @override 20 | String toString() { 21 | return jsonEncode(this); 22 | } 23 | } -------------------------------------------------------------------------------- /lib/entity/public_settings_resp.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_field.dart'; 2 | import 'package:alist/generated/json/public_settings_resp.g.dart'; 3 | import 'dart:convert'; 4 | export 'package:alist/generated/json/public_settings_resp.g.dart'; 5 | 6 | @JsonSerializable() 7 | class PublicSettingsResp { 8 | @JSONField(name: "allow_indexed") 9 | String? allowIndexed; 10 | @JSONField(name: "allow_mounted") 11 | String? allowMounted; 12 | String? announcement; 13 | @JSONField(name: "audio_autoplay") 14 | String? audioAutoplay; 15 | @JSONField(name: "audio_cover") 16 | String? audioCover; 17 | @JSONField(name: "auto_update_index") 18 | String? autoUpdateIndex; 19 | @JSONField(name: "default_page_size") 20 | String? defaultPageSize; 21 | @JSONField(name: "external_previews") 22 | String? externalPreviews; 23 | String? favicon; 24 | @JSONField(name: "filename_char_mapping") 25 | String? filenameCharMapping; 26 | @JSONField(name: "forward_direct_link_params") 27 | String? forwardDirectLinkParams; 28 | @JSONField(name: "hide_files") 29 | String? hideFiles; 30 | @JSONField(name: "home_container") 31 | String? homeContainer; 32 | @JSONField(name: "home_icon") 33 | String? homeIcon; 34 | @JSONField(name: "iframe_previews") 35 | String? iframePreviews; 36 | String? logo; 37 | @JSONField(name: "main_color") 38 | String? mainColor; 39 | @JSONField(name: "ocr_api") 40 | String? ocrApi; 41 | @JSONField(name: "package_download") 42 | String? packageDownload; 43 | @JSONField(name: "pagination_type") 44 | String? paginationType; 45 | @JSONField(name: "robots_txt") 46 | String? robotsTxt; 47 | @JSONField(name: "search_index") 48 | String? searchIndex; 49 | @JSONField(name: "settings_layout") 50 | String? settingsLayout; 51 | @JSONField(name: "site_title") 52 | String? siteTitle; 53 | @JSONField(name: "sso_login_enabled") 54 | String? ssoLoginEnabled; 55 | @JSONField(name: "sso_login_platform") 56 | String? ssoLoginPlatform; 57 | String? version; 58 | @JSONField(name: "video_autoplay") 59 | String? videoAutoplay; 60 | 61 | PublicSettingsResp(); 62 | 63 | factory PublicSettingsResp.fromJson(Map json) => $PublicSettingsRespFromJson(json); 64 | 65 | Map toJson() => $PublicSettingsRespToJson(this); 66 | 67 | @override 68 | String toString() { 69 | return jsonEncode(this); 70 | } 71 | } -------------------------------------------------------------------------------- /lib/generated/color_schemes.g.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | const lightColorScheme = ColorScheme( 4 | brightness: Brightness.light, 5 | primary: Color(0xFF0060A9), 6 | onPrimary: Color(0xFFFFFFFF), 7 | primaryContainer: Color(0xFFD3E4FF), 8 | onPrimaryContainer: Color(0xFF001C38), 9 | secondary: Color(0xFF006A64), 10 | onSecondary: Color(0xFFFFFFFF), 11 | secondaryContainer: Color(0xFF71F7EC), 12 | onSecondaryContainer: Color(0xFF00201E), 13 | tertiary: Color(0xFF6C5677), 14 | onTertiary: Color(0xFFFFFFFF), 15 | tertiaryContainer: Color(0xFFF5D9FF), 16 | onTertiaryContainer: Color(0xFF261431), 17 | error: Color(0xFFBA1A1A), 18 | errorContainer: Color(0xFFFFDAD6), 19 | onError: Color(0xFFFFFFFF), 20 | onErrorContainer: Color(0xFF410002), 21 | background: Color(0xFFFDFCFF), 22 | onBackground: Color(0xFF1A1C1E), 23 | surface: Color(0xFFFDFCFF), 24 | onSurface: Color(0xFF1A1C1E), 25 | surfaceVariant: Color(0xFFDFE2EB), 26 | onSurfaceVariant: Color(0xFF43474E), 27 | outline: Color(0xFF73777F), 28 | onInverseSurface: Color(0xFFF1F0F4), 29 | inverseSurface: Color(0xFF2F3033), 30 | inversePrimary: Color(0xFFA2C9FF), 31 | shadow: Color(0xFF000000), 32 | surfaceTint: Color(0xFF0060A9), 33 | outlineVariant: Color(0xFFC3C6CF), 34 | scrim: Color(0xFF000000), 35 | ); 36 | 37 | const darkColorScheme = ColorScheme( 38 | brightness: Brightness.dark, 39 | primary: Color(0xFFA2C9FF), 40 | onPrimary: Color(0xFF00315B), 41 | primaryContainer: Color(0xFF004881), 42 | onPrimaryContainer: Color(0xFFD3E4FF), 43 | secondary: Color(0xFF50DBD0), 44 | onSecondary: Color(0xFF003734), 45 | secondaryContainer: Color(0xFF00504B), 46 | onSecondaryContainer: Color(0xFF71F7EC), 47 | tertiary: Color(0xFFD8BDE3), 48 | onTertiary: Color(0xFF3C2947), 49 | tertiaryContainer: Color(0xFF533F5E), 50 | onTertiaryContainer: Color(0xFFF5D9FF), 51 | error: Color(0xFFFFB4AB), 52 | errorContainer: Color(0xFF93000A), 53 | onError: Color(0xFF690005), 54 | onErrorContainer: Color(0xFFFFDAD6), 55 | background: Color(0xFF111111), 56 | onBackground: Color(0xFFE3E2E6), 57 | surface: Color(0xFF111111), 58 | onSurface: Color(0xFFE3E2E6), 59 | surfaceVariant: Color(0xFF43474E), 60 | onSurfaceVariant: Color(0xFFC3C6CF), 61 | outline: Color(0xFF8D9199), 62 | onInverseSurface: Color(0xFF111111), 63 | inverseSurface: Color(0xFFE3E2E6), 64 | inversePrimary: Color(0xFF0060A9), 65 | shadow: Color(0xFF000000), 66 | surfaceTint: Color(0xFFA2C9FF), 67 | outlineVariant: Color(0xFF43474E), 68 | scrim: Color(0xFF000000), 69 | ); 70 | -------------------------------------------------------------------------------- /lib/generated/images.dart: -------------------------------------------------------------------------------- 1 | class Images { 2 | static const String accountIcon = 'assets/images/account_icon.png'; 3 | static const String accountIconChoosed = 'assets/images/account_icon_choosed.png'; 4 | static const String fileTypeApk = 'assets/images/file_type_apk.png'; 5 | static const String fileTypeAudio = 'assets/images/file_type_audio.png'; 6 | static const String fileTypeCode = 'assets/images/file_type_code.png'; 7 | static const String fileTypeDocment = 'assets/images/file_type_docment.png'; 8 | static const String fileTypeExcel = 'assets/images/file_type_excel.png'; 9 | static const String fileTypeFolder = 'assets/images/file_type_folder.png'; 10 | static const String fileTypeImage = 'assets/images/file_type_image.png'; 11 | static const String fileTypeMd = 'assets/images/file_type_md.png'; 12 | static const String fileTypePdf = 'assets/images/file_type_pdf.png'; 13 | static const String fileTypePpt = 'assets/images/file_type_ppt.png'; 14 | static const String fileTypeUnknow = 'assets/images/file_type_unknow.png'; 15 | static const String fileTypeVideo = 'assets/images/file_type_video.png'; 16 | static const String fileTypeWord = 'assets/images/file_type_word.png'; 17 | static const String fileTypeZip = 'assets/images/file_type_zip.png'; 18 | static const String icInfuse = 'assets/images/ic_infuse.png'; 19 | static const String icLauncher = 'assets/images/ic_launcher.png'; 20 | static const String icNplayer = 'assets/images/ic_nplayer.png'; 21 | static const String icVlc = 'assets/images/ic_vlc.png'; 22 | static const String iconArrowRight = 'assets/images/icon_arrow_right.png'; 23 | static const String iconFfwd = 'assets/images/icon_ffwd.png'; 24 | static const String loginScreenAccount = 'assets/images/login_screen_account.png'; 25 | static const String loginScreenPassword = 'assets/images/login_screen_password.png'; 26 | static const String loginScreenServerUrl = 'assets/images/login_screen_server_url.png'; 27 | static const String logo = 'assets/images/logo.png'; 28 | static const String settingsScreenAbout = 'assets/images/settings_screen_about.png'; 29 | static const String settingsScreenAccount = 'assets/images/settings_screen_account.png'; 30 | static const String settingsScreenCacheManager = 'assets/images/settings_screen_cache_manager.png'; 31 | static const String settingsScreenDonate = 'assets/images/settings_screen_donate.png'; 32 | static const String settingsScreenDownload = 'assets/images/settings_screen_download.png'; 33 | static const String settingsScreenPlayer = 'assets/images/settings_screen_player.png'; 34 | static const String settingsScreenPrivacyPolicy = 'assets/images/settings_screen_privacy_policy.png'; 35 | } 36 | -------------------------------------------------------------------------------- /lib/generated/json/base/json_field.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: non_constant_identifier_names 2 | // ignore_for_file: camel_case_types 3 | // ignore_for_file: prefer_single_quotes 4 | 5 | // This file is automatically generated. DO NOT EDIT, all your changes would be lost. 6 | 7 | import 'package:meta/meta_meta.dart'; 8 | 9 | @Target({TargetKind.classType}) 10 | class JsonSerializable { 11 | const JsonSerializable(); 12 | } 13 | 14 | @Target({TargetKind.field}) 15 | class JSONField { 16 | //Specify the parse field name 17 | final String? name; 18 | 19 | //Whether to participate in toJson 20 | final bool? serialize; 21 | 22 | //Whether to participate in fromMap 23 | final bool? deserialize; 24 | 25 | //Whether to participate in copyWith 26 | final bool? copyWith; 27 | 28 | //Enumeration or not 29 | final bool? isEnum; 30 | 31 | const JSONField({this.name, this.serialize, this.deserialize, this.isEnum, this.copyWith}); 32 | } 33 | -------------------------------------------------------------------------------- /lib/generated/json/copy_move_req.g.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_convert_content.dart'; 2 | import 'package:alist/entity/copy_move_req.dart'; 3 | 4 | CopyMoveReq $CopyMoveReqFromJson(Map json) { 5 | final CopyMoveReq copyMoveReq = CopyMoveReq(); 6 | final String? srcDir = jsonConvert.convert(json['src_dir']); 7 | if (srcDir != null) { 8 | copyMoveReq.srcDir = srcDir; 9 | } 10 | final String? dstDir = jsonConvert.convert(json['dst_dir']); 11 | if (dstDir != null) { 12 | copyMoveReq.dstDir = dstDir; 13 | } 14 | final List? names = (json['names'] as List?)?.map( 15 | (e) => jsonConvert.convert(e) as String).toList(); 16 | if (names != null) { 17 | copyMoveReq.names = names; 18 | } 19 | return copyMoveReq; 20 | } 21 | 22 | Map $CopyMoveReqToJson(CopyMoveReq entity) { 23 | final Map data = {}; 24 | data['src_dir'] = entity.srcDir; 25 | data['dst_dir'] = entity.dstDir; 26 | data['names'] = entity.names; 27 | return data; 28 | } 29 | 30 | extension CopyMoveReqExtension on CopyMoveReq { 31 | CopyMoveReq copyWith({ 32 | String? srcDir, 33 | String? dstDir, 34 | List? names, 35 | }) { 36 | return CopyMoveReq() 37 | ..srcDir = srcDir ?? this.srcDir 38 | ..dstDir = dstDir ?? this.dstDir 39 | ..names = names ?? this.names; 40 | } 41 | } -------------------------------------------------------------------------------- /lib/generated/json/donate_config_entity.g.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_convert_content.dart'; 2 | import 'package:alist/entity/donate_config_entity.dart'; 3 | 4 | DonateConfigEntity $DonateConfigEntityFromJson(Map json) { 5 | final DonateConfigEntity donateConfigEntity = DonateConfigEntity(); 6 | final String? wechat = jsonConvert.convert(json['wechat']); 7 | if (wechat != null) { 8 | donateConfigEntity.wechat = wechat; 9 | } 10 | final String? wechatSmall = jsonConvert.convert(json['wechat_small']); 11 | if (wechatSmall != null) { 12 | donateConfigEntity.wechatSmall = wechatSmall; 13 | } 14 | final String? alipay = jsonConvert.convert(json['alipay']); 15 | if (alipay != null) { 16 | donateConfigEntity.alipay = alipay; 17 | } 18 | final String? alipaySmall = jsonConvert.convert(json['alipay_small']); 19 | if (alipaySmall != null) { 20 | donateConfigEntity.alipaySmall = alipaySmall; 21 | } 22 | return donateConfigEntity; 23 | } 24 | 25 | Map $DonateConfigEntityToJson(DonateConfigEntity entity) { 26 | final Map data = {}; 27 | data['wechat'] = entity.wechat; 28 | data['wechat_small'] = entity.wechatSmall; 29 | data['alipay'] = entity.alipay; 30 | data['alipay_small'] = entity.alipaySmall; 31 | return data; 32 | } 33 | 34 | extension DonateConfigEntityExtension on DonateConfigEntity { 35 | DonateConfigEntity copyWith({ 36 | String? wechat, 37 | String? wechatSmall, 38 | String? alipay, 39 | String? alipaySmall, 40 | }) { 41 | return DonateConfigEntity() 42 | ..wechat = wechat ?? this.wechat 43 | ..wechatSmall = wechatSmall ?? this.wechatSmall 44 | ..alipay = alipay ?? this.alipay 45 | ..alipaySmall = alipaySmall ?? this.alipaySmall; 46 | } 47 | } -------------------------------------------------------------------------------- /lib/generated/json/downloads_info.g.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_convert_content.dart'; 2 | import 'package:alist/entity/downloads_info.dart'; 3 | 4 | DownloadsInfo $DownloadsInfoFromJson(Map json) { 5 | final DownloadsInfo downloadsInfo = DownloadsInfo(); 6 | final bool? isSupportRange = jsonConvert.convert( 7 | json['isSupportRange']); 8 | if (isSupportRange != null) { 9 | downloadsInfo.isSupportRange = isSupportRange; 10 | } 11 | final bool? decompress = jsonConvert.convert(json['decompress']); 12 | if (decompress != null) { 13 | downloadsInfo.decompress = decompress; 14 | } 15 | final String? lastModified = jsonConvert.convert( 16 | json['lastModified']); 17 | if (lastModified != null) { 18 | downloadsInfo.lastModified = lastModified; 19 | } 20 | final String? etag = jsonConvert.convert(json['etag']); 21 | if (etag != null) { 22 | downloadsInfo.etag = etag; 23 | } 24 | final int? contentLength = jsonConvert.convert(json['contentLength']); 25 | if (contentLength != null) { 26 | downloadsInfo.contentLength = contentLength; 27 | } 28 | return downloadsInfo; 29 | } 30 | 31 | Map $DownloadsInfoToJson(DownloadsInfo entity) { 32 | final Map data = {}; 33 | data['isSupportRange'] = entity.isSupportRange; 34 | data['decompress'] = entity.decompress; 35 | data['lastModified'] = entity.lastModified; 36 | data['etag'] = entity.etag; 37 | data['contentLength'] = entity.contentLength; 38 | return data; 39 | } 40 | 41 | extension DownloadsInfoExtension on DownloadsInfo { 42 | DownloadsInfo copyWith({ 43 | bool? isSupportRange, 44 | bool? decompress, 45 | String? lastModified, 46 | String? etag, 47 | int? contentLength, 48 | }) { 49 | return DownloadsInfo() 50 | ..isSupportRange = isSupportRange ?? this.isSupportRange 51 | ..decompress = decompress ?? this.decompress 52 | ..lastModified = lastModified ?? this.lastModified 53 | ..etag = etag ?? this.etag 54 | ..contentLength = contentLength ?? this.contentLength; 55 | } 56 | } -------------------------------------------------------------------------------- /lib/generated/json/file_remove_req.g.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_convert_content.dart'; 2 | import 'package:alist/entity/file_remove_req.dart'; 3 | 4 | FileRemoveReq $FileRemoveReqFromJson(Map json) { 5 | final FileRemoveReq fileRemoveReq = FileRemoveReq(); 6 | final String? dir = jsonConvert.convert(json['dir']); 7 | if (dir != null) { 8 | fileRemoveReq.dir = dir; 9 | } 10 | final List? names = (json['names'] as List?)?.map( 11 | (e) => jsonConvert.convert(e) as String).toList(); 12 | if (names != null) { 13 | fileRemoveReq.names = names; 14 | } 15 | return fileRemoveReq; 16 | } 17 | 18 | Map $FileRemoveReqToJson(FileRemoveReq entity) { 19 | final Map data = {}; 20 | data['dir'] = entity.dir; 21 | data['names'] = entity.names; 22 | return data; 23 | } 24 | 25 | extension FileRemoveReqExtension on FileRemoveReq { 26 | FileRemoveReq copyWith({ 27 | String? dir, 28 | List? names, 29 | }) { 30 | return FileRemoveReq() 31 | ..dir = dir ?? this.dir 32 | ..names = names ?? this.names; 33 | } 34 | } -------------------------------------------------------------------------------- /lib/generated/json/file_rename_req.g.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_convert_content.dart'; 2 | import 'package:alist/entity/file_rename_req.dart'; 3 | 4 | FileRenameReq $FileRenameReqFromJson(Map json) { 5 | final FileRenameReq fileRenameReq = FileRenameReq(); 6 | final String? path = jsonConvert.convert(json['path']); 7 | if (path != null) { 8 | fileRenameReq.path = path; 9 | } 10 | final String? name = jsonConvert.convert(json['name']); 11 | if (name != null) { 12 | fileRenameReq.name = name; 13 | } 14 | return fileRenameReq; 15 | } 16 | 17 | Map $FileRenameReqToJson(FileRenameReq entity) { 18 | final Map data = {}; 19 | data['path'] = entity.path; 20 | data['name'] = entity.name; 21 | return data; 22 | } 23 | 24 | extension FileRenameReqExtension on FileRenameReq { 25 | FileRenameReq copyWith({ 26 | String? path, 27 | String? name, 28 | }) { 29 | return FileRenameReq() 30 | ..path = path ?? this.path 31 | ..name = name ?? this.name; 32 | } 33 | } -------------------------------------------------------------------------------- /lib/generated/json/login_resp_entity.g.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_convert_content.dart'; 2 | import 'package:alist/entity/login_resp_entity.dart'; 3 | 4 | LoginRespEntity $LoginRespEntityFromJson(Map json) { 5 | final LoginRespEntity loginRespEntity = LoginRespEntity(); 6 | final String? token = jsonConvert.convert(json['token']); 7 | if (token != null) { 8 | loginRespEntity.token = token; 9 | } 10 | return loginRespEntity; 11 | } 12 | 13 | Map $LoginRespEntityToJson(LoginRespEntity entity) { 14 | final Map data = {}; 15 | data['token'] = entity.token; 16 | return data; 17 | } 18 | 19 | extension LoginRespEntityExtension on LoginRespEntity { 20 | LoginRespEntity copyWith({ 21 | String? token, 22 | }) { 23 | return LoginRespEntity() 24 | ..token = token ?? this.token; 25 | } 26 | } -------------------------------------------------------------------------------- /lib/generated/json/mkdir_req.g.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_convert_content.dart'; 2 | import 'package:alist/entity/mkdir_req.dart'; 3 | 4 | MkdirReq $MkdirReqFromJson(Map json) { 5 | final MkdirReq mkdirReq = MkdirReq(); 6 | final String? path = jsonConvert.convert(json['path']); 7 | if (path != null) { 8 | mkdirReq.path = path; 9 | } 10 | return mkdirReq; 11 | } 12 | 13 | Map $MkdirReqToJson(MkdirReq entity) { 14 | final Map data = {}; 15 | data['path'] = entity.path; 16 | return data; 17 | } 18 | 19 | extension MkdirReqExtension on MkdirReq { 20 | MkdirReq copyWith({ 21 | String? path, 22 | }) { 23 | return MkdirReq() 24 | ..path = path ?? this.path; 25 | } 26 | } -------------------------------------------------------------------------------- /lib/generated/json/my_info_resp.g.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_convert_content.dart'; 2 | import 'package:alist/entity/my_info_resp.dart'; 3 | 4 | MyInfoResp $MyInfoRespFromJson(Map json) { 5 | final MyInfoResp myInfoResp = MyInfoResp(); 6 | final int? id = jsonConvert.convert(json['id']); 7 | if (id != null) { 8 | myInfoResp.id = id; 9 | } 10 | final String? username = jsonConvert.convert(json['username']); 11 | if (username != null) { 12 | myInfoResp.username = username; 13 | } 14 | final String? password = jsonConvert.convert(json['password']); 15 | if (password != null) { 16 | myInfoResp.password = password; 17 | } 18 | final String? basePath = jsonConvert.convert(json['base_path']); 19 | if (basePath != null) { 20 | myInfoResp.basePath = basePath; 21 | } 22 | final int? role = jsonConvert.convert(json['role']); 23 | if (role != null) { 24 | myInfoResp.role = role; 25 | } 26 | final bool? disabled = jsonConvert.convert(json['disabled']); 27 | if (disabled != null) { 28 | myInfoResp.disabled = disabled; 29 | } 30 | final int? permission = jsonConvert.convert(json['permission']); 31 | if (permission != null) { 32 | myInfoResp.permission = permission; 33 | } 34 | final String? ssoId = jsonConvert.convert(json['sso_id']); 35 | if (ssoId != null) { 36 | myInfoResp.ssoId = ssoId; 37 | } 38 | final bool? otp = jsonConvert.convert(json['otp']); 39 | if (otp != null) { 40 | myInfoResp.otp = otp; 41 | } 42 | return myInfoResp; 43 | } 44 | 45 | Map $MyInfoRespToJson(MyInfoResp entity) { 46 | final Map data = {}; 47 | data['id'] = entity.id; 48 | data['username'] = entity.username; 49 | data['password'] = entity.password; 50 | data['base_path'] = entity.basePath; 51 | data['role'] = entity.role; 52 | data['disabled'] = entity.disabled; 53 | data['permission'] = entity.permission; 54 | data['sso_id'] = entity.ssoId; 55 | data['otp'] = entity.otp; 56 | return data; 57 | } 58 | 59 | extension MyInfoRespExtension on MyInfoResp { 60 | MyInfoResp copyWith({ 61 | int? id, 62 | String? username, 63 | String? password, 64 | String? basePath, 65 | int? role, 66 | bool? disabled, 67 | int? permission, 68 | String? ssoId, 69 | bool? otp, 70 | }) { 71 | return MyInfoResp() 72 | ..id = id ?? this.id 73 | ..username = username ?? this.username 74 | ..password = password ?? this.password 75 | ..basePath = basePath ?? this.basePath 76 | ..role = role ?? this.role 77 | ..disabled = disabled ?? this.disabled 78 | ..permission = permission ?? this.permission 79 | ..ssoId = ssoId ?? this.ssoId 80 | ..otp = otp ?? this.otp; 81 | } 82 | } -------------------------------------------------------------------------------- /lib/generated/json/player_resolve_info_entity.g.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_convert_content.dart'; 2 | import 'package:alist/entity/player_resolve_info_entity.dart'; 3 | 4 | ExternalPlayerEntity $ExternalPlayerEntityFromJson(Map json) { 5 | final ExternalPlayerEntity externalPlayerEntity = ExternalPlayerEntity(); 6 | final String? packageName = jsonConvert.convert(json['packageName']); 7 | if (packageName != null) { 8 | externalPlayerEntity.packageName = packageName; 9 | } 10 | final String? activity = jsonConvert.convert(json['activity']); 11 | if (activity != null) { 12 | externalPlayerEntity.activity = activity; 13 | } 14 | final String? label = jsonConvert.convert(json['label']); 15 | if (label != null) { 16 | externalPlayerEntity.label = label; 17 | } 18 | final String? icon = jsonConvert.convert(json['icon']); 19 | if (icon != null) { 20 | externalPlayerEntity.icon = icon; 21 | } 22 | return externalPlayerEntity; 23 | } 24 | 25 | Map $ExternalPlayerEntityToJson(ExternalPlayerEntity entity) { 26 | final Map data = {}; 27 | data['packageName'] = entity.packageName; 28 | data['activity'] = entity.activity; 29 | data['label'] = entity.label; 30 | data['icon'] = entity.icon; 31 | return data; 32 | } 33 | 34 | extension ExternalPlayerEntityExtension on ExternalPlayerEntity { 35 | ExternalPlayerEntity copyWith({ 36 | String? packageName, 37 | String? activity, 38 | String? label, 39 | String? icon, 40 | }) { 41 | return ExternalPlayerEntity() 42 | ..packageName = packageName ?? this.packageName 43 | ..activity = activity ?? this.activity 44 | ..label = label ?? this.label 45 | ..icon = icon ?? this.icon; 46 | } 47 | } -------------------------------------------------------------------------------- /lib/l10n/alist_translations.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/l10n/intl_zh_cn.dart'; 2 | import 'package:get/get.dart'; 3 | 4 | import 'intl_en_us.dart'; 5 | 6 | class AlistTranslations extends Translations { 7 | @override 8 | Map> get keys => { 9 | 'zh_CN': translationsZhCN, 10 | 'en_US': translationsEnUS, 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /lib/net/base_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/json/base/json_convert_content.dart'; 2 | import 'package:alist/util/constant.dart'; 3 | 4 | class BaseEntity { 5 | 6 | BaseEntity(this.code, this.message, this.data); 7 | 8 | BaseEntity.fromJson(Map json) { 9 | code = json[AlistConstant.code] as int; 10 | message = json[AlistConstant.message] as String; 11 | if (json.containsKey(AlistConstant.data)) { 12 | data = _generateOBJ(json[AlistConstant.data] as Object?); 13 | } 14 | } 15 | 16 | late int code; 17 | late String message; 18 | T? data; 19 | 20 | T? _generateOBJ(Object? json) { 21 | if (json == null) { 22 | return null; 23 | } 24 | if (T.toString() == 'String') { 25 | return json.toString() as T; 26 | } else if (T.toString() == 'Map') { 27 | return json as T; 28 | } else { 29 | /// List类型数据由fromJsonAsT判断处理 30 | return JsonConvert.fromJsonAsT(json); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/net/intercept.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/util/constant.dart'; 2 | import 'package:alist/util/log_utils.dart'; 3 | import 'package:dio/dio.dart'; 4 | import 'package:sp_util/sp_util.dart'; 5 | 6 | class AuthInterceptor extends Interceptor { 7 | @override 8 | void onRequest(RequestOptions options, RequestInterceptorHandler handler) { 9 | if (options.headers[AlistConstant.noAuth] == 1) { 10 | options.headers.remove(AlistConstant.noAuth); 11 | super.onRequest(options, handler); 12 | return; 13 | } 14 | 15 | final String accessToken = SpUtil.getString(AlistConstant.token) ?? ""; 16 | final String serverUrl = SpUtil.getString(AlistConstant.serverUrl) ?? ""; 17 | final String url = options.uri.toString(); 18 | if (accessToken.isNotEmpty && 19 | serverUrl.isNotEmpty && 20 | url.startsWith(serverUrl)) { 21 | options.headers['Authorization'] = accessToken; 22 | } 23 | super.onRequest(options, handler); 24 | } 25 | } 26 | 27 | class LoggingInterceptor extends Interceptor { 28 | late DateTime _startTime; 29 | late DateTime _endTime; 30 | 31 | @override 32 | void onRequest(RequestOptions options, RequestInterceptorHandler handler) { 33 | _startTime = DateTime.now(); 34 | Log.d('----------Start----------'); 35 | if (options.queryParameters.isEmpty) { 36 | if (options.path.startsWith("http://") || 37 | options.path.startsWith("https://")) { 38 | Log.d('RequestUrl: ${options.path}'); 39 | } else { 40 | Log.d('RequestUrl: ${options.baseUrl}${options.path}'); 41 | } 42 | } else { 43 | if (options.path.startsWith("http://") || 44 | options.path.startsWith("https://")) { 45 | Log.d( 46 | 'RequestUrl: ${options.path}?${Transformer.urlEncodeMap(options.queryParameters)}'); 47 | } else { 48 | Log.d( 49 | 'RequestUrl: ${options.baseUrl}${options.path}?${Transformer.urlEncodeMap(options.queryParameters)}'); 50 | } 51 | } 52 | Log.d('RequestMethod: ${options.method}'); 53 | Log.d('RequestHeaders:${options.headers}'); 54 | Log.d('RequestContentType: ${options.contentType}'); 55 | Log.d('RequestData: ${options.data}'); 56 | super.onRequest(options, handler); 57 | } 58 | 59 | @override 60 | void onResponse( 61 | Response response, ResponseInterceptorHandler handler) { 62 | _endTime = DateTime.now(); 63 | final int duration = _endTime.difference(_startTime).inMilliseconds; 64 | Log.d('ResponseCode: ${response.statusCode}'); 65 | // 输出结果 66 | Log.json(response.data.toString()); 67 | Log.d('----------End: $duration 毫秒----------'); 68 | super.onResponse(response, handler); 69 | } 70 | 71 | @override 72 | void onError(DioError err, ErrorInterceptorHandler handler) { 73 | Log.d('----------Error-----------'); 74 | super.onError(err, handler); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/net/json_parse_error.dart: -------------------------------------------------------------------------------- 1 | class JsonParseException implements Exception { 2 | final String message; 3 | 4 | JsonParseException(this.message); 5 | 6 | @override 7 | String toString() { 8 | String report = "Error: $message"; 9 | return report; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/net/net.dart: -------------------------------------------------------------------------------- 1 | export 'dio_utils.dart'; 2 | -------------------------------------------------------------------------------- /lib/net/net_error_handler.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:alist/l10n/intl_keys.dart'; 4 | import 'package:alist/net/json_parse_error.dart'; 5 | import 'package:alist/net/redirect_exception.dart'; 6 | import 'package:alist/util/log_utils.dart'; 7 | import 'package:dio/dio.dart'; 8 | import 'package:flustars/flustars.dart'; 9 | import 'package:flutter/widgets.dart'; 10 | import 'package:get/get.dart'; 11 | 12 | class NetErrorHandler { 13 | static String netErrorToMessage(dynamic error) { 14 | if (error is RedirectException) { 15 | return error.message; 16 | } 17 | if (error is JsonParseException) { 18 | return Intl.net_error_parse_error.tr; 19 | } 20 | if (error is SocketException) { 21 | return Intl.net_error_socket_error.tr; 22 | } 23 | if (error is HttpException) { 24 | return Intl.net_error_http_error.tr; 25 | } 26 | if (error is FormatException) { 27 | return Intl.net_error_parse_error.tr; 28 | } 29 | if (error is DioException) { 30 | if (error.error is HandshakeException) { 31 | return Intl.net_error_certificate_error.tr; 32 | } 33 | Log.d(error.type.toString()); 34 | switch (error.type) { 35 | case DioExceptionType.connectionTimeout: 36 | return Intl.net_error_connect_timeout_error.tr; 37 | case DioExceptionType.sendTimeout: 38 | return Intl.net_error_send_timeout_error.tr; 39 | case DioExceptionType.receiveTimeout: 40 | return Intl.net_error_receive_timeout_error.tr; 41 | case DioExceptionType.badCertificate: 42 | return Intl.net_error_certificate_error.tr; 43 | case DioExceptionType.badResponse: 44 | if (error.response?.statusCode != null) { 45 | return "Response ${error.response?.statusCode ?? ""} ${error.response?.statusMessage ?? ""}"; 46 | } 47 | return Intl.net_error_net_error.tr; 48 | case DioExceptionType.cancel: 49 | return Intl.net_error_cancel_error.tr; 50 | case DioExceptionType.connectionError: 51 | return Intl.net_error_net_error.tr; 52 | default: 53 | break; 54 | } 55 | } 56 | return Intl.net_error_net_error.tr; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/net/redirect_exception.dart: -------------------------------------------------------------------------------- 1 | class RedirectException implements Exception { 2 | final String message; 3 | 4 | RedirectException(this.message); 5 | 6 | @override 7 | String toString() { 8 | String report = "Location: $message"; 9 | return report; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/screen/aboute_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/generated/images.dart'; 2 | import 'package:alist/widget/alist_scaffold.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:get/get.dart'; 5 | import 'package:package_info_plus/package_info_plus.dart'; 6 | 7 | import 'package:alist/l10n/intl_keys.dart'; 8 | 9 | class AboutScreen extends StatelessWidget { 10 | const AboutScreen({Key? key}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return AlistScaffold( 15 | appbarTitle: Text(Intl.screenName_about.tr), 16 | body: const _AboutPageContainer(), 17 | ); 18 | } 19 | } 20 | 21 | class _AboutPageContainer extends StatefulWidget { 22 | const _AboutPageContainer({Key? key}) : super(key: key); 23 | 24 | @override 25 | State<_AboutPageContainer> createState() => _AboutPageContainerState(); 26 | } 27 | 28 | class _AboutPageContainerState extends State<_AboutPageContainer> { 29 | PackageInfo? packageInfo; 30 | 31 | @override 32 | void initState() { 33 | super.initState(); 34 | initPackageInfo(); 35 | } 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | return Center( 40 | child: Column( 41 | children: [ 42 | Padding( 43 | padding: const EdgeInsets.only(top: 20), 44 | child: Image.asset(Images.logo), 45 | ), 46 | Padding( 47 | padding: const EdgeInsets.only(top: 8), 48 | child: Text( 49 | Intl.appName.tr, 50 | style: Theme.of(context).textTheme.titleLarge, 51 | ), 52 | ), 53 | Padding( 54 | padding: const EdgeInsets.only(top: 2), 55 | child: Text("v${packageInfo?.version ?? ""}"), 56 | ), 57 | ], 58 | ), 59 | ); 60 | } 61 | 62 | initPackageInfo() async { 63 | packageInfo = await PackageInfo.fromPlatform(); 64 | setState(() {}); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/screen/file_list/file_list_navigator.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/router.dart'; 2 | import 'package:alist/screen/file_list/file_list_screen.dart'; 3 | import 'package:alist/widget/alist_will_pop_scope.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:get/get.dart'; 6 | 7 | class FileListNavigator extends StatefulWidget { 8 | const FileListNavigator({Key? key, required this.isInFileListStack}) 9 | : super(key: key); 10 | final bool isInFileListStack; 11 | 12 | @override 13 | State createState() => _FileListNavigatorState(); 14 | } 15 | 16 | class _FileListNavigatorState extends State 17 | with AutomaticKeepAliveClientMixin { 18 | final GlobalKey? _key = 19 | Get.nestedKey(AlistRouter.fileListRouterStackId); 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | super.build(context); 24 | return AlistWillPopScope( 25 | onWillPop: () async { 26 | if (widget.isInFileListStack && 27 | _key?.currentState != null && 28 | _key?.currentState?.canPop() == true) { 29 | _key?.currentState?.pop(); 30 | return false; 31 | } 32 | return true; 33 | }, 34 | child: Navigator( 35 | key: _key, 36 | onGenerateRoute: (settings) { 37 | dynamic arguments = settings.arguments; 38 | return GetPageRoute( 39 | page: () => FileListScreen( 40 | path: arguments?["path"], 41 | sortBy: arguments?["sortBy"], 42 | sortByUp: arguments?["sortByUp"], 43 | backupPassword: arguments?["backupPassword"], 44 | isRootStack: false, 45 | ), 46 | ); 47 | }, 48 | ), 49 | ); 50 | } 51 | 52 | @override 53 | bool get wantKeepAlive => true; 54 | } 55 | -------------------------------------------------------------------------------- /lib/screen/file_list/file_rename_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/l10n/intl_keys.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:get/get.dart'; 4 | 5 | class FileRenameDialog extends StatefulWidget { 6 | const FileRenameDialog({ 7 | Key? key, 8 | required this.controller, 9 | required this.focusNode, 10 | this.onConfirm, 11 | this.onCancel, 12 | }) : super(key: key); 13 | final TextEditingController controller; 14 | final FocusNode focusNode; 15 | final VoidCallback? onConfirm; 16 | final VoidCallback? onCancel; 17 | 18 | @override 19 | State createState() => _FileRenameDialogState(); 20 | } 21 | 22 | class _FileRenameDialogState extends State { 23 | var _showClear = false; 24 | var _hasContent = false; 25 | 26 | @override 27 | void initState() { 28 | super.initState(); 29 | widget.controller.addListener(() { 30 | var showClear = widget.controller.text.isNotEmpty; 31 | var hasContent = widget.controller.text.trim().isNotEmpty; 32 | if (_showClear != showClear || _hasContent != hasContent) { 33 | setState(() { 34 | _showClear = showClear; 35 | _hasContent = hasContent; 36 | }); 37 | } 38 | }); 39 | } 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | return AlertDialog( 44 | title: Text(Intl.fileRenameDialog_title.tr), 45 | content: TextField( 46 | focusNode: widget.focusNode, 47 | autofocus: true, 48 | controller: widget.controller, 49 | decoration: InputDecoration( 50 | border: const OutlineInputBorder(), 51 | hintText: Intl.fileRenameDialog_hint.tr, 52 | suffixIcon: _showClear 53 | ? IconButton( 54 | onPressed: () => widget.controller.clear(), 55 | icon: const Icon(Icons.close), 56 | ) 57 | : null, 58 | isCollapsed: true, 59 | isDense: true, 60 | contentPadding: 61 | const EdgeInsets.symmetric(horizontal: 11, vertical: 12), 62 | ), 63 | ), 64 | actions: [ 65 | TextButton( 66 | onPressed: widget.onCancel, 67 | child: Text(Intl.fileRenameDialog_btn_cancel.tr), 68 | ), 69 | TextButton( 70 | onPressed: _hasContent ? widget.onConfirm : null, 71 | child: Text(Intl.fileRenameDialog_btn_ok.tr), 72 | ), 73 | ], 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/screen/file_list/mkdir_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/l10n/intl_keys.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:get/get.dart'; 4 | 5 | class MkdirDialog extends StatefulWidget { 6 | const MkdirDialog({ 7 | Key? key, 8 | required this.controller, 9 | required this.focusNode, 10 | this.onConfirm, 11 | this.onCancel, 12 | }) : super(key: key); 13 | final TextEditingController controller; 14 | final FocusNode focusNode; 15 | final VoidCallback? onConfirm; 16 | final VoidCallback? onCancel; 17 | 18 | @override 19 | State createState() => _MkdirDialogState(); 20 | } 21 | 22 | class _MkdirDialogState extends State { 23 | var _showClear = false; 24 | var _hasContent = false; 25 | 26 | @override 27 | void initState() { 28 | super.initState(); 29 | widget.controller.addListener(() { 30 | var showClear = widget.controller.text.isNotEmpty; 31 | var hasContent = widget.controller.text.trim().isNotEmpty; 32 | if (_showClear != showClear || _hasContent != hasContent) { 33 | setState(() { 34 | _showClear = showClear; 35 | _hasContent = hasContent; 36 | }); 37 | } 38 | }); 39 | } 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | return AlertDialog( 44 | title: Text(Intl.mkdirDialog_title.tr), 45 | content: TextField( 46 | focusNode: widget.focusNode, 47 | autofocus: true, 48 | controller: widget.controller, 49 | decoration: InputDecoration( 50 | border: const OutlineInputBorder(), 51 | hintText: Intl.mkdirDialog_hint.tr, 52 | suffixIcon: _showClear 53 | ? IconButton( 54 | onPressed: () => widget.controller.clear(), 55 | icon: const Icon(Icons.close), 56 | ) 57 | : null, 58 | isCollapsed: true, 59 | isDense: true, 60 | contentPadding: 61 | const EdgeInsets.symmetric(horizontal: 11, vertical: 12), 62 | ), 63 | ), 64 | actions: [ 65 | TextButton( 66 | onPressed: widget.onCancel, 67 | child: Text(Intl.mkdirDialog_cancel.tr), 68 | ), 69 | TextButton( 70 | onPressed: _hasContent ? widget.onConfirm : null, 71 | child: Text(Intl.mkdirDialog_ok.tr), 72 | ), 73 | ], 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/util/constant.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | 3 | class AlistConstant { 4 | /// App运行在Release环境时,inProduction为true;当App运行在Debug和Profile环境时,inProduction为false 5 | static const bool inProduction = kReleaseMode; 6 | 7 | static bool isDriverTest = false; 8 | static bool isUnitTest = false; 9 | 10 | static const String appName = "AList Client"; 11 | static const String data = 'data'; 12 | static const String message = 'message'; 13 | static const String code = 'code'; 14 | static const String noAuth = 'noAuth'; 15 | 16 | static const String serverUrl = 'address'; 17 | static const String baseUrl = 'baseUrl'; 18 | static const String basePath = 'basePath'; 19 | static const String username = 'username'; 20 | static const String password = 'password'; 21 | static const String token = 'token'; 22 | static const String guest = 'guest'; 23 | static const String useDemoServer = 'useDemoServer'; 24 | static const String isAgreePrivacyPolicy = 'isAgreePrivacyPolicy'; 25 | static const String ignoreSSLError = "ignoreSSLError"; 26 | static const String ignoreAppVersion = "ignoreAppVersion"; 27 | static const String isFirstTimeDownload = "isFirstTimeDownload"; 28 | static const String isFirstTimeSaveToLocal = "isFirstTimeSaveToLocal"; 29 | static const String maxRunningTaskCount = "maxRunningTaskCount"; 30 | static const String fileNameMaxLines = 'fileNameMaxLines'; 31 | static const String fileSortWayIndex = 'fileSortWayIndex'; 32 | static const String fileSortWayUp = 'fileSortWayUp'; 33 | static const String videoPlayerName = 'videoPlayerName'; 34 | static const String videoPlayerRouter = 'videoPlayerRouter'; 35 | static const String playerType = 'playerType'; 36 | 37 | static const String locale = 'locale'; 38 | } 39 | -------------------------------------------------------------------------------- /lib/util/download/download_http_client.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flustars/flustars.dart'; 4 | 5 | class DownloadHttpClient { 6 | final HttpClient _httpClient = HttpClient()..autoUncompress = false; 7 | int _lastLimitRequestTime = 0; 8 | bool _requesting = false; 9 | 10 | DownloadHttpClient(); 11 | 12 | // limitFrequency 用于解决部分网盘(如:阿里云盘)存在下载链接请求频率限制的问题 13 | // limitFrequency 为与上一次请求的最小时间隔,单位:秒 14 | Future get(String url, 15 | {Map? headers, int? limitFrequency}) async { 16 | if (limitFrequency == null || limitFrequency < 1) { 17 | return _getInner(url, headers: headers); 18 | } 19 | 20 | int now = DateTime.now().millisecondsSinceEpoch; 21 | if (_requesting || now - _lastLimitRequestTime < limitFrequency * 1000) { 22 | do { 23 | await Future.delayed(const Duration(milliseconds: 200)); 24 | now = DateTime.now().millisecondsSinceEpoch; 25 | } while (_requesting || now - _lastLimitRequestTime < limitFrequency); 26 | } 27 | 28 | _requesting = true; 29 | try { 30 | return await _getInner(url, headers: headers); 31 | } finally { 32 | _requesting = false; 33 | _lastLimitRequestTime = DateTime.now().millisecondsSinceEpoch; 34 | } 35 | } 36 | 37 | Future _getInner(String url, 38 | {Map? headers}) async { 39 | HttpClientRequest request = 40 | await _httpClient.openUrl("GET", Uri.parse(url)); 41 | headers?.forEach((key, value) { 42 | LogUtil.d("header $key=$value"); 43 | request.headers.set(key, value); 44 | }); 45 | return request.close(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/util/download/download_task_status.dart: -------------------------------------------------------------------------------- 1 | enum DownloadTaskStatus { 2 | waiting, 3 | downloading, 4 | decompressing, 5 | paused, 6 | failed, 7 | finished, 8 | canceled, 9 | } 10 | -------------------------------------------------------------------------------- /lib/util/file_password_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/database/dao/file_password_dao.dart'; 2 | import 'package:alist/database/table/file_password.dart'; 3 | import 'package:alist/util/string_utils.dart'; 4 | import 'package:alist/util/user_controller.dart'; 5 | import 'package:get/get.dart'; 6 | 7 | class FilePasswordHelper { 8 | static final FilePasswordHelper _singleton = FilePasswordHelper._(); 9 | late FilePasswordDao _filePasswordDao; 10 | 11 | FilePasswordHelper._(); 12 | 13 | factory FilePasswordHelper() { 14 | return _singleton; 15 | } 16 | 17 | void setFilePasswordDao(FilePasswordDao filePasswordDao) { 18 | _filePasswordDao = filePasswordDao; 19 | } 20 | 21 | Future fastFindPassword(String remotePath, 22 | {String? backupPassword}) async { 23 | final userController = Get.find(); 24 | final user = userController.user.value; 25 | return await findPasswordByPath(user.serverUrl, user.username, remotePath, 26 | backupPassword: backupPassword); 27 | } 28 | 29 | Future findPasswordByPath( 30 | String serverUrl, String userId, String remotePath, 31 | {String? backupPassword}) async { 32 | var path = remotePath; 33 | if (!path.startsWith("/")) { 34 | path = "/$path"; 35 | } 36 | FilePassword? filePassword; 37 | if (backupPassword == null) { 38 | do { 39 | filePassword = 40 | await _filePasswordDao.findPasswordByPath(serverUrl, userId, path); 41 | if (filePassword == null) { 42 | path = path.substringBeforeLast("/")!; 43 | } 44 | } while (filePassword == null && path != ""); 45 | } else { 46 | filePassword = 47 | await _filePasswordDao.findPasswordByPath(serverUrl, userId, path); 48 | if (filePassword == null) { 49 | return backupPassword; 50 | } 51 | } 52 | return filePassword?.password; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/util/file_type.dart: -------------------------------------------------------------------------------- 1 | enum FileType { 2 | audio, 3 | code, 4 | compress, 5 | email, 6 | excel, 7 | flash, 8 | html, 9 | image, 10 | keynote, 11 | numbers, 12 | others, 13 | pages, 14 | pdf, 15 | ppt, 16 | psd, 17 | sketch, 18 | txt, 19 | video, 20 | word, 21 | folder, 22 | file, 23 | apk, 24 | markdown 25 | } 26 | -------------------------------------------------------------------------------- /lib/util/focus_node_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | extension FocusNodeUtils on FocusNode { 4 | FocusNode autoFocus() { 5 | Future.delayed(const Duration(milliseconds: 100), () => requestFocus()); 6 | return this; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lib/util/global.dart: -------------------------------------------------------------------------------- 1 | import 'package:get/get.dart'; 2 | 3 | class Global { 4 | static String configServerHost = "c.qianyi605.eu.org"; 5 | static String demoServerBaseUrl = "https://qianyi605.eu.org/"; 6 | static final fileNameMaxLines = 1.obs; 7 | } -------------------------------------------------------------------------------- /lib/util/iterator.dart: -------------------------------------------------------------------------------- 1 | extension IteratablEextension on Iterable { 2 | E? firstWhereOrNull(bool Function(E element) test) { 3 | for (E element in this) { 4 | if (test(element)) return element; 5 | } 6 | return null; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lib/util/keyboard_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class KeyboardUtil { 4 | static void hideKeyboard(BuildContext context) { 5 | FocusScopeNode currentFocus = FocusScope.of(context); 6 | if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) { 7 | FocusManager.instance.primaryFocus!.unfocus(); 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/util/markdown_utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:alist/util/global.dart'; 4 | 5 | class MarkdownUtil { 6 | static makePreviewUrl(String url) { 7 | String scheme; 8 | if (Platform.isIOS && url.startsWith("http://")) { 9 | scheme = "http"; 10 | } else { 11 | scheme = "https"; 12 | } 13 | 14 | return "$scheme://${Global.configServerHost}/alist_h5/showMarkDown?markdownUrl=${Uri.encodeComponent(url)}"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/util/named_router.dart: -------------------------------------------------------------------------------- 1 | class NamedRouter { 2 | // root 3 | static const root = "/index"; 4 | 5 | // login 6 | static const login = "/login"; 7 | 8 | // home index 9 | static const home = "/home"; 10 | 11 | // file list 12 | static const fileList = "/fileList"; 13 | 14 | // file list 15 | static const settings = "/settings"; 16 | 17 | // video player 18 | static const videoPlayer = "/videoPlayer"; 19 | 20 | // donate 21 | static const donate = "/donate"; 22 | 23 | // donate 24 | static const about = "/about"; 25 | 26 | // gallery 27 | static const gallery = "/gallery"; 28 | 29 | // audio player 30 | static const audioPlayer = "/audioPlayer"; 31 | 32 | // file reader 33 | static const fileReader = "/fileReader"; 34 | 35 | // web 36 | static const web = "/web"; 37 | 38 | // pdfReader 39 | static const pdfReader = "/pdfReader"; 40 | 41 | // uploadingFiles 42 | static const uploadingFiles = "/uploadingFiles"; 43 | 44 | // account 45 | static const account = "/account"; 46 | 47 | // download manager 48 | static const downloadManager = "/downloadManager"; 49 | 50 | // file list search 51 | static const fileSearch = "/fileSearch"; 52 | 53 | // cache manager 54 | static const cacheManager = "/cacheManager"; 55 | 56 | // player settings 57 | static const playerSettings = "/playerSettings"; 58 | } 59 | -------------------------------------------------------------------------------- /lib/util/nature_sort.dart: -------------------------------------------------------------------------------- 1 | class NaturalSort { 2 | NaturalSort._(); 3 | 4 | static int _commonPrefix(String a, String b) { 5 | int m = a.length; 6 | int n = b.length; 7 | if (n < m) { 8 | m = n; 9 | } 10 | if (m == 0) { 11 | return 0; 12 | } 13 | 14 | for (int i = 0; i < m; i++) { 15 | String ca = a[i]; 16 | String cb = b[i]; 17 | if ((ca.compareTo('0') >= 0 && ca.compareTo('9') <= 0) || 18 | (cb.compareTo('0') >= 0 && cb.compareTo('9') <= 0) || 19 | ca != cb) { 20 | return i; 21 | } 22 | } 23 | return m; 24 | } 25 | 26 | static int _digits(String s) { 27 | for (int i = 0; i < s.length; i++) { 28 | String c = s[i]; 29 | if (c.compareTo('0') < 0 || c.compareTo('9') > 0) { 30 | return i; 31 | } 32 | } 33 | return s.length; 34 | } 35 | 36 | static int compare(String a, String b) { 37 | if (a == b) { 38 | return 0; 39 | } 40 | 41 | while (true) { 42 | int p = _commonPrefix(a, b); 43 | if (p != 0) { 44 | a = a.substring(p); 45 | b = b.substring(p); 46 | } 47 | if (a.isEmpty) { 48 | return b.isNotEmpty ? -1 : 1; 49 | } 50 | int ia = _digits(a); 51 | if (ia > 0) { 52 | int ib = _digits(b); 53 | if (ib > 0) { 54 | // Both sides have digits. 55 | int an = int.parse(a.substring(0, ia)); 56 | int bn = int.parse(b.substring(0, ib)); 57 | if (an != bn) { 58 | return an.compareTo(bn); 59 | } 60 | // Semantically the same digits. 61 | if (ia != a.length && ib != b.length) { 62 | a = a.substring(ia); 63 | b = b.substring(ib); 64 | continue; 65 | } 66 | } 67 | } 68 | return a.compareTo(b); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/util/string_utils.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'dart:convert'; 3 | import 'package:crypto/crypto.dart'; 4 | 5 | extension StringExtensions on String? { 6 | String? substringAfterLast(String separator) { 7 | if (this == null) { 8 | return null; 9 | } 10 | 11 | final index = this!.lastIndexOf(separator); 12 | if (index == -1) { 13 | return this; 14 | } 15 | return this!.substring(index + separator.length); 16 | } 17 | 18 | String? substringBeforeLast(String separator) { 19 | if (this == null) { 20 | return null; 21 | } 22 | 23 | final index = this!.lastIndexOf(separator); 24 | if (index == -1) { 25 | return this; 26 | } 27 | return this!.substring(0, index); 28 | } 29 | 30 | String md5String(){ 31 | var bytes = utf8.encode(this ?? ""); 32 | var md5Hash = md5.convert(bytes); 33 | String md5String = md5Hash.toString(); 34 | return md5String; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/util/widget_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class WidgetUtils { 4 | static bool isDarkMode(BuildContext context) { 5 | return Theme.of(context).brightness == Brightness.dark; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /lib/widget/alist_checkbox.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | 3 | class AlistCheckBox extends StatelessWidget { 4 | final bool? value; 5 | final String text; 6 | final ValueChanged? onChanged; 7 | 8 | const AlistCheckBox({ 9 | super.key, 10 | required this.value, 11 | required this.text, 12 | required this.onChanged, 13 | }); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Row( 18 | mainAxisSize: MainAxisSize.min, 19 | children: [ 20 | CupertinoCheckbox( 21 | value: value, 22 | // materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, 23 | onChanged: onChanged, 24 | ), 25 | GestureDetector( 26 | onTap: onChanged == null 27 | ? null 28 | : () { 29 | onChanged!(!(value ?? false)); 30 | }, 31 | child: Text(text), 32 | ), 33 | ], 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/widget/alist_scaffold.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/util/widget_utils.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AlistScaffold extends StatelessWidget { 5 | const AlistScaffold({ 6 | Key? key, 7 | this.appbarTitle, 8 | required this.body, 9 | this.onLeadingDoubleTap, 10 | this.resizeToAvoidBottomInset, 11 | this.appbarActions, 12 | this.showAppbar = true, 13 | }) : super(key: key); 14 | final Widget? appbarTitle; 15 | final Widget body; 16 | final GestureTapCallback? onLeadingDoubleTap; 17 | final bool? resizeToAvoidBottomInset; 18 | final List? appbarActions; 19 | final bool showAppbar; 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | List colors = List.empty(); 24 | bool isDarkMode = WidgetUtils.isDarkMode(context); 25 | 26 | if (!isDarkMode) { 27 | Color startColor = Theme.of(context).colorScheme.primaryContainer; 28 | const Color endColor = Colors.white; 29 | colors = [startColor, endColor]; 30 | } 31 | final ModalRoute? parentRoute = ModalRoute.of(context); 32 | var canPop = null != parentRoute && parentRoute.canPop; 33 | 34 | return DecoratedBox( 35 | decoration: isDarkMode 36 | ? const BoxDecoration() 37 | : BoxDecoration( 38 | gradient: LinearGradient( 39 | colors: colors, 40 | begin: Alignment.topCenter, 41 | end: Alignment.bottomCenter, 42 | ), 43 | ), 44 | child: Scaffold( 45 | backgroundColor: isDarkMode ? null : Colors.transparent, 46 | resizeToAvoidBottomInset: resizeToAvoidBottomInset ?? true, 47 | appBar: !showAppbar 48 | ? null 49 | : AppBar( 50 | leading: canPop 51 | ? GestureDetector( 52 | onDoubleTap: onLeadingDoubleTap, 53 | child: const BackButton(), 54 | ) 55 | : null, 56 | automaticallyImplyLeading: false, 57 | backgroundColor: isDarkMode ? null : Colors.transparent, 58 | title: appbarTitle, 59 | actions: appbarActions, 60 | ), 61 | body: SafeArea(child: body), 62 | )); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/widget/alist_will_pop_scope.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | class AlistWillPopScope extends StatelessWidget { 6 | const AlistWillPopScope({ 7 | Key? key, 8 | required this.child, 9 | this.onWillPop, 10 | this.alwaysAllowSwipeBackOnIOS = true, 11 | }) : super(key: key); 12 | 13 | final Widget child; 14 | final WillPopCallback? onWillPop; 15 | final bool alwaysAllowSwipeBackOnIOS; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | final onWillPop = 20 | (Platform.isIOS && alwaysAllowSwipeBackOnIOS) ? null : this.onWillPop; 21 | return WillPopScope(onWillPop: onWillPop, child: child); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/widget/config_file_name_max_lines_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/l10n/intl_keys.dart'; 2 | import 'package:alist/util/constant.dart'; 3 | import 'package:alist/util/global.dart'; 4 | import 'package:alist/widget/alist_checkbox.dart'; 5 | import 'package:flustars/flustars.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:get/get.dart'; 8 | 9 | class ConfigFileNameMaxLinesDialog extends StatelessWidget { 10 | const ConfigFileNameMaxLinesDialog({super.key}); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Dialog( 15 | child: Padding( 16 | padding: const EdgeInsets.symmetric(vertical: 15), 17 | child: Column( 18 | crossAxisAlignment: CrossAxisAlignment.start, 19 | mainAxisSize: MainAxisSize.min, 20 | children: [ 21 | Center( 22 | child: Text(Intl.configFileNameMaxLinesDialog_title.tr, 23 | style: Theme.of(context).textTheme.titleLarge), 24 | ), 25 | const SizedBox(height: 10), 26 | _buildChoices(), 27 | ], 28 | ), 29 | ), 30 | ); 31 | } 32 | 33 | Padding _buildChoices() { 34 | callback(int fileNameMaxLines) { 35 | if (Global.fileNameMaxLines.value != fileNameMaxLines) { 36 | Global.fileNameMaxLines.value = fileNameMaxLines; 37 | SpUtil.putInt(AlistConstant.fileNameMaxLines, fileNameMaxLines); 38 | } 39 | } 40 | 41 | return Padding( 42 | padding: const EdgeInsets.symmetric(horizontal: 20), 43 | child: Obx(() => Column( 44 | crossAxisAlignment: CrossAxisAlignment.start, 45 | mainAxisSize: MainAxisSize.min, 46 | children: [ 47 | AlistCheckBox( 48 | value: Global.fileNameMaxLines.value == 1, 49 | text: Intl.configFileNameMaxLinesDialog_choice_one.tr, 50 | onChanged: (bool? b) => callback(1), 51 | ), 52 | AlistCheckBox( 53 | value: Global.fileNameMaxLines.value == 2, 54 | text: Intl.configFileNameMaxLinesDialog_choice_two.tr, 55 | onChanged: (bool? b) => callback(2), 56 | ), 57 | AlistCheckBox( 58 | value: Global.fileNameMaxLines.value > 2, 59 | text: Intl.configFileNameMaxLinesDialog_choice_noLimit.tr, 60 | onChanged: (bool? b) => callback(3), 61 | ) 62 | ], 63 | )), 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/widget/loading_status_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:alist/l10n/intl_keys.dart'; 2 | import 'package:flustars/flustars.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:get/get.dart'; 5 | 6 | class LoadingStatusWidget extends StatelessWidget { 7 | const LoadingStatusWidget({ 8 | Key? key, 9 | required this.loading, 10 | this.errorMsg, 11 | required this.child, 12 | required this.retryCallback, 13 | }) : super(key: key); 14 | final bool loading; 15 | final String? errorMsg; 16 | final Widget child; 17 | final VoidCallback retryCallback; 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | if (errorMsg != null && errorMsg!.isNotEmpty) { 22 | return Center( 23 | child: Column( 24 | mainAxisAlignment: MainAxisAlignment.center, 25 | children: [ 26 | Padding( 27 | padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10), 28 | child: Text(errorMsg!), 29 | ), 30 | FilledButton( 31 | onPressed: () { 32 | LogUtil.d("retry..."); 33 | retryCallback(); 34 | }, 35 | child: Text(Intl.loadingStatusWidget_retry.tr), 36 | ) 37 | ], 38 | ), 39 | ); 40 | } else if (loading) { 41 | return const Center( 42 | child: CircularProgressIndicator(), 43 | ); 44 | } else { 45 | return child; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/widget/overflow_text.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class OverflowText extends StatelessWidget { 4 | static const ellipsis = "..."; 5 | 6 | const OverflowText({super.key, required this.text, this.style}); 7 | 8 | final String text; 9 | final TextStyle? style; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return LayoutBuilder( 14 | builder: (BuildContext context, BoxConstraints constraints) { 15 | var textStyle = DefaultTextStyle.of(context).style; 16 | if (style != null) { 17 | textStyle = textStyle.merge(style); 18 | } 19 | 20 | var maxWidth = constraints.biggest.width; 21 | 22 | final textSpan = TextSpan(text: text, style: textStyle); 23 | final textPainter = TextPainter( 24 | text: textSpan, 25 | textDirection: TextDirection.ltr, 26 | )..layout(); 27 | if (textPainter.width > maxWidth) { 28 | // LogUtil.d("${textPainter.width} $maxWidth"); 29 | var left = 0; 30 | TextSpan? leftText; 31 | var leftWidth = 0.0; 32 | var right = 0; 33 | TextSpan? rightText; 34 | var rightWidth = 0.0; 35 | 36 | var ellipsisText = TextSpan(text: ellipsis, style: textStyle); 37 | textPainter.text = ellipsisText; 38 | textPainter.layout(); 39 | maxWidth -= textPainter.width; 40 | 41 | while (leftWidth + rightWidth < maxWidth) { 42 | if (leftWidth <= rightWidth) { 43 | left++; 44 | leftText = 45 | TextSpan(text: text.substring(0, left), style: textStyle); 46 | 47 | textPainter.text = leftText; 48 | textPainter.layout(); 49 | leftWidth = textPainter.width; 50 | 51 | if (leftWidth + rightWidth > maxWidth) { 52 | left--; 53 | leftText = 54 | TextSpan(text: text.substring(0, left), style: textStyle); 55 | break; 56 | } 57 | } else { 58 | right++; 59 | rightText = TextSpan( 60 | text: text.substring(text.length - right), style: textStyle); 61 | 62 | textPainter.text = rightText; 63 | textPainter.layout(); 64 | rightWidth = textPainter.width; 65 | 66 | if (leftWidth + rightWidth > maxWidth) { 67 | right--; 68 | rightText = TextSpan( 69 | text: text.substring(text.length - right), style: textStyle); 70 | break; 71 | } 72 | } 73 | } 74 | 75 | return Text( 76 | "${leftText?.text ?? ""}$ellipsis${rightText?.text ?? ""}", 77 | style: textStyle, 78 | ); 79 | } else { 80 | return Text(text, style: textStyle); 81 | } 82 | }); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/widget/player_selector_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:alist/entity/player_resolve_info_entity.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; 6 | 7 | typedef OnExternalPlayerClick = Function(ExternalPlayerEntity); 8 | 9 | class PlayerSelectorDialog extends StatelessWidget { 10 | const PlayerSelectorDialog( 11 | {super.key, 12 | required this.players, 13 | required this.onPlayerClick}); 14 | 15 | final List players; 16 | final OnExternalPlayerClick onPlayerClick; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | var itemCount = players.length; 21 | 22 | return Container( 23 | constraints: const BoxConstraints(minHeight: 100, maxHeight: 300), 24 | child: AlignedGridView.count( 25 | crossAxisCount: 4, 26 | shrinkWrap: itemCount < 8, 27 | itemCount: itemCount, 28 | itemBuilder: (context, index) { 29 | var info = players[index]; 30 | return GestureDetector( 31 | onTap: () { 32 | onPlayerClick(info); 33 | }, 34 | child: _buildPlayerWidget(info.icon, info.label, iconIsFile: info.activity.isNotEmpty), 35 | ); 36 | }), 37 | ); 38 | } 39 | 40 | Widget _buildPlayerWidget(String icon, String label, 41 | {bool iconIsFile = true}) { 42 | dynamic image = iconIsFile ? FileImage(File(icon)) : AssetImage(icon); 43 | 44 | return Padding( 45 | padding: const EdgeInsets.symmetric(vertical: 10), 46 | child: Column( 47 | mainAxisSize: MainAxisSize.min, 48 | mainAxisAlignment: MainAxisAlignment.center, 49 | children: [ 50 | ClipRRect( 51 | borderRadius: BorderRadius.circular(10), 52 | child: Image( 53 | image: image, 54 | width: 45, 55 | height: 45, 56 | ), 57 | ), 58 | Padding( 59 | padding: const EdgeInsets.only(top: 2.0), 60 | child: Text( 61 | label, 62 | textAlign: TextAlign.center, 63 | style: const TextStyle(fontSize: 12), 64 | ), 65 | ) 66 | ], 67 | ), 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | 12 | void fl_register_plugins(FlPluginRegistry* registry) { 13 | g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = 14 | fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); 15 | file_selector_plugin_register_with_registrar(file_selector_linux_registrar); 16 | g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = 17 | fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); 18 | url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); 19 | } 20 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | file_selector_linux 7 | url_launcher_linux 8 | ) 9 | 10 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 11 | ) 12 | 13 | set(PLUGIN_BUNDLED_LIBRARIES) 14 | 15 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 16 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 17 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 20 | endforeach(plugin) 21 | 22 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 23 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 25 | endforeach(ffi_plugin) 26 | -------------------------------------------------------------------------------- /linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import audio_service 9 | import audio_session 10 | import device_info_plus 11 | import file_selector_macos 12 | import just_audio 13 | import package_info_plus 14 | import path_provider_foundation 15 | import screen_brightness_macos 16 | import shared_preferences_foundation 17 | import sqflite 18 | import url_launcher_macos 19 | import wakelock_macos 20 | 21 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 22 | AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin")) 23 | AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) 24 | DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) 25 | FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) 26 | JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) 27 | FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) 28 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 29 | ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin")) 30 | SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) 31 | SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) 32 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 33 | WakelockMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockMacosPlugin")) 34 | } 35 | -------------------------------------------------------------------------------- /macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.14' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @main 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | 10 | override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { 11 | return true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = alist 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.github.alist 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2023 com.github. All rights reserved. 15 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | com.apple.security.network.client 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | NSAppTransportSecurity 32 | 33 | NSAllowsArbitraryLoads 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.network.server 8 | 9 | com.apple.security.network.client 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /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 in the flutter_test package. 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:alist/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 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/web/favicon.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | alist 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alist", 3 | "short_name": "alist", 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 | -------------------------------------------------------------------------------- /windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | void RegisterPlugins(flutter::PluginRegistry* registry) { 15 | FileSelectorWindowsRegisterWithRegistrar( 16 | registry->GetRegistrarForPlugin("FileSelectorWindows")); 17 | PermissionHandlerWindowsPluginRegisterWithRegistrar( 18 | registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); 19 | ScreenBrightnessWindowsPluginRegisterWithRegistrar( 20 | registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin")); 21 | UrlLauncherWindowsRegisterWithRegistrar( 22 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 23 | } 24 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | file_selector_windows 7 | permission_handler_windows 8 | screen_brightness_windows 9 | url_launcher_windows 10 | ) 11 | 12 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 13 | ) 14 | 15 | set(PLUGIN_BUNDLED_LIBRARIES) 16 | 17 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 18 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 19 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 20 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 21 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 22 | endforeach(plugin) 23 | 24 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 25 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 26 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 27 | endforeach(ffi_plugin) 28 | -------------------------------------------------------------------------------- /windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} WIN32 10 | "flutter_window.cpp" 11 | "main.cpp" 12 | "utils.cpp" 13 | "win32_window.cpp" 14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 15 | "Runner.rc" 16 | "runner.exe.manifest" 17 | ) 18 | 19 | # Apply the standard set of build settings. This can be removed for applications 20 | # that need different build settings. 21 | apply_standard_settings(${BINARY_NAME}) 22 | 23 | # Add preprocessor definitions for the build version. 24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 29 | 30 | # Disable Windows macros that collide with C++ standard library functions. 31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 32 | 33 | # Add dependency libraries and include directories. Add any application-specific 34 | # dependencies here. 35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 36 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") 37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 38 | 39 | # Run the Flutter tool portions of the build. This must not be removed. 40 | add_dependencies(${BINARY_NAME} flutter_assemble) 41 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | 30 | flutter_controller_->engine()->SetNextFrameCallback([&]() { 31 | this->Show(); 32 | }); 33 | 34 | return true; 35 | } 36 | 37 | void FlutterWindow::OnDestroy() { 38 | if (flutter_controller_) { 39 | flutter_controller_ = nullptr; 40 | } 41 | 42 | Win32Window::OnDestroy(); 43 | } 44 | 45 | LRESULT 46 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 47 | WPARAM const wparam, 48 | LPARAM const lparam) noexcept { 49 | // Give Flutter, including plugins, an opportunity to handle window messages. 50 | if (flutter_controller_) { 51 | std::optional result = 52 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 53 | lparam); 54 | if (result) { 55 | return *result; 56 | } 57 | } 58 | 59 | switch (message) { 60 | case WM_FONTCHANGE: 61 | flutter_controller_->engine()->ReloadSystemFonts(); 62 | break; 63 | } 64 | 65 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 66 | } 67 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(200, 10); 29 | Win32Window::Size size(720/2, 1280/2); 30 | if (!window.Create(L"alist", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | window.SetQuitOnClose(true); 34 | 35 | ::MSG msg; 36 | while (::GetMessage(&msg, nullptr, 0, 0)) { 37 | ::TranslateMessage(&msg); 38 | ::DispatchMessage(&msg); 39 | } 40 | 41 | ::CoUninitialize(); 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BFWXKJGS/AlistClient/98a794eb7c7ce70449ee20f0c1ccaa887812d9f8/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr); 51 | std::string utf8_string; 52 | if (target_length == 0 || target_length > utf8_string.max_size()) { 53 | return utf8_string; 54 | } 55 | utf8_string.resize(target_length); 56 | int converted_length = ::WideCharToMultiByte( 57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 58 | -1, utf8_string.data(), 59 | target_length, nullptr, nullptr); 60 | if (converted_length == 0) { 61 | return std::string(); 62 | } 63 | return utf8_string; 64 | } 65 | -------------------------------------------------------------------------------- /windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | --------------------------------------------------------------------------------