├── .github └── workflows │ └── static.yml ├── .gitignore ├── .idea ├── .gitignore ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── compiler.xml ├── dbnavigator.xml ├── deploymentTargetDropDown.xml ├── deploymentTargetSelector.xml ├── gradle.xml ├── inspectionProfiles │ └── Project_Default.xml ├── jpa-buddy.xml ├── jsonSchemas.xml ├── migrations.xml ├── misc.xml ├── php.xml ├── runConfigurations.xml └── vcs.xml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── lanzou │ │ └── cloud │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── js │ │ │ └── user.js │ │ └── litepal.xml │ ├── java │ │ └── com │ │ │ └── lanzou │ │ │ └── cloud │ │ │ ├── LanzouApplication.java │ │ │ ├── LanzouGlideModule.java │ │ │ ├── MainActivity.java │ │ │ ├── adapter │ │ │ ├── DownloadAdapter.java │ │ │ ├── FileAdapter.java │ │ │ ├── FileSelectorAdapter.java │ │ │ ├── FolderListAdapter.java │ │ │ ├── MainPageAdapter.java │ │ │ ├── PathAdapter.java │ │ │ ├── SimpleListAdapter.java │ │ │ ├── TransmissionAdapter.java │ │ │ ├── TransmissionViewHolder.java │ │ │ └── UploadAdapter.java │ │ │ ├── base │ │ │ └── BaseActivity.java │ │ │ ├── data │ │ │ ├── Download.java │ │ │ ├── FileInfo.java │ │ │ ├── LanzouDownloadResponse.java │ │ │ ├── LanzouFile.java │ │ │ ├── LanzouFileResponse.java │ │ │ ├── LanzouFolder.java │ │ │ ├── LanzouFolderResponse.java │ │ │ ├── LanzouPage.java │ │ │ ├── LanzouSimpleResponse.java │ │ │ ├── LanzouTask.java │ │ │ ├── LanzouUploadResponse.java │ │ │ ├── LanzouUrl.java │ │ │ ├── LanzouUrlResponse.java │ │ │ ├── Question.java │ │ │ ├── SimpleItem.java │ │ │ ├── SplitFile.java │ │ │ ├── Upload.java │ │ │ ├── UploadTask.java │ │ │ └── User.java │ │ │ ├── event │ │ │ ├── FileActionListener.java │ │ │ ├── OnDownloadListener.java │ │ │ ├── OnFileIOListener.java │ │ │ ├── OnItemClickListener.java │ │ │ ├── OnItemLongClickListener.java │ │ │ ├── OnUploadListener.java │ │ │ └── Searchable.java │ │ │ ├── network │ │ │ ├── FileRequestBody.java │ │ │ └── Repository.java │ │ │ ├── service │ │ │ ├── DownloadService.java │ │ │ ├── LanzouService.java │ │ │ └── UploadService.java │ │ │ ├── ui │ │ │ ├── LinearItemDecoration.java │ │ │ ├── dialog │ │ │ │ └── UserDialog.java │ │ │ ├── download │ │ │ │ ├── DownloadInfoActivity.java │ │ │ │ └── DownloadListFragment.java │ │ │ ├── file │ │ │ │ ├── AbstractFileAction.java │ │ │ │ ├── FileFragment.java │ │ │ │ └── imple │ │ │ │ │ └── FileActionImpl.java │ │ │ ├── folder │ │ │ │ └── FolderSelectorActivity.java │ │ │ ├── me │ │ │ │ └── MeFragment.java │ │ │ ├── question │ │ │ │ └── QuestionActivity.java │ │ │ ├── resolve │ │ │ │ └── ResolveFileActivity.java │ │ │ ├── selector │ │ │ │ ├── FileSelectorActivity.java │ │ │ │ ├── FileSelectorFragment.java │ │ │ │ ├── PhoneFileActivity.java │ │ │ │ └── PhoneFileSelectorFragment.java │ │ │ ├── setting │ │ │ │ └── SettingActivity.java │ │ │ ├── transmission │ │ │ │ ├── TransmissionFragment.java │ │ │ │ └── TransmissionListActivity.java │ │ │ ├── upload │ │ │ │ ├── ExternalUploadActivity.java │ │ │ │ ├── UploadInfoActivity.java │ │ │ │ └── UploadListFragment.java │ │ │ └── web │ │ │ │ └── WebActivity.java │ │ │ └── utils │ │ │ ├── ApkLoaderFactory.java │ │ │ ├── DisplayUtils.java │ │ │ ├── FileUtils.java │ │ │ ├── SpUtils.java │ │ │ ├── UpdateUtils.java │ │ │ └── UriUtils.java │ └── res │ │ ├── color │ │ └── color_card.xml │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── baseline_add_24.xml │ │ ├── baseline_chevron_right_24.xml │ │ ├── baseline_delete_outline_24.xml │ │ ├── baseline_done_24.xml │ │ ├── baseline_folder_24.xml │ │ ├── baseline_get_app_24.xml │ │ ├── baseline_home_24.xml │ │ ├── baseline_insert_drive_file_24.xml │ │ ├── baseline_pause_circle_filled_24.xml │ │ ├── baseline_person_24.xml │ │ ├── baseline_play_circle_filled_24.xml │ │ ├── baseline_search_24.xml │ │ ├── baseline_settings_24.xml │ │ ├── baseline_share_24.xml │ │ ├── baseline_sync_alt_24.xml │ │ ├── bg_card.xml │ │ ├── ic_corner_left.xml │ │ ├── ic_corner_right.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_select.xml │ │ ├── ic_select_icon.xml │ │ └── ic_toggle.xml │ │ ├── layout │ │ ├── activity_download_info.xml │ │ ├── activity_external_upload.xml │ │ ├── activity_file_selector.xml │ │ ├── activity_folder_selector.xml │ │ ├── activity_main.xml │ │ ├── activity_phone_file.xml │ │ ├── activity_question.xml │ │ ├── activity_resolve_file.xml │ │ ├── activity_setting.xml │ │ ├── activity_transmission_list.xml │ │ ├── activity_upload_info.xml │ │ ├── activity_webview.xml │ │ ├── content_header.xml │ │ ├── dialog_create_folder.xml │ │ ├── dialog_file_action.xml │ │ ├── fragment_file.xml │ │ ├── fragment_file_selector.xml │ │ ├── fragment_me.xml │ │ ├── fragment_phone_file_selector.xml │ │ ├── fragment_transmission.xml │ │ ├── fragment_transmission_list.xml │ │ ├── item_list_file.xml │ │ ├── item_list_file_selector.xml │ │ ├── item_list_folder.xml │ │ ├── item_list_left.xml │ │ ├── item_list_right.xml │ │ ├── item_list_simple.xml │ │ ├── item_list_transmission.xml │ │ ├── item_path.xml │ │ ├── layout_button_upload.xml │ │ └── window_download_file.xml │ │ ├── menu │ │ ├── menu_bottom.xml │ │ ├── menu_file_selector.xml │ │ └── menu_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-anydpi-v33 │ │ └── ic_launcher.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values-land │ │ └── dimens.xml │ │ ├── values-night │ │ ├── colors.xml │ │ └── themes.xml │ │ ├── values-w1240dp │ │ └── dimens.xml │ │ ├── values-w600dp │ │ └── dimens.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ ├── data_extraction_rules.xml │ │ └── file_paths.xml │ └── test │ └── java │ └── com │ └── lanzou │ └── cloud │ ├── ExampleUnitTest.java │ └── LanzouDownload.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── version.json /.github/workflows/static.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: Deploy static content to Pages 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["master"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 19 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 20 | concurrency: 21 | group: "pages" 22 | cancel-in-progress: false 23 | 24 | jobs: 25 | # Single deploy job since we're just deploying 26 | deploy: 27 | environment: 28 | name: github-pages 29 | url: ${{ steps.deployment.outputs.page_url }} 30 | runs-on: ubuntu-latest 31 | steps: 32 | - name: Checkout 33 | uses: actions/checkout@v4 34 | - name: Setup Pages 35 | uses: actions/configure-pages@v5 36 | - name: Upload artifact 37 | uses: actions/upload-pages-artifact@v3 38 | with: 39 | # Upload entire repository 40 | path: '.' 41 | - name: Deploy to GitHub Pages 42 | id: deployment 43 | uses: actions/deploy-pages@v4 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 21 | 22 | 26 | 27 | 28 | 140 | 141 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/deploymentTargetDropDown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/deploymentTargetSelector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | -------------------------------------------------------------------------------- /.idea/jpa-buddy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/jsonSchemas.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /.idea/migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | -------------------------------------------------------------------------------- /.idea/php.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | 12 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SplitLanzou 2 | 3 | 突破上传文件限制,**分割上传文件,第三方蓝奏云** 4 | 5 | > 特别说明:本项目为**蓝奏云(lanzou.com)的第三方客户端**,本项目不存储任何文件和资源。项目采用 6 | > 分割文件方式达到上传储存目的,任何用户二次开发本项目行为,**本项目概不负责**。 7 | > **请勿将本项目用于非法用途,否则一切后果由使用者自己承担。如本项目侵犯了原作者的版权,请立即联系我删除。** 8 | 9 | ## 联系我 10 | 11 | 1. gmail:jiangdongyu54@gmail.com 12 | 2. qq: 2475058223@qq.com 13 | 14 | ## 下载 15 | 16 | ### 1.最新发行版(release) 17 | 18 | > **以下版本不会自动更新,需要手动前往 github gitee 首页进行更新,如存在问题请提 issue** 19 | 20 | 1. [github release](https://github.com/Yu2002s/SplitLanzou/releases) **可能无法访问** 21 | 22 | 2. [gitee release](https://gitee.com/jdy2002/SplitLanzou/releases) **推荐** 23 | 24 | ### 2.其他版本下载 25 | 26 | > 以下版本比本项目**功能更加完善**,可以辅助本项目使用。但是**可能存在问题**,不会发布正式更新,后期可能修复问题,可在 27 | > App 内加入交流群获得更新 28 | 29 | 1. **可能存在问题** [LanzouCloud 下载](https://github.com/Yu2002s/LanzouCloud) 30 | | 31 | [云盘下载](https://jdy2002.lanzoue.com/b041496oj) (密码: 123456) 32 | 33 | 2. **下载目前有问题** [雨盘下载](https://jdy2002.lanzoue.com/b040cdb5g) (密码: hyf3) 34 | 35 | ## 项目 36 | 37 | 编译此项目需要的一些修改 38 | 39 | ### 本项目依赖环境: 40 | 41 | 1. jdk21 42 | 2. gradle8.11.1 43 | 3. AndroidStudio 2024.2.2 (AS 版本太高,jdk 也高,需要手动设置 jdk 版本) 44 | 45 | 其他环境可能无法成功编译 46 | 47 | ### 修改签名 48 | 49 | ```gradle 50 | // /app/build.gradle 51 | android { 52 | signingConfigs { 53 | debug { 54 | // 修改签名信息 55 | } 56 | release { 57 | // ... 58 | } 59 | } 60 | } 61 | ``` 62 | 63 | ## 问题 64 | 65 | ~~1. 没有文件选择器上传文件~~ 66 | 67 | > 解决办法: 使用外部文件管理器分享(可多选)文件,选择 SplitLanzou 上传文件。 68 | > 或者使用 [雨盘下载](https://jdy2002.lanzoue.com/b040cdb5g) (密码: hyf3) 69 | 70 | 2. 文件列表没有图标 71 | 72 | > 懒得做了 73 | 74 | 3. 可以分享 100M 文件嘛? 75 | 76 | > 支持,但是新用户注册的,只有一次下载机会,第二次网页下载会报错,需要对方也下载此 App 77 | 78 | ## 截图 79 | 80 | 文件管理截图,支持上传、下载、分享并显示**100m+**文件 81 | 82 | 83 | 84 | 85 | 86 | ## 关于 87 | 88 | 1. 开发时间较短,可能有一些 bug,欢迎提 issue。 89 | 2. App 不会自动更新,请前往本主页手动获取更新。 90 | 3. 代码全部开源,不用担心后门问题。 91 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | // id 'androidx.navigation.safeargs' 4 | } 5 | 6 | android { 7 | signingConfigs { 8 | debug { 9 | storeFile file('D:\\jdy2002\\appkey\\jdy.jks') 10 | storePassword 'jdy200255' 11 | keyAlias 'jdy2002' 12 | keyPassword 'jdy200255' 13 | } 14 | release { 15 | storeFile file('D:\\jdy2002\\appkey\\jdy.jks') 16 | storePassword 'jdy200255' 17 | keyAlias 'jdy2002' 18 | keyPassword 'jdy200255' 19 | } 20 | } 21 | namespace 'com.lanzou.cloud' 22 | compileSdk 34 23 | 24 | defaultConfig { 25 | applicationId "com.lanzou.cloud" 26 | minSdk 24 27 | targetSdk 34 28 | versionCode 10 29 | versionName "1.7.1" 30 | 31 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 32 | signingConfig signingConfigs.debug 33 | } 34 | 35 | buildTypes { 36 | release { 37 | minifyEnabled false 38 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 39 | } 40 | } 41 | compileOptions { 42 | sourceCompatibility JavaVersion.VERSION_1_8 43 | targetCompatibility JavaVersion.VERSION_1_8 44 | } 45 | buildFeatures { 46 | viewBinding true 47 | } 48 | } 49 | 50 | dependencies { 51 | 52 | implementation 'androidx.appcompat:appcompat:1.6.1' 53 | implementation 'com.google.android.material:material:1.7.0' 54 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4' 55 | // https://mvnrepository.com/artifact/androidx.recyclerview/recyclerview 56 | implementation 'androidx.recyclerview:recyclerview:1.3.0' 57 | 58 | implementation 'com.squareup.retrofit2:retrofit:2.9.0' 59 | implementation 'com.squareup.retrofit2:converter-gson:2.9.0' 60 | 61 | implementation 'org.litepal.guolindev:core:3.2.3' 62 | implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' 63 | 64 | implementation 'com.github.javakam:file.core:3.7.0@aar' 65 | 66 | // https://mvnrepository.com/artifact/com.github.bumptech.glide/glide 67 | implementation 'com.github.bumptech.glide:glide:4.11.0' 68 | 69 | annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' 70 | 71 | 72 | testImplementation 'junit:junit:4.13.2' 73 | androidTestImplementation 'androidx.test.ext:junit:1.1.3' 74 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 75 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/com/lanzou/cloud/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | assertEquals("com.lanzou.cloud", appContext.getPackageName()); 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 20 | 21 | 22 | 35 | 40 | 43 | 44 | 45 | 47 | 48 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 61 | 64 | 67 | 70 | 72 | 74 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 86 | 91 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /app/src/main/assets/js/user.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | let disk = document.querySelector('.mydisk_bar'); 3 | let username = disk.childNodes[0].data.trim(); 4 | let src = document.querySelector('#mainframe').getAttribute('src'); 5 | src = src.substring(src.lastIndexOf('u=') + 2); 6 | local_obj.saveUser(parseInt(src), username, document.cookie); 7 | })(); 8 | -------------------------------------------------------------------------------- /app/src/main/assets/litepal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/LanzouApplication.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Application; 5 | import android.content.Context; 6 | 7 | import org.litepal.LitePal; 8 | 9 | import ando.file.core.FileOperator; 10 | 11 | /** 12 | * 第三方蓝奏云 (lanzou.com) 13 | * 支持上传 100M+ 文件 14 | */ 15 | public class LanzouApplication extends Application { 16 | 17 | @SuppressLint("StaticFieldLeak") 18 | public static Context context; 19 | 20 | public static final String HOST = "https://pc.woozooo.com/"; 21 | public static final String HOST_FILE = HOST + "mydisk.php"; 22 | 23 | public static final String HOST_LOGIN = HOST + "account.php?action=login"; 24 | 25 | public static final String API_URL = "http://api.jdynb.xyz:6400"; 26 | 27 | public static final String SHARE_URL = "http://lz.jdynb.xyz/index.html"; 28 | 29 | @Override 30 | public void onCreate() { 31 | super.onCreate(); 32 | context = this; 33 | LitePal.initialize(this); 34 | FileOperator.INSTANCE.init(this, false); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/LanzouGlideModule.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import androidx.annotation.NonNull; 7 | 8 | import com.bumptech.glide.Glide; 9 | import com.bumptech.glide.GlideBuilder; 10 | import com.bumptech.glide.Registry; 11 | import com.bumptech.glide.annotation.GlideModule; 12 | import com.bumptech.glide.module.AppGlideModule; 13 | import com.lanzou.cloud.data.FileInfo; 14 | import com.lanzou.cloud.utils.ApkLoaderFactory; 15 | 16 | import java.io.InputStream; 17 | 18 | @GlideModule 19 | public class LanzouGlideModule extends AppGlideModule { 20 | @Override 21 | public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) { 22 | super.applyOptions(context, builder); 23 | } 24 | 25 | @Override 26 | public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) { 27 | // super.registerComponents(context, glide, registry); 28 | registry.prepend(FileInfo.class, InputStream.class, new ApkLoaderFactory(context)); 29 | } 30 | 31 | @Override 32 | public boolean isManifestParsingEnabled() { 33 | return false; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/adapter/DownloadAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.adapter; 2 | 3 | import android.view.View; 4 | 5 | import androidx.annotation.NonNull; 6 | 7 | import com.lanzou.cloud.data.Download; 8 | import com.lanzou.cloud.databinding.ItemListTransmissionBinding; 9 | import com.lanzou.cloud.utils.FileUtils; 10 | 11 | import java.util.List; 12 | 13 | public class DownloadAdapter extends TransmissionAdapter { 14 | 15 | private final List downloads; 16 | 17 | public DownloadAdapter(List downloads) { 18 | this.downloads = downloads; 19 | } 20 | 21 | @Override 22 | public void onBindViewHolder(@NonNull TransmissionViewHolder holder, int position) { 23 | ItemListTransmissionBinding binding = holder.binding; 24 | Download download = downloads.get(position); 25 | binding.tvName.setText(download.getName()); 26 | updateView(binding, download); 27 | } 28 | 29 | @Override 30 | public void onBindViewHolder(@NonNull TransmissionViewHolder holder, int position, @NonNull List payloads) { 31 | if (payloads.isEmpty()) { 32 | super.onBindViewHolder(holder, position, payloads); 33 | return; 34 | } 35 | ItemListTransmissionBinding binding = holder.binding; 36 | Download download = downloads.get(position); 37 | 38 | updateView(binding, download); 39 | } 40 | 41 | private void updateView(ItemListTransmissionBinding binding, Download download) { 42 | binding.tvDesc.setText(download.getStatusStr() + " " + FileUtils.toSize(download.getCurrent()) 43 | + "/" + FileUtils.toSize(download.getLength()) + " " + FileUtils.toSize(download.getSpeed()) + "/s"); 44 | binding.progressBar.setVisibility(download.isComplete() ? View.GONE: View.VISIBLE); 45 | binding.progressBar.setProgress(download.getProgress()); 46 | binding.btnToggle.setVisibility(download.isComplete() ? View.GONE: View.VISIBLE); 47 | binding.btnToggle.setBackground(download.isDownload() ? pause : resume); 48 | } 49 | 50 | @Override 51 | public int getItemCount() { 52 | return downloads.size(); 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/adapter/FolderListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.adapter; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.TextView; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.recyclerview.widget.DiffUtil; 10 | import androidx.recyclerview.widget.ListAdapter; 11 | import androidx.recyclerview.widget.RecyclerView; 12 | 13 | import com.lanzou.cloud.R; 14 | import com.lanzou.cloud.data.LanzouFolder; 15 | import com.lanzou.cloud.event.OnItemClickListener; 16 | 17 | public class FolderListAdapter extends ListAdapter { 18 | 19 | private OnItemClickListener listener; 20 | 21 | public void setOnItemClickListener(OnItemClickListener listener) { 22 | this.listener = listener; 23 | } 24 | 25 | public FolderListAdapter() { 26 | super(new DiffUtil.ItemCallback() { 27 | @Override 28 | public boolean areItemsTheSame(@NonNull LanzouFolder oldItem, @NonNull LanzouFolder newItem) { 29 | return oldItem == newItem; 30 | } 31 | 32 | @Override 33 | public boolean areContentsTheSame(@NonNull LanzouFolder oldItem, @NonNull LanzouFolder newItem) { 34 | return oldItem.getFolder_id() == newItem.getFolder_id(); 35 | } 36 | }); 37 | } 38 | 39 | @NonNull 40 | @Override 41 | public FolderListAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 42 | View itemView = LayoutInflater.from(parent.getContext()) 43 | .inflate(R.layout.item_list_folder, parent, false); 44 | ViewHolder viewHolder = new ViewHolder(itemView); 45 | itemView.setOnClickListener(v -> listener.onItemClick(viewHolder.getAbsoluteAdapterPosition(), v)); 46 | return viewHolder; 47 | } 48 | 49 | @Override 50 | public void onBindViewHolder(@NonNull FolderListAdapter.ViewHolder holder, int position) { 51 | LanzouFolder lanzouFolder = getItem(position); 52 | holder.title.setText(lanzouFolder.getFolder_name()); 53 | holder.sub.setText(String.valueOf(lanzouFolder.getFolder_id())); 54 | } 55 | 56 | public static class ViewHolder extends RecyclerView.ViewHolder { 57 | TextView title; 58 | TextView sub; 59 | 60 | public ViewHolder(@NonNull View itemView) { 61 | super(itemView); 62 | title = itemView.findViewById(R.id.tv_title); 63 | sub = itemView.findViewById(R.id.tv_sub); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/adapter/MainPageAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.adapter; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.fragment.app.Fragment; 5 | import androidx.fragment.app.FragmentManager; 6 | import androidx.lifecycle.Lifecycle; 7 | import androidx.viewpager2.adapter.FragmentStateAdapter; 8 | 9 | import com.lanzou.cloud.ui.file.FileFragment; 10 | import com.lanzou.cloud.ui.me.MeFragment; 11 | import com.lanzou.cloud.ui.transmission.TransmissionFragment; 12 | 13 | public class MainPageAdapter extends FragmentStateAdapter { 14 | 15 | public MainPageAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) { 16 | super(fragmentManager, lifecycle); 17 | } 18 | 19 | @NonNull 20 | @Override 21 | public Fragment createFragment(int position) { 22 | switch (position) { 23 | case 0: return new FileFragment(); 24 | case 1: return new TransmissionFragment(); 25 | default: return new MeFragment(); 26 | } 27 | } 28 | 29 | @Override 30 | public int getItemCount() { 31 | return 3; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/adapter/PathAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.adapter; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.TextView; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | 11 | import com.lanzou.cloud.data.LanzouPage; 12 | import com.lanzou.cloud.databinding.ItemPathBinding; 13 | import com.lanzou.cloud.event.OnItemClickListener; 14 | 15 | import java.util.List; 16 | 17 | public class PathAdapter extends RecyclerView.Adapter { 18 | 19 | private final List list; 20 | 21 | public PathAdapter(List list) { 22 | this.list = list; 23 | } 24 | 25 | private OnItemClickListener listener; 26 | 27 | public void setListener(OnItemClickListener listener) { 28 | this.listener = listener; 29 | } 30 | 31 | @NonNull 32 | @Override 33 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 34 | View itemView = ItemPathBinding.inflate(LayoutInflater. 35 | from(parent.getContext()), parent, false).getRoot(); 36 | ViewHolder viewHolder = new ViewHolder(itemView); 37 | viewHolder.itemView.setOnClickListener(new View.OnClickListener() { 38 | @Override 39 | public void onClick(View v) { 40 | listener.onItemClick(viewHolder.getAdapterPosition(), v); 41 | } 42 | }); 43 | return viewHolder; 44 | } 45 | 46 | @Override 47 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 48 | ((TextView) holder.itemView).setText(list.get(position).getName()); 49 | } 50 | 51 | @Override 52 | public int getItemCount() { 53 | return list.size(); 54 | } 55 | 56 | public static class ViewHolder extends RecyclerView.ViewHolder { 57 | 58 | public ViewHolder(@NonNull View itemView) { 59 | super(itemView); 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/adapter/SimpleListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.adapter; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.BaseAdapter; 7 | import android.widget.TextView; 8 | 9 | import androidx.core.content.ContextCompat; 10 | 11 | import com.lanzou.cloud.R; 12 | import com.lanzou.cloud.data.SimpleItem; 13 | import com.lanzou.cloud.databinding.ItemListSimpleBinding; 14 | 15 | import java.util.List; 16 | 17 | public class SimpleListAdapter extends BaseAdapter { 18 | 19 | private final List list; 20 | 21 | public SimpleListAdapter(List list) { 22 | this.list = list; 23 | } 24 | 25 | @Override 26 | public int getCount() { 27 | return list.size(); 28 | } 29 | 30 | @Override 31 | public Object getItem(int position) { 32 | return list.get(position); 33 | } 34 | 35 | @Override 36 | public long getItemId(int position) { 37 | return 0; 38 | } 39 | 40 | @Override 41 | public View getView(int position, View convertView, ViewGroup parent) { 42 | if (convertView == null) { 43 | ItemListSimpleBinding binding = ItemListSimpleBinding 44 | .inflate(LayoutInflater.from(parent.getContext())); 45 | convertView = binding.getRoot(); 46 | } 47 | SimpleItem simpleItem = list.get(position); 48 | TextView tv = ((TextView) convertView); 49 | tv.setText(simpleItem.getTitle()); 50 | tv.setCompoundDrawablePadding(30); 51 | tv.setCompoundDrawablesRelativeWithIntrinsicBounds( 52 | ContextCompat.getDrawable(parent.getContext(), simpleItem.getIcon()) 53 | , null, null, null); 54 | return convertView; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/adapter/TransmissionAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.adapter; 2 | 3 | import android.graphics.drawable.Drawable; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.core.content.ContextCompat; 10 | import androidx.recyclerview.widget.RecyclerView; 11 | 12 | import com.lanzou.cloud.R; 13 | import com.lanzou.cloud.databinding.ItemListTransmissionBinding; 14 | import com.lanzou.cloud.event.OnItemClickListener; 15 | 16 | public class TransmissionAdapter extends RecyclerView.Adapter { 17 | 18 | private OnItemClickListener itemClickListener; 19 | 20 | private OnItemClickListener toggleTransmissionListener; 21 | 22 | public void setToggleTransmissionListener(OnItemClickListener toggleUploadListener) { 23 | this.toggleTransmissionListener = toggleUploadListener; 24 | } 25 | 26 | public void setItemClickListener(OnItemClickListener itemClickListener) { 27 | this.itemClickListener = itemClickListener; 28 | } 29 | 30 | Drawable resume; 31 | Drawable pause; 32 | 33 | @Override 34 | public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { 35 | super.onAttachedToRecyclerView(recyclerView); 36 | pause = ContextCompat.getDrawable(recyclerView.getContext(), R.drawable.baseline_pause_circle_filled_24); 37 | resume = ContextCompat.getDrawable(recyclerView.getContext(), R.drawable.baseline_play_circle_filled_24); 38 | } 39 | 40 | @NonNull 41 | @Override 42 | public TransmissionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 43 | ItemListTransmissionBinding binding = ItemListTransmissionBinding 44 | .inflate(LayoutInflater.from(parent.getContext()), parent, false); 45 | TransmissionViewHolder viewHolder = new TransmissionViewHolder(binding); 46 | binding.btnToggle.setOnClickListener(new View.OnClickListener() { 47 | @Override 48 | public void onClick(View v) { 49 | toggleTransmissionListener.onItemClick(viewHolder.getAdapterPosition(), v); 50 | } 51 | }); 52 | binding.getRoot().setOnClickListener(new View.OnClickListener() { 53 | @Override 54 | public void onClick(View v) { 55 | itemClickListener.onItemClick(viewHolder.getAdapterPosition(), v); 56 | } 57 | }); 58 | return viewHolder; 59 | } 60 | 61 | @Override 62 | public void onBindViewHolder(@NonNull TransmissionViewHolder holder, int position) { 63 | } 64 | 65 | @Override 66 | public int getItemCount() { 67 | return 0; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/adapter/TransmissionViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.adapter; 2 | 3 | import androidx.recyclerview.widget.RecyclerView; 4 | 5 | import com.lanzou.cloud.databinding.ItemListTransmissionBinding; 6 | 7 | public class TransmissionViewHolder extends RecyclerView.ViewHolder { 8 | ItemListTransmissionBinding binding; 9 | 10 | public TransmissionViewHolder(ItemListTransmissionBinding binding) { 11 | super(binding.getRoot()); 12 | this.binding = binding; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/adapter/UploadAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.adapter; 2 | 3 | import android.view.View; 4 | 5 | import androidx.annotation.NonNull; 6 | 7 | import com.lanzou.cloud.R; 8 | import com.lanzou.cloud.data.Upload; 9 | import com.lanzou.cloud.databinding.ItemListTransmissionBinding; 10 | import com.lanzou.cloud.utils.FileUtils; 11 | 12 | import java.util.List; 13 | 14 | public class UploadAdapter extends TransmissionAdapter { 15 | 16 | private final List uploads; 17 | 18 | public UploadAdapter(List uploads) { 19 | this.uploads = uploads; 20 | } 21 | 22 | @Override 23 | public void onBindViewHolder(@NonNull TransmissionViewHolder holder, int position) { 24 | Upload upload = uploads.get(position); 25 | ItemListTransmissionBinding binding = holder.binding; 26 | binding.tvName.setText(upload.getName()); 27 | updateView(binding, upload); 28 | } 29 | 30 | @Override 31 | public void onBindViewHolder(@NonNull TransmissionViewHolder holder, int position, @NonNull List payloads) { 32 | if (payloads.isEmpty()) { 33 | super.onBindViewHolder(holder, position, payloads); 34 | return; 35 | } 36 | Upload upload = uploads.get(position); 37 | ItemListTransmissionBinding binding = holder.binding; 38 | updateView(binding, upload); 39 | } 40 | 41 | private void updateView(ItemListTransmissionBinding binding, Upload upload) { 42 | binding.tvDesc.setText(upload.getStatusStr() + " " + FileUtils.toSize(upload.getCurrent()) 43 | + "/" + FileUtils.toSize(upload.getLength()) + " " + FileUtils.toSize(upload.getSpeed()) + "/s"); 44 | binding.progressBar.setProgress(upload.getProgress()); 45 | binding.progressBar.setVisibility(upload.isComplete() ? View.GONE: View.VISIBLE); 46 | binding.btnToggle.setVisibility(upload.isComplete() ? View.GONE: View.VISIBLE); 47 | binding.btnToggle.setBackground(upload.isUpload() ? pause : resume); 48 | } 49 | 50 | @Override 51 | public int getItemCount() { 52 | return uploads.size(); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.base; 2 | 3 | import android.os.Bundle; 4 | import android.view.MenuItem; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.annotation.Nullable; 10 | import androidx.appcompat.app.AppCompatActivity; 11 | import androidx.core.view.ViewCompat; 12 | import androidx.core.view.WindowCompat; 13 | import androidx.core.view.WindowInsetsCompat; 14 | import androidx.recyclerview.widget.RecyclerView; 15 | 16 | public class BaseActivity extends AppCompatActivity { 17 | @Override 18 | protected void onCreate(@Nullable Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | WindowCompat.setDecorFitsSystemWindows(getWindow(), false); 21 | } 22 | 23 | @Override 24 | public void setContentView(View view) { 25 | super.setContentView(view); 26 | getRecyclerView(view); 27 | ViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -> { 28 | int bottom = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom; 29 | if (recyclerView != null) { 30 | recyclerView.setClipToPadding(false); 31 | recyclerView.setPadding(recyclerView.getPaddingStart(), recyclerView.getPaddingTop(), 32 | recyclerView.getPaddingEnd(), recyclerView.getPaddingBottom() + bottom); 33 | } 34 | onApplyInsertBottom(bottom); 35 | return insets; 36 | }); 37 | } 38 | 39 | protected void onApplyInsertBottom(int bottom) { 40 | } 41 | 42 | private RecyclerView recyclerView; 43 | 44 | private void getRecyclerView(View view) { 45 | if (view instanceof ViewGroup) { 46 | ViewGroup viewGroup = (ViewGroup) view; 47 | for (int i = 0; i < viewGroup.getChildCount(); i++) { 48 | View child = viewGroup.getChildAt(i); 49 | if (child instanceof RecyclerView) { 50 | recyclerView = (RecyclerView) child; 51 | } else { 52 | getRecyclerView(child); 53 | } 54 | } 55 | } 56 | } 57 | 58 | @Override 59 | public boolean onOptionsItemSelected(@NonNull MenuItem item) { 60 | if (item.getItemId() == android.R.id.home) { 61 | finish(); 62 | } 63 | return super.onOptionsItemSelected(item); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/FileInfo.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | import android.text.TextUtils; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.annotation.Nullable; 7 | 8 | public class FileInfo implements Comparable { 9 | 10 | private Long id; 11 | 12 | private String name; 13 | 14 | private String uri; 15 | 16 | private Long length; 17 | 18 | private Long time; 19 | 20 | private String pkgName; 21 | 22 | @Nullable 23 | private String extension; 24 | 25 | private String fileDesc; 26 | 27 | public String getFileDesc() { 28 | return fileDesc; 29 | } 30 | 31 | public void setFileDesc(String fileDesc) { 32 | this.fileDesc = fileDesc; 33 | } 34 | 35 | @Nullable 36 | public String getExtension() { 37 | return extension; 38 | } 39 | 40 | public Long getId() { 41 | return id; 42 | } 43 | 44 | public void setId(Long id) { 45 | this.id = id; 46 | } 47 | 48 | public void setExtension(@Nullable String extension) { 49 | this.extension = extension; 50 | } 51 | 52 | public String getPkgName() { 53 | return pkgName; 54 | } 55 | 56 | public void setPkgName(String pkgName) { 57 | this.pkgName = pkgName; 58 | } 59 | 60 | public Long getTime() { 61 | return time; 62 | } 63 | 64 | public void setTime(Long time) { 65 | this.time = time; 66 | } 67 | 68 | private boolean isSelected = false; 69 | 70 | public FileInfo(String name, String uri, Long length) { 71 | this.name = name; 72 | this.uri = uri; 73 | this.length = length; 74 | } 75 | 76 | public Long getLength() { 77 | return length; 78 | } 79 | 80 | public void setLength(Long length) { 81 | this.length = length; 82 | } 83 | 84 | public String getName() { 85 | return name; 86 | } 87 | 88 | public void setName(String name) { 89 | this.name = name; 90 | } 91 | 92 | public String getUri() { 93 | return uri; 94 | } 95 | 96 | public void setUri(String uri) { 97 | this.uri = uri; 98 | } 99 | 100 | public boolean isSelected() { 101 | return isSelected; 102 | } 103 | 104 | public void setSelected(boolean selected) { 105 | isSelected = selected; 106 | } 107 | 108 | public boolean isApp() { 109 | return pkgName != null; 110 | } 111 | 112 | public boolean isApk() { 113 | return "apk".equalsIgnoreCase(extension); 114 | } 115 | 116 | public boolean isDirectory() { 117 | return TextUtils.isEmpty(extension); 118 | } 119 | 120 | public boolean isFile() { 121 | return !isDirectory(); 122 | } 123 | 124 | @Override 125 | public boolean equals(Object o) { 126 | if (this == o) return true; 127 | if (o == null || getClass() != o.getClass()) return false; 128 | 129 | FileInfo fileInfo = (FileInfo) o; 130 | 131 | if (id != null && id.equals(fileInfo.id)) return true; 132 | return uri.equals(fileInfo.uri); 133 | } 134 | 135 | @Override 136 | public int hashCode() { 137 | int result = id != null ? id.hashCode() : 0; 138 | result = 31 * result + uri.hashCode(); 139 | return result; 140 | } 141 | 142 | @NonNull 143 | @Override 144 | public String toString() { 145 | return "FileInfo{" + 146 | "name='" + name + '\'' + 147 | ", uri='" + uri + '\'' + 148 | ", length=" + length + 149 | ", isSelected=" + isSelected + 150 | '}'; 151 | } 152 | 153 | @Override 154 | public int compareTo(FileInfo o) { 155 | if (isApp() && o.isApp()) { 156 | return o.getTime().compareTo(time); 157 | } 158 | 159 | if (isDirectory() && o.isFile()) { 160 | return -1; 161 | } else if (isFile() && o.isDirectory()) { 162 | return 1; 163 | } 164 | 165 | return name.compareTo(o.getName()); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/LanzouDownloadResponse.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | public class LanzouDownloadResponse { 8 | 9 | @SerializedName("zt") 10 | private int status; 11 | 12 | private String dom; 13 | 14 | private String url; 15 | 16 | private String info; 17 | 18 | public int getStatus() { 19 | return status; 20 | } 21 | 22 | public void setStatus(int status) { 23 | this.status = status; 24 | } 25 | 26 | public String getDom() { 27 | return dom; 28 | } 29 | 30 | public void setDom(String dom) { 31 | this.dom = dom; 32 | } 33 | 34 | public String getUrl() { 35 | return url; 36 | } 37 | 38 | public void setUrl(String url) { 39 | this.url = url; 40 | } 41 | 42 | public String getInfo() { 43 | return info; 44 | } 45 | 46 | public void setInfo(String info) { 47 | this.info = info; 48 | } 49 | 50 | @NonNull 51 | @Override 52 | public String toString() { 53 | return "LanzouDownloadResponse{" + 54 | "status=" + status + 55 | ", dom='" + dom + '\'' + 56 | ", url='" + url + '\'' + 57 | ", info='" + info + '\'' + 58 | '}'; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/LanzouFile.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | import androidx.annotation.NonNull; 7 | 8 | import com.google.gson.annotations.SerializedName; 9 | 10 | public class LanzouFile implements Parcelable { 11 | 12 | @SerializedName("id") 13 | private long fileId; 14 | 15 | @SerializedName("fol_id") 16 | private long folderId; 17 | 18 | private String time; 19 | 20 | @SerializedName("icon") 21 | private String extension; 22 | 23 | @SerializedName("downs") 24 | private int downloadCount; 25 | 26 | private boolean isSelected = false; 27 | 28 | public LanzouFile() {} 29 | 30 | protected LanzouFile(Parcel in) { 31 | fileId = in.readLong(); 32 | folderId = in.readLong(); 33 | time = in.readString(); 34 | extension = in.readString(); 35 | downloadCount = in.readInt(); 36 | size = in.readString(); 37 | name = in.readString(); 38 | name_all = in.readString(); 39 | } 40 | 41 | @Override 42 | public void writeToParcel(Parcel dest, int flags) { 43 | dest.writeLong(fileId); 44 | dest.writeLong(folderId); 45 | dest.writeString(time); 46 | dest.writeString(extension); 47 | dest.writeInt(downloadCount); 48 | dest.writeString(size); 49 | dest.writeString(name); 50 | dest.writeString(name_all); 51 | } 52 | 53 | @Override 54 | public int describeContents() { 55 | return 0; 56 | } 57 | 58 | public static final Creator CREATOR = new Creator() { 59 | @Override 60 | public LanzouFile createFromParcel(Parcel in) { 61 | return new LanzouFile(in); 62 | } 63 | 64 | @Override 65 | public LanzouFile[] newArray(int size) { 66 | return new LanzouFile[size]; 67 | } 68 | }; 69 | 70 | public String getExtension() { 71 | return extension; 72 | } 73 | 74 | public void setExtension(String extension) { 75 | this.extension = extension; 76 | } 77 | 78 | public String getTime() { 79 | return time; 80 | } 81 | 82 | public void setTime(String time) { 83 | this.time = time; 84 | } 85 | 86 | public String getSize() { 87 | return size; 88 | } 89 | 90 | public void setSize(String size) { 91 | this.size = size; 92 | } 93 | 94 | private String size; 95 | 96 | public long getFolderId() { 97 | return folderId; 98 | } 99 | 100 | public long getFileId() { 101 | return fileId; 102 | } 103 | 104 | public void setFileId(long fileId) { 105 | this.fileId = fileId; 106 | } 107 | 108 | public void setFolderId(long folderId) { 109 | this.folderId = folderId; 110 | } 111 | 112 | public int getDownloadCount() { 113 | return downloadCount; 114 | } 115 | 116 | public void setDownloadCount(int downloadCount) { 117 | this.downloadCount = downloadCount; 118 | } 119 | 120 | public boolean isFolder() { 121 | return folderId != 0; 122 | } 123 | 124 | private String name; 125 | private String name_all; 126 | 127 | public String getName() { 128 | return name; 129 | } 130 | 131 | public void setName(String name) { 132 | this.name = name; 133 | } 134 | 135 | public String getName_all() { 136 | return name_all; 137 | } 138 | 139 | public void setName_all(String name_all) { 140 | this.name_all = name_all; 141 | } 142 | 143 | public String getFileName() { 144 | return isFolder() ? name : name_all; 145 | } 146 | 147 | public void setSelected(boolean selected) { 148 | isSelected = selected; 149 | } 150 | 151 | public boolean isSelected() { 152 | return isSelected; 153 | } 154 | 155 | @Override 156 | public boolean equals(Object o) { 157 | if (this == o) return true; 158 | if (o == null || getClass() != o.getClass()) return false; 159 | 160 | LanzouFile that = (LanzouFile) o; 161 | 162 | if (isFolder() && folderId == that.folderId) return true; 163 | return fileId != 0 && fileId == that.fileId; 164 | } 165 | 166 | @Override 167 | public int hashCode() { 168 | int result = Long.hashCode(fileId); 169 | result = 31 * result + Long.hashCode(folderId); 170 | return result; 171 | } 172 | 173 | @NonNull 174 | @Override 175 | public String toString() { 176 | return "LanzouFile{" + 177 | "fileId=" + fileId + 178 | ", folderId=" + folderId + 179 | ", name='" + name + '\'' + 180 | ", name_all='" + name_all + '\'' + 181 | '}'; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/LanzouFileResponse.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.List; 6 | 7 | public class LanzouFileResponse { 8 | 9 | @SerializedName("zt") 10 | private Integer status; 11 | @SerializedName("text") 12 | private List files; 13 | 14 | public Integer getStatus() { 15 | return status; 16 | } 17 | 18 | public void setStatus(Integer status) { 19 | this.status = status; 20 | } 21 | 22 | public List getFiles() { 23 | return files; 24 | } 25 | 26 | public void setFiles(List files) { 27 | this.files = files; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/LanzouFolder.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | public class LanzouFolder { 4 | 5 | private long folder_id; 6 | private String folder_name; 7 | 8 | public LanzouFolder() { 9 | } 10 | 11 | public LanzouFolder(long folder_id, String folder_name) { 12 | this.folder_id = folder_id; 13 | this.folder_name = folder_name; 14 | } 15 | 16 | public long getFolder_id() { 17 | return folder_id; 18 | } 19 | 20 | public void setFolder_id(long folder_id) { 21 | this.folder_id = folder_id; 22 | } 23 | 24 | public String getFolder_name() { 25 | return folder_name; 26 | } 27 | 28 | public void setFolder_name(String folder_name) { 29 | this.folder_name = folder_name; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/LanzouFolderResponse.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.List; 6 | 7 | public class LanzouFolderResponse { 8 | 9 | @SerializedName("zt") 10 | private int status; 11 | 12 | @SerializedName("info") 13 | private List folders; 14 | 15 | public int getStatus() { 16 | return status; 17 | } 18 | 19 | public void setStatus(int status) { 20 | this.status = status; 21 | } 22 | 23 | public List getFolders() { 24 | return folders; 25 | } 26 | 27 | public void setFolders(List folders) { 28 | this.folders = folders; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/LanzouPage.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class LanzouPage implements Parcelable { 10 | 11 | private long folderId; 12 | 13 | private String name; 14 | 15 | private int page = 1; 16 | 17 | private boolean isCompleted = false; 18 | private boolean isNull = false; 19 | 20 | public LanzouPage() { 21 | } 22 | 23 | protected LanzouPage(Parcel in) { 24 | folderId = in.readLong(); 25 | name = in.readString(); 26 | page = in.readInt(); 27 | isCompleted = in.readByte() != 0; 28 | isNull = in.readByte() != 0; 29 | } 30 | 31 | @Override 32 | public void writeToParcel(Parcel dest, int flags) { 33 | dest.writeLong(folderId); 34 | dest.writeString(name); 35 | dest.writeInt(page); 36 | dest.writeByte((byte) (isCompleted ? 1 : 0)); 37 | dest.writeByte((byte) (isNull ? 1 : 0)); 38 | } 39 | 40 | @Override 41 | public int describeContents() { 42 | return 0; 43 | } 44 | 45 | public static final Creator CREATOR = new Creator() { 46 | @Override 47 | public LanzouPage createFromParcel(Parcel in) { 48 | return new LanzouPage(in); 49 | } 50 | 51 | @Override 52 | public LanzouPage[] newArray(int size) { 53 | return new LanzouPage[size]; 54 | } 55 | }; 56 | 57 | public boolean isCompleted() { 58 | return isCompleted; 59 | } 60 | 61 | public void setCompleted(boolean completed) { 62 | isCompleted = completed; 63 | } 64 | 65 | public boolean isNull() { 66 | return isNull; 67 | } 68 | 69 | public boolean isNotNull() { 70 | return !isNull(); 71 | } 72 | 73 | public void setNull(boolean aNull) { 74 | isNull = aNull; 75 | } 76 | 77 | public int getPage() { 78 | return page; 79 | } 80 | 81 | public void setPage(int page) { 82 | this.page = page; 83 | } 84 | 85 | public void nextPage() { 86 | page++; 87 | } 88 | 89 | private final List files = new ArrayList<>(); 90 | 91 | public long getFolderId() { 92 | return folderId; 93 | } 94 | 95 | public void setFolderId(long folderId) { 96 | this.folderId = folderId; 97 | } 98 | 99 | public String getName() { 100 | return name; 101 | } 102 | 103 | public void setName(String name) { 104 | this.name = name; 105 | } 106 | 107 | public List getFiles() { 108 | return files; 109 | } 110 | 111 | public void addFiles(List files) { 112 | this.files.addAll(files); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/LanzouSimpleResponse.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | public class LanzouSimpleResponse { 6 | 7 | @SerializedName("zt") 8 | private int status; 9 | 10 | private String info; 11 | 12 | private String text; 13 | 14 | public int getStatus() { 15 | return status; 16 | } 17 | 18 | public void setStatus(int status) { 19 | this.status = status; 20 | } 21 | 22 | public String getInfo() { 23 | return info; 24 | } 25 | 26 | public void setInfo(String info) { 27 | this.info = info; 28 | } 29 | 30 | public String getText() { 31 | return text; 32 | } 33 | 34 | public void setText(String text) { 35 | this.text = text; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/LanzouTask.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | /** 4 | * 对应 Lanzou 的各种文件操作的 task 5 | */ 6 | public enum LanzouTask { 7 | 8 | /** 9 | * 获取文件列表 10 | */ 11 | GET_FILES(5), 12 | /** 13 | * 获取文件夹列表 14 | */ 15 | GET_FOLDERS(47); 16 | 17 | public final Integer id; 18 | 19 | LanzouTask(Integer id) { 20 | this.id = id; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/LanzouUploadResponse.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import java.util.List; 8 | 9 | public class LanzouUploadResponse { 10 | 11 | @SerializedName("zt") 12 | private int status; 13 | 14 | private String info; 15 | 16 | @SerializedName("text") 17 | private List uploadInfos; 18 | 19 | public int getStatus() { 20 | return status; 21 | } 22 | 23 | public void setStatus(int status) { 24 | this.status = status; 25 | } 26 | 27 | public String getInfo() { 28 | return info; 29 | } 30 | 31 | public void setInfo(String info) { 32 | this.info = info; 33 | } 34 | 35 | public List getUploadInfos() { 36 | return uploadInfos; 37 | } 38 | 39 | public void setUploadInfos(List uploadInfos) { 40 | this.uploadInfos = uploadInfos; 41 | } 42 | 43 | public static class UploadInfo { 44 | @SerializedName("f_id") 45 | private String fileId; 46 | private String name_all; 47 | private long id; 48 | private String size; 49 | 50 | public String getFileId() { 51 | return fileId; 52 | } 53 | 54 | public void setFileId(String fileId) { 55 | this.fileId = fileId; 56 | } 57 | 58 | public String getName_all() { 59 | return name_all; 60 | } 61 | 62 | public void setName_all(String name_all) { 63 | this.name_all = name_all; 64 | } 65 | 66 | public long getId() { 67 | return id; 68 | } 69 | 70 | public void setId(long id) { 71 | this.id = id; 72 | } 73 | 74 | public String getSize() { 75 | return size; 76 | } 77 | 78 | public void setSize(String size) { 79 | this.size = size; 80 | } 81 | } 82 | 83 | @NonNull 84 | @Override 85 | public String toString() { 86 | return "LanzouUploadResponse{" + 87 | "status=" + status + 88 | ", info='" + info + '\'' + 89 | ", uploadInfos=" + uploadInfos + 90 | '}'; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/LanzouUrl.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | public class LanzouUrl { 8 | 9 | @Nullable 10 | private String pwd; 11 | 12 | @SerializedName("f_id") 13 | private String fileId; 14 | 15 | @SerializedName("is_newd") 16 | private String host; 17 | 18 | @SerializedName("onof") 19 | private int hasPwd; 20 | 21 | @Nullable 22 | public String getPwd() { 23 | return pwd; 24 | } 25 | 26 | public void setPwd(@Nullable String pwd) { 27 | this.pwd = pwd; 28 | } 29 | 30 | public String getFileId() { 31 | return fileId; 32 | } 33 | 34 | public void setFileId(String fileId) { 35 | this.fileId = fileId; 36 | } 37 | 38 | public String getHost() { 39 | return host; 40 | } 41 | 42 | public void setHost(String host) { 43 | this.host = host; 44 | } 45 | 46 | public int getHasPwd() { 47 | return hasPwd; 48 | } 49 | 50 | public void setHasPwd(int hasPwd) { 51 | this.hasPwd = hasPwd; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/LanzouUrlResponse.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | public class LanzouUrlResponse { 6 | 7 | @SerializedName("zt") 8 | private int status; 9 | 10 | private LanzouUrl info; 11 | 12 | public int getStatus() { 13 | return status; 14 | } 15 | 16 | public void setStatus(int status) { 17 | this.status = status; 18 | } 19 | 20 | public LanzouUrl getInfo() { 21 | return info; 22 | } 23 | 24 | public void setInfo(LanzouUrl info) { 25 | this.info = info; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/Question.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | public class Question { 4 | 5 | public static final int LEFT = 0; 6 | public static final int RIGHT = 1; 7 | 8 | private int type; 9 | 10 | private String content; 11 | 12 | public Question(int type, String content) { 13 | this.type = type; 14 | this.content = content; 15 | } 16 | 17 | public int getType() { 18 | return type; 19 | } 20 | 21 | public void setType(int type) { 22 | this.type = type; 23 | } 24 | 25 | public String getContent() { 26 | return content; 27 | } 28 | 29 | public void setContent(String content) { 30 | this.content = content; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/SimpleItem.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | public class SimpleItem { 4 | 5 | String title; 6 | Integer icon; 7 | 8 | public SimpleItem(String title, Integer icon) { 9 | this.title = title; 10 | this.icon = icon; 11 | } 12 | 13 | public String getTitle() { 14 | return title; 15 | } 16 | 17 | public void setTitle(String title) { 18 | this.title = title; 19 | } 20 | 21 | public Integer getIcon() { 22 | return icon; 23 | } 24 | 25 | public void setIcon(Integer icon) { 26 | this.icon = icon; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/SplitFile.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | import androidx.annotation.NonNull; 7 | import androidx.annotation.Nullable; 8 | 9 | import com.google.gson.annotations.Since; 10 | 11 | public class SplitFile implements Parcelable { 12 | 13 | /** 14 | * 文件批次 15 | */ 16 | private int index; 17 | /** 18 | * 起始位置 19 | */ 20 | private long start; 21 | /** 22 | * 结束位置 23 | */ 24 | private long end; 25 | 26 | /** 27 | * 文件大小 28 | */ 29 | private long length; 30 | 31 | /** 32 | * 文件唯一ID 33 | */ 34 | private long fileId; 35 | 36 | /** 37 | * 文件唯一分享地址 这个地址进行AES加密 38 | */ 39 | private String url; 40 | 41 | /** 42 | * 文件下载密码 43 | */ 44 | @Nullable 45 | private String pwd; 46 | 47 | /** 48 | * 控制单个文件字节读取开始位置 49 | */ 50 | @Since(1.1) 51 | private long byteStart; 52 | 53 | public SplitFile() { 54 | } 55 | 56 | protected SplitFile(Parcel in) { 57 | index = in.readInt(); 58 | start = in.readLong(); 59 | end = in.readLong(); 60 | length = in.readLong(); 61 | fileId = in.readLong(); 62 | url = in.readString(); 63 | pwd = in.readString(); 64 | byteStart = in.readLong(); 65 | } 66 | 67 | @Override 68 | public void writeToParcel(Parcel dest, int flags) { 69 | dest.writeInt(index); 70 | dest.writeLong(start); 71 | dest.writeLong(end); 72 | dest.writeLong(length); 73 | dest.writeLong(fileId); 74 | dest.writeString(url); 75 | dest.writeString(pwd); 76 | dest.writeLong(byteStart); 77 | } 78 | 79 | @Override 80 | public int describeContents() { 81 | return 0; 82 | } 83 | 84 | public static final Creator CREATOR = new Creator() { 85 | @Override 86 | public SplitFile createFromParcel(Parcel in) { 87 | return new SplitFile(in); 88 | } 89 | 90 | @Override 91 | public SplitFile[] newArray(int size) { 92 | return new SplitFile[size]; 93 | } 94 | }; 95 | 96 | public int getIndex() { 97 | return index; 98 | } 99 | 100 | public void setIndex(int index) { 101 | this.index = index; 102 | } 103 | 104 | public long getStart() { 105 | return start; 106 | } 107 | 108 | public void setStart(long start) { 109 | this.start = start; 110 | } 111 | 112 | public long getEnd() { 113 | return end; 114 | } 115 | 116 | public void setEnd(long end) { 117 | this.end = end; 118 | } 119 | 120 | public long getLength() { 121 | return length; 122 | } 123 | 124 | public void setLength(long length) { 125 | this.length = length; 126 | } 127 | 128 | public long getFileId() { 129 | return fileId; 130 | } 131 | 132 | public void setFileId(long fileId) { 133 | this.fileId = fileId; 134 | } 135 | 136 | public String getUrl() { 137 | return url; 138 | } 139 | 140 | public void setUrl(String url) { 141 | this.url = url; 142 | } 143 | 144 | @Nullable 145 | public String getPwd() { 146 | return pwd; 147 | } 148 | 149 | public void setPwd(@Nullable String pwd) { 150 | this.pwd = pwd; 151 | } 152 | 153 | public long getByteStart() { 154 | return byteStart; 155 | } 156 | 157 | public void setByteStart(long byteStart) { 158 | this.byteStart = byteStart; 159 | } 160 | 161 | public boolean isComplete() { 162 | return byteStart == length; 163 | } 164 | 165 | @NonNull 166 | @Override 167 | public String toString() { 168 | return "SplitFile{" + 169 | "index=" + index + 170 | ", start=" + start + 171 | ", end=" + end + 172 | ", length=" + length + 173 | ", fileId=" + fileId + 174 | ", url='" + url + '\'' + 175 | ", pwd='" + pwd + '\'' + 176 | '}'; 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/UploadTask.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | import java.util.concurrent.Future; 4 | 5 | public class UploadTask { 6 | 7 | private Upload upload; 8 | private Future task; 9 | 10 | public UploadTask(Upload upload, Future task) { 11 | this.upload = upload; 12 | this.task = task; 13 | } 14 | 15 | public Upload getUpload() { 16 | return upload; 17 | } 18 | 19 | public void setUpload(Upload upload) { 20 | this.upload = upload; 21 | } 22 | 23 | public Future getTask() { 24 | return task; 25 | } 26 | 27 | public void setTask(Future task) { 28 | this.task = task; 29 | } 30 | 31 | @Override 32 | public boolean equals(Object o) { 33 | if (this == o) return true; 34 | if (o instanceof Upload) { 35 | return upload.equals(o); 36 | } 37 | return false; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/data/User.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.data; 2 | 3 | import org.litepal.annotation.Column; 4 | import org.litepal.crud.LitePalSupport; 5 | 6 | public class User extends LitePalSupport { 7 | 8 | private long id; 9 | 10 | @Column(unique = true) 11 | private long uid; 12 | private String username; 13 | private String password; 14 | 15 | private Long uploadPath; 16 | 17 | public Long getUploadPath() { 18 | return uploadPath; 19 | } 20 | 21 | public void setUploadPath(Long uploadPath) { 22 | this.uploadPath = uploadPath; 23 | } 24 | 25 | public User() { 26 | } 27 | 28 | public User(long uid) { 29 | assignBaseObjId(uid); 30 | } 31 | 32 | public void update() { 33 | update(id); 34 | } 35 | 36 | public String getPassword() { 37 | return password; 38 | } 39 | 40 | public void setPassword(String password) { 41 | this.password = password; 42 | } 43 | 44 | private String cookie; 45 | 46 | private boolean isCurrent; 47 | 48 | public long getUid() { 49 | return uid; 50 | } 51 | 52 | public void setUid(long uid) { 53 | this.uid = uid; 54 | } 55 | 56 | public String getUsername() { 57 | return username; 58 | } 59 | 60 | public void setUsername(String username) { 61 | this.username = username; 62 | } 63 | 64 | public String getCookie() { 65 | return cookie; 66 | } 67 | 68 | public void setCookie(String cookie) { 69 | this.cookie = cookie; 70 | } 71 | 72 | public boolean isCurrent() { 73 | return isCurrent; 74 | } 75 | 76 | public void setCurrent(boolean current) { 77 | isCurrent = current; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/event/FileActionListener.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.event; 2 | 3 | public interface FileActionListener { 4 | 5 | void onPreLoadFile(); 6 | 7 | void onFileLoaded(); 8 | 9 | void onPageChange(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/event/OnDownloadListener.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.event; 2 | 3 | import com.lanzou.cloud.data.Download; 4 | 5 | public interface OnDownloadListener { 6 | 7 | void onDownload(Download download); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/event/OnFileIOListener.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.event; 2 | 3 | public interface OnFileIOListener { 4 | 5 | void onProgress(long current, long length, long byteCount); 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/event/OnItemClickListener.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.event; 2 | 3 | import android.view.View; 4 | 5 | public interface OnItemClickListener { 6 | 7 | void onItemClick(int position, View view); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/event/OnItemLongClickListener.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.event; 2 | 3 | import android.view.View; 4 | 5 | public interface OnItemLongClickListener { 6 | 7 | void onItemLongClick(int position, View v); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/event/OnUploadListener.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.event; 2 | 3 | import com.lanzou.cloud.data.Upload; 4 | 5 | public interface OnUploadListener { 6 | 7 | void onUpload(Upload upload); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/event/Searchable.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.event; 2 | 3 | public interface Searchable { 4 | 5 | void onSearch(String keyWorld); 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/network/FileRequestBody.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.network; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.lanzou.cloud.event.OnFileIOListener; 6 | 7 | import java.io.IOException; 8 | 9 | import okhttp3.MediaType; 10 | import okhttp3.RequestBody; 11 | import okio.Buffer; 12 | import okio.BufferedSink; 13 | import okio.ForwardingSink; 14 | import okio.Okio; 15 | 16 | public class FileRequestBody extends RequestBody { 17 | 18 | private final RequestBody requestBody; 19 | 20 | private final OnFileIOListener listener; 21 | 22 | public FileRequestBody(RequestBody requestBody, OnFileIOListener listener) { 23 | this.requestBody = requestBody; 24 | this.listener = listener; 25 | } 26 | 27 | @Override 28 | public MediaType contentType() { 29 | return requestBody.contentType(); 30 | } 31 | 32 | @Override 33 | public long contentLength() throws IOException { 34 | return requestBody.contentLength(); 35 | } 36 | 37 | private long currentLength; 38 | 39 | @Override 40 | public void writeTo(@NonNull BufferedSink sink) throws IOException { 41 | long length = contentLength(); 42 | ForwardingSink forwardingSink = new ForwardingSink(sink) { 43 | @Override 44 | public void write(@NonNull Buffer source, long byteCount) throws IOException { 45 | if (listener != null) { 46 | currentLength += byteCount; 47 | listener.onProgress(currentLength, length, byteCount); 48 | } 49 | super.write(source, byteCount); 50 | } 51 | }; 52 | BufferedSink buffer = Okio.buffer(forwardingSink); 53 | requestBody.writeTo(buffer); 54 | buffer.flush(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/service/LanzouService.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.service; 2 | 3 | import com.lanzou.cloud.data.LanzouDownloadResponse; 4 | import com.lanzou.cloud.data.LanzouFileResponse; 5 | import com.lanzou.cloud.data.LanzouFolderResponse; 6 | import com.lanzou.cloud.data.LanzouSimpleResponse; 7 | import com.lanzou.cloud.data.LanzouUploadResponse; 8 | import com.lanzou.cloud.data.LanzouUrlResponse; 9 | 10 | import java.util.Map; 11 | 12 | import okhttp3.FormBody; 13 | import okhttp3.RequestBody; 14 | import retrofit2.Call; 15 | import retrofit2.http.Body; 16 | import retrofit2.http.Field; 17 | import retrofit2.http.FieldMap; 18 | import retrofit2.http.FormUrlEncoded; 19 | import retrofit2.http.Header; 20 | import retrofit2.http.POST; 21 | import retrofit2.http.Query; 22 | import retrofit2.http.Url; 23 | 24 | /** 25 | * API 接口 26 | */ 27 | public interface LanzouService { 28 | 29 | /** 30 | * 获取文件列表 31 | * 32 | * @param task 47加载文件夹,5 加载文件 33 | * @param uid 用户 UID 34 | * @param folderId 父文件夹 id 35 | * @param page 页码 36 | */ 37 | @POST("doupload.php") 38 | @FormUrlEncoded 39 | Call getFiles( 40 | @Query("uid") long uid, 41 | @Field("task") int task, 42 | @Field("folder_id") long folderId, 43 | @Field("pg") int page 44 | ); 45 | 46 | /** 47 | * 上传文件 task: 1 48 | * 49 | * @param requestBody 请求体数据 50 | */ 51 | @POST("html5up.php") 52 | Call uploadFile(@Body RequestBody requestBody); 53 | 54 | /** 55 | * 获取所有文件夹 56 | * 57 | * @param task 19 58 | */ 59 | @POST("doupload.php") 60 | @FormUrlEncoded 61 | Call getAllFolder(@Field("task") int task); 62 | 63 | /** 64 | * 获取文件的分享链 65 | * @param task 22 66 | * @param fileId 文件 id 67 | */ 68 | @POST("doupload.php") 69 | @FormUrlEncoded 70 | Call getShareUrl( 71 | @Field("task") int task, 72 | @Field("file_id") long fileId 73 | ); 74 | 75 | /** 76 | * 获取下载地址,先改用接口进行获取 77 | * @param userAgent 代理 78 | * @param referer referer 79 | * @param url 分享地址 80 | * @param body 表单数据 81 | */ 82 | @Deprecated 83 | @POST 84 | Call getDownloadUrl( 85 | @Header("User-Agent") String userAgent, 86 | @Header("Referer") String referer, 87 | @Url String url, 88 | @Body FormBody body); 89 | 90 | /** 91 | * 创建文件夹 92 | * @param task 2 新建文件夹 93 | * @param parentId 父文件夹 id 94 | * @param name 文件夹名称 95 | * @param desc 文件夹描述消息 96 | */ 97 | @POST("doupload.php") 98 | @FormUrlEncoded 99 | Call createFolder( 100 | @Field("task") int task, 101 | @Field("parent_id") long parentId, 102 | @Field("folder_name") String name, 103 | @Field("folder_description") String desc 104 | ); 105 | 106 | /** 107 | * 删除文件 108 | * @param map 所有参数 109 | * @return 操作结果 110 | */ 111 | @POST("doupload.php") 112 | @FormUrlEncoded 113 | Call deleteFile( 114 | @FieldMap Map map 115 | ); 116 | 117 | /** 118 | * 移动文件 119 | * @param task 20 120 | * @param fileId 文件 id 121 | * @param folderId 目标文件夹 id 122 | */ 123 | @POST("doupload.php") 124 | @FormUrlEncoded 125 | Call moveFile( 126 | @Field("task") int task, 127 | @Field("file_id") long fileId, 128 | @Field("folder_id") long folderId 129 | ); 130 | } 131 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/ui/LinearItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.ui; 2 | 3 | import android.graphics.Rect; 4 | import android.view.View; 5 | 6 | import androidx.annotation.NonNull; 7 | import androidx.recyclerview.widget.RecyclerView; 8 | 9 | public class LinearItemDecoration extends RecyclerView.ItemDecoration { 10 | @Override 11 | public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { 12 | int position = parent.getChildAdapterPosition(view); 13 | outRect.left = 20; 14 | outRect.right = 20; 15 | if (position == 0) { 16 | outRect.top = 20; 17 | } 18 | outRect.bottom = 20; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/ui/dialog/UserDialog.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.ui.dialog; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.widget.Toast; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.appcompat.app.AlertDialog; 9 | import androidx.recyclerview.widget.LinearLayoutManager; 10 | import androidx.recyclerview.widget.RecyclerView; 11 | 12 | import com.lanzou.cloud.LanzouApplication; 13 | import com.lanzou.cloud.data.User; 14 | import com.lanzou.cloud.network.Repository; 15 | import com.lanzou.cloud.ui.web.WebActivity; 16 | 17 | import java.util.List; 18 | 19 | public class UserDialog extends AlertDialog.Builder { 20 | public UserDialog(@NonNull Context context) { 21 | super(context); 22 | 23 | RecyclerView recyclerView = new RecyclerView(getContext()); 24 | recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); 25 | 26 | setView(recyclerView); 27 | 28 | setTitle("账号管理"); 29 | Repository repository = Repository.getInstance(); 30 | List userList = repository.getSavedUserList(); 31 | 32 | String[] list = new String[userList.size()]; 33 | int position = 0; 34 | for (int i = 0; i < userList.size(); i++) { 35 | User user = userList.get(i); 36 | list[i] = user.getUsername(); 37 | if (user.isCurrent()) { 38 | position = i; 39 | } 40 | } 41 | 42 | setSingleChoiceItems(list, position, (dialog, which) -> { 43 | repository.selectUser(userList.get(which)); 44 | dialog.dismiss(); 45 | Toast.makeText(context, "切换账号后请返回主页根目录刷新", Toast.LENGTH_SHORT).show(); 46 | }); 47 | 48 | setPositiveButton("添加账号", (dialog, which) -> context.startActivity(new Intent(context, WebActivity.class) 49 | .putExtra("url", LanzouApplication.HOST_LOGIN))); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/ui/download/DownloadListFragment.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.ui.download; 2 | 3 | import android.content.ComponentName; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.ServiceConnection; 7 | import android.os.Bundle; 8 | import android.os.IBinder; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | import androidx.activity.result.ActivityResultLauncher; 14 | import androidx.activity.result.contract.ActivityResultContracts; 15 | import androidx.annotation.NonNull; 16 | import androidx.annotation.Nullable; 17 | import androidx.fragment.app.Fragment; 18 | import androidx.recyclerview.widget.LinearLayoutManager; 19 | import androidx.recyclerview.widget.RecyclerView; 20 | 21 | import com.lanzou.cloud.R; 22 | import com.lanzou.cloud.adapter.DownloadAdapter; 23 | import com.lanzou.cloud.data.Download; 24 | import com.lanzou.cloud.event.OnDownloadListener; 25 | import com.lanzou.cloud.service.DownloadService; 26 | 27 | import org.litepal.LitePal; 28 | 29 | import java.util.ArrayList; 30 | import java.util.List; 31 | 32 | public class DownloadListFragment extends Fragment implements ServiceConnection, OnDownloadListener { 33 | 34 | private DownloadService downloadService; 35 | 36 | private final List downloadList = new ArrayList<>(); 37 | 38 | private final DownloadAdapter downloadAdapter = new DownloadAdapter(downloadList); 39 | 40 | @Override 41 | public void onCreate(@Nullable Bundle savedInstanceState) { 42 | super.onCreate(savedInstanceState); 43 | requireContext().bindService(new Intent(requireContext(), DownloadService.class), this, Context.BIND_AUTO_CREATE); 44 | } 45 | 46 | @Override 47 | public void onServiceDisconnected(ComponentName name) { 48 | } 49 | 50 | @Override 51 | public void onServiceConnected(ComponentName name, IBinder service) { 52 | downloadService = ((DownloadService.DownloadBinder) service).getService(); 53 | downloadService.addDownloadListener(this); 54 | // downloadList.addAll(downloadService.getDownloadList()); 55 | downloadList.addAll(LitePal.order("id desc").limit(1000).find(Download.class)); 56 | downloadAdapter.notifyDataSetChanged(); 57 | } 58 | 59 | @Override 60 | public void onDownload(Download download) { 61 | if (download.isInsert()) { 62 | downloadList.add(0, download); 63 | downloadAdapter.notifyItemInserted(0); 64 | return; 65 | } 66 | int index = downloadList.indexOf(download); 67 | if (index != -1) { 68 | if (downloadList.get(index) != download) { 69 | downloadList.set(index, download); 70 | } 71 | downloadAdapter.notifyItemChanged(index, 0); 72 | } else { 73 | downloadList.add(0, download); 74 | downloadAdapter.notifyItemInserted(0); 75 | } 76 | } 77 | 78 | @Nullable 79 | @Override 80 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 81 | return inflater.inflate(R.layout.fragment_transmission_list, container, false); 82 | } 83 | 84 | @Override 85 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 86 | super.onViewCreated(view, savedInstanceState); 87 | RecyclerView recyclerView = (RecyclerView) view; 88 | recyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); 89 | recyclerView.setAdapter(downloadAdapter); 90 | 91 | downloadAdapter.setToggleTransmissionListener((position, view1) 92 | -> downloadService.toggleDownload(downloadList.get(position))); 93 | 94 | ActivityResultLauncher launcher = registerForActivityResult( 95 | new ActivityResultContracts.StartActivityForResult(), result -> { 96 | if (result.getData() != null) { 97 | int position = result.getData().getIntExtra("position", -1); 98 | if (position == -1) return; 99 | downloadList.remove(position); 100 | downloadAdapter.notifyItemRemoved(position); 101 | } 102 | }); 103 | 104 | downloadAdapter.setItemClickListener((position, view12) -> { 105 | DownloadInfoActivity.actionStart(requireContext(), launcher, downloadList.get(position), position); 106 | }); 107 | } 108 | 109 | @Override 110 | public void onDestroy() { 111 | super.onDestroy(); 112 | requireContext().unbindService(this); 113 | downloadService.removeDownloadListener(this); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/ui/file/AbstractFileAction.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.ui.file; 2 | 3 | import android.content.Intent; 4 | 5 | import androidx.activity.result.ActivityResultLauncher; 6 | import androidx.recyclerview.widget.RecyclerView; 7 | 8 | import com.lanzou.cloud.data.LanzouFile; 9 | import com.lanzou.cloud.data.LanzouPage; 10 | import com.lanzou.cloud.event.FileActionListener; 11 | 12 | import java.util.List; 13 | 14 | public abstract class AbstractFileAction { 15 | 16 | public abstract void refresh(); 17 | 18 | public abstract void getFiles(long folderId, String folderName); 19 | 20 | public abstract void onBackPressed(); 21 | 22 | protected abstract void loadMoreFiles(); 23 | 24 | public abstract List getSource(); 25 | 26 | public abstract List getLanzouPages(); 27 | 28 | public abstract LanzouPage getCurrentPage(); 29 | 30 | public abstract void bindView(RecyclerView rv, FileActionListener fileActionListener); 31 | 32 | protected void getFiles() { 33 | getFiles(-1, "根目录"); 34 | } 35 | 36 | public void navigateTo(int position) {} 37 | 38 | public void deleteItem(int position) {} 39 | 40 | public void deleteFile(int position) {} 41 | 42 | public void deleteFiles(Callback callback) {} 43 | 44 | public void shareFile(int position) {} 45 | 46 | public void moveFile(ActivityResultLauncher launcher, LanzouFile lanzouFile) {} 47 | 48 | public void moveFiles(ActivityResultLauncher launcher) {} 49 | 50 | 51 | public interface Callback { 52 | void onCompleted(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/ui/folder/FolderSelectorActivity.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.ui.folder; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.Menu; 7 | import android.view.MenuItem; 8 | import android.widget.Toast; 9 | 10 | import androidx.activity.result.ActivityResultLauncher; 11 | import androidx.annotation.Nullable; 12 | import androidx.appcompat.widget.SearchView; 13 | import androidx.recyclerview.widget.RecyclerView; 14 | import androidx.recyclerview.widget.StaggeredGridLayoutManager; 15 | 16 | import com.lanzou.cloud.R; 17 | import com.lanzou.cloud.adapter.FolderListAdapter; 18 | import com.lanzou.cloud.base.BaseActivity; 19 | import com.lanzou.cloud.data.LanzouFile; 20 | import com.lanzou.cloud.data.LanzouFolder; 21 | import com.lanzou.cloud.databinding.ActivityFolderSelectorBinding; 22 | import com.lanzou.cloud.network.Repository; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | public class FolderSelectorActivity extends BaseActivity { 28 | 29 | private ActivityFolderSelectorBinding binding; 30 | 31 | private List lanzouFolders; 32 | 33 | private FolderListAdapter folderListAdapter; 34 | 35 | public static void moveFile(Context context, ActivityResultLauncher launcher, 36 | LanzouFile lanzouFile) { 37 | launcher.launch(new Intent(context, FolderSelectorActivity.class) 38 | .putExtra("lanzouFile", lanzouFile) 39 | ); 40 | } 41 | 42 | public static void moveFiles(Context context, ActivityResultLauncher launcher) { 43 | launcher.launch(new Intent(context, FolderSelectorActivity.class)); 44 | } 45 | 46 | @Override 47 | protected void onCreate(@Nullable Bundle savedInstanceState) { 48 | super.onCreate(savedInstanceState); 49 | binding = ActivityFolderSelectorBinding.inflate(getLayoutInflater()); 50 | setContentView(binding.getRoot()); 51 | setSupportActionBar(binding.header.toolBar); 52 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 53 | 54 | RecyclerView recyclerView = binding.folderRecycler; 55 | recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); 56 | folderListAdapter = new FolderListAdapter(); 57 | recyclerView.setAdapter(folderListAdapter); 58 | 59 | binding.refresh.setRefreshing(true); 60 | getFolders(); 61 | 62 | binding.refresh.setOnRefreshListener(this::getFolders); 63 | 64 | folderListAdapter.setOnItemClickListener((position, view) -> { 65 | Intent intent = new Intent(); 66 | intent.putExtra("id", folderListAdapter.getCurrentList().get(position).getFolder_id()); 67 | LanzouFile lanzouFile = getIntent().getParcelableExtra("lanzouFile"); 68 | intent.putExtra("lanzouFile", lanzouFile); 69 | setResult(RESULT_OK, intent); 70 | finish(); 71 | }); 72 | 73 | binding.add.setOnClickListener(v -> Toast.makeText(FolderSelectorActivity.this, "前往主页新建文件夹", Toast.LENGTH_SHORT).show()); 74 | 75 | } 76 | 77 | private void getFolders() { 78 | new Thread(() -> { 79 | lanzouFolders = Repository.getInstance().getAllFolder(); 80 | if (lanzouFolders == null) { 81 | lanzouFolders = new ArrayList<>(); 82 | } 83 | lanzouFolders.add(0, new LanzouFolder(-1, "根目录")); 84 | runOnUiThread(() -> { 85 | folderListAdapter.submitList(lanzouFolders); 86 | binding.refresh.setRefreshing(false); 87 | }); 88 | }).start(); 89 | } 90 | 91 | @Override 92 | public boolean onCreateOptionsMenu(Menu menu) { 93 | MenuItem search = menu.add("搜索"); 94 | search.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW | MenuItem.SHOW_AS_ACTION_ALWAYS); 95 | search.setIcon(R.drawable.baseline_search_24); 96 | SearchView searchView = new SearchView(this); 97 | search.setActionView(searchView); 98 | searchView.setQueryHint("输入关键字搜索"); 99 | searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { 100 | @Override 101 | public boolean onQueryTextSubmit(String query) { 102 | return false; 103 | } 104 | 105 | @Override 106 | public boolean onQueryTextChange(String newText) { 107 | List filteredList = new ArrayList<>(); 108 | for (LanzouFolder lanzouFolder : lanzouFolders) { 109 | if (lanzouFolder.getFolder_name().toLowerCase().contains(newText.toLowerCase())) { 110 | filteredList.add(lanzouFolder); 111 | } 112 | } 113 | folderListAdapter.submitList(filteredList); 114 | return false; 115 | } 116 | }); 117 | return super.onCreateOptionsMenu(menu); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/ui/me/MeFragment.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.ui.me; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.annotation.Nullable; 11 | import androidx.fragment.app.Fragment; 12 | 13 | import com.lanzou.cloud.data.User; 14 | import com.lanzou.cloud.databinding.FragmentMeBinding; 15 | import com.lanzou.cloud.network.Repository; 16 | import com.lanzou.cloud.ui.dialog.UserDialog; 17 | import com.lanzou.cloud.ui.resolve.ResolveFileActivity; 18 | 19 | public class MeFragment extends Fragment { 20 | 21 | private FragmentMeBinding binding; 22 | 23 | @Nullable 24 | @Override 25 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 26 | binding = FragmentMeBinding.inflate(inflater, container, false); 27 | return binding.getRoot(); 28 | } 29 | 30 | @Override 31 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 32 | super.onViewCreated(view, savedInstanceState); 33 | 34 | binding.btnManager.setOnClickListener(v -> { 35 | UserDialog userDialog = new UserDialog(v.getContext()); 36 | userDialog.setOnDismissListener(dialog -> getUser()); 37 | userDialog.show(); 38 | }); 39 | 40 | binding.btnResolve.setOnClickListener(v -> 41 | startActivity(new Intent(requireContext(), ResolveFileActivity.class)) 42 | ); 43 | } 44 | 45 | private void getUser() { 46 | Repository repository = Repository.getInstance(); 47 | User user = repository.getSavedUser(); 48 | binding.tvUsername.setText(user == null ? "未登录" : user.getUsername()); 49 | } 50 | 51 | @Override 52 | public void onResume() { 53 | super.onResume(); 54 | getUser(); 55 | } 56 | 57 | @Override 58 | public void onDestroyView() { 59 | super.onDestroyView(); 60 | binding = null; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/ui/question/QuestionActivity.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.ui.question; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.FrameLayout; 8 | import android.widget.TextView; 9 | 10 | import androidx.annotation.NonNull; 11 | import androidx.annotation.Nullable; 12 | import androidx.core.view.WindowCompat; 13 | import androidx.recyclerview.widget.LinearLayoutManager; 14 | import androidx.recyclerview.widget.RecyclerView; 15 | 16 | import com.lanzou.cloud.R; 17 | import com.lanzou.cloud.base.BaseActivity; 18 | import com.lanzou.cloud.data.Question; 19 | import com.lanzou.cloud.databinding.ActivityQuestionBinding; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | public class QuestionActivity extends BaseActivity { 25 | 26 | private ActivityQuestionBinding binding; 27 | 28 | private final List questions = new ArrayList<>(); 29 | 30 | @Override 31 | protected void onCreate(@Nullable Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | WindowCompat.setDecorFitsSystemWindows(getWindow(), false); 34 | binding = ActivityQuestionBinding.inflate(getLayoutInflater()); 35 | setContentView(binding.getRoot()); 36 | setSupportActionBar(binding.header.toolBar); 37 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 38 | 39 | RecyclerView rv = binding.questionRv; 40 | rv.setLayoutManager(new LinearLayoutManager(this)); 41 | 42 | addLeft("文件下载在哪里?"); 43 | addRight("没有授权储存权限保存在" + getExternalFilesDir("Download") 44 | + "\n授权了保存在外部根目录/Download"); 45 | addLeft("为啥重新打开软件上传下载记录没了"); 46 | addRight("懒得搞了"); 47 | addLeft("为啥软件没有图标?"); 48 | addRight("懒得搞了"); 49 | addLeft("文件上传下载有问题?"); 50 | addRight("由于就几天时间写的,所以难免有问题,重新下载上传就好了,不行就提issue"); 51 | addLeft("为啥软件功能这么少?"); 52 | addRight("懒得做了,主要功能做好就行"); 53 | addLeft("为啥打开软件就要获取权限?"); 54 | addRight("为了省事,省的后面判断有没有权限"); 55 | addLeft("我的账号会被上传到云端吗?"); 56 | addRight("不会的,全部源代码开源,都保存在本地"); 57 | addLeft("软件会自动更新吗?"); 58 | addRight("暂时会,可能后面会移除自动更新"); 59 | addLeft("我要分享文件出去怎么办?"); 60 | addRight("已支持分享100M+文件,不过新注册用户有限制,下载一次可能就会失效,需要对方也下载本App"); 61 | addLeft("好的,我已了解"); 62 | addRight("--------------------------------------"); 63 | addRight("软件仅供交流学习使用,请勿用于其他用途"); 64 | addRight("作者:Yu2002s"); 65 | 66 | rv.setAdapter(new QuestionAdapter(questions)); 67 | } 68 | 69 | private static class QuestionAdapter extends RecyclerView.Adapter { 70 | 71 | private final List questions; 72 | 73 | public QuestionAdapter(List questions) { 74 | this.questions = questions; 75 | } 76 | 77 | @NonNull 78 | @Override 79 | public QuestionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 80 | int resId = viewType == Question.LEFT ? R.layout.item_list_left : R.layout.item_list_right; 81 | View view = LayoutInflater.from(parent.getContext()).inflate(resId, parent, false); 82 | return new QuestionViewHolder(view); 83 | } 84 | 85 | @Override 86 | public void onBindViewHolder(@NonNull QuestionViewHolder holder, int position) { 87 | ((TextView)((FrameLayout)holder.itemView).getChildAt(0)).setText(questions.get(position).getContent()); 88 | } 89 | 90 | @Override 91 | public int getItemCount() { 92 | return questions.size(); 93 | } 94 | 95 | @Override 96 | public int getItemViewType(int position) { 97 | return questions.get(position).getType(); 98 | } 99 | } 100 | 101 | private static class QuestionViewHolder extends RecyclerView.ViewHolder { 102 | public QuestionViewHolder(@NonNull View itemView) { 103 | super(itemView); 104 | } 105 | } 106 | 107 | private void addLeft(String content) { 108 | questions.add(new Question(Question.LEFT, content)); 109 | } 110 | private void addRight(String content) { 111 | questions.add(new Question(Question.RIGHT, content)); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/ui/resolve/ResolveFileActivity.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.ui.resolve; 2 | 3 | import android.content.ComponentName; 4 | import android.content.Intent; 5 | import android.content.ServiceConnection; 6 | import android.os.Bundle; 7 | import android.os.IBinder; 8 | import android.view.MenuItem; 9 | 10 | import androidx.annotation.NonNull; 11 | import androidx.annotation.Nullable; 12 | import androidx.appcompat.app.AppCompatActivity; 13 | 14 | import com.lanzou.cloud.databinding.ActivityResolveFileBinding; 15 | import com.lanzou.cloud.service.DownloadService; 16 | 17 | public class ResolveFileActivity extends AppCompatActivity implements ServiceConnection { 18 | 19 | private DownloadService downloadService; 20 | 21 | @Override 22 | protected void onCreate(@Nullable Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | bindService(new Intent(this, DownloadService.class), this, BIND_AUTO_CREATE); 25 | ActivityResolveFileBinding binding = ActivityResolveFileBinding.inflate(getLayoutInflater()); 26 | setContentView(binding.getRoot()); 27 | setSupportActionBar(binding.header.toolBar); 28 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 29 | 30 | binding.btnResolve.setOnClickListener(v -> { 31 | String url = binding.editUrl.getText().toString(); 32 | String pwd = binding.editPwd.getText().toString(); 33 | resolveFile(url, pwd); 34 | }); 35 | 36 | CharSequence charSequenceExtra = getIntent().getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT); 37 | boolean readonly = getIntent().getBooleanExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, false); 38 | if (charSequenceExtra != null) { 39 | binding.editUrl.setText(charSequenceExtra); 40 | } 41 | } 42 | 43 | private void resolveFile(String url, @Nullable String pwd) { 44 | downloadService.addDownload(url, null, pwd); 45 | } 46 | 47 | @Override 48 | public void onServiceConnected(ComponentName name, IBinder service) { 49 | downloadService = ((DownloadService.DownloadBinder) service).getService(); 50 | } 51 | 52 | @Override 53 | public void onServiceDisconnected(ComponentName name) { 54 | 55 | } 56 | 57 | @Override 58 | public boolean onOptionsItemSelected(@NonNull MenuItem item) { 59 | if (item.getItemId() == android.R.id.home) { 60 | finish(); 61 | } 62 | return super.onOptionsItemSelected(item); 63 | } 64 | 65 | @Override 66 | protected void onDestroy() { 67 | super.onDestroy(); 68 | unbindService(this); 69 | downloadService = null; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/ui/selector/FileSelectorActivity.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.ui.selector; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.view.Menu; 6 | import android.view.MenuItem; 7 | import android.widget.Button; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.annotation.Nullable; 11 | import androidx.appcompat.app.AppCompatActivity; 12 | import androidx.appcompat.widget.SearchView; 13 | import androidx.core.view.WindowCompat; 14 | import androidx.fragment.app.Fragment; 15 | import androidx.viewpager2.adapter.FragmentStateAdapter; 16 | import androidx.viewpager2.widget.ViewPager2; 17 | 18 | import com.google.android.material.tabs.TabLayoutMediator; 19 | import com.lanzou.cloud.R; 20 | import com.lanzou.cloud.data.FileInfo; 21 | import com.lanzou.cloud.databinding.ActivityFileSelectorBinding; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | public class FileSelectorActivity extends AppCompatActivity { 27 | 28 | private ActivityFileSelectorBinding binding; 29 | 30 | private final List selectedFiles = new ArrayList<>(); 31 | 32 | public List getSelectedFiles() { 33 | return selectedFiles; 34 | } 35 | 36 | private String searchWorld = ""; 37 | 38 | public String getSearchWorld() { 39 | return searchWorld; 40 | } 41 | 42 | @Override 43 | protected void onCreate(@Nullable Bundle savedInstanceState) { 44 | super.onCreate(savedInstanceState); 45 | WindowCompat.setDecorFitsSystemWindows(getWindow(), false); 46 | binding = ActivityFileSelectorBinding.inflate(getLayoutInflater()); 47 | setContentView(binding.getRoot()); 48 | 49 | binding.header.toolBar.setContentInsetStartWithNavigation(0); 50 | setSupportActionBar(binding.header.toolBar); 51 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 52 | getSupportActionBar().setTitle(""); 53 | SearchView searchView = new SearchView(this); 54 | searchView.setQueryHint("输入关键字进行搜索"); 55 | searchView.post(searchView::clearFocus); 56 | searchView.onActionViewExpanded(); 57 | getSupportActionBar().setDisplayShowCustomEnabled(true); 58 | getSupportActionBar().setCustomView(searchView); 59 | 60 | String[] titles = {"最近", "软件", "安装包", "图片", "微信", "QQ", "音频", "视频", "文档", /*"QQ", "微信"*/}; 61 | List fragmentList = new ArrayList<>(); 62 | for (int i = 0; i < titles.length; i++) { 63 | fragmentList.add(FileSelectorFragment.newInstance(i)); 64 | } 65 | 66 | ViewPager2 viewpager2 = binding.viewpager2; 67 | viewpager2.setOffscreenPageLimit(titles.length + 1); 68 | viewpager2.setAdapter(new FragmentStateAdapter(getSupportFragmentManager(), getLifecycle()) { 69 | @NonNull 70 | @Override 71 | public Fragment createFragment(int position) { 72 | return fragmentList.get(position); 73 | } 74 | 75 | @Override 76 | public int getItemCount() { 77 | return titles.length; 78 | } 79 | }); 80 | new TabLayoutMediator(binding.tabLayout, viewpager2, (tab, position) -> 81 | tab.setText(titles[position]) 82 | ).attach(); 83 | 84 | searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { 85 | @Override 86 | public boolean onQueryTextSubmit(String query) { 87 | return false; 88 | } 89 | 90 | @Override 91 | public boolean onQueryTextChange(String newText) { 92 | // 直接进行搜索 93 | searchWorld = newText; 94 | for (FileSelectorFragment fragment : fragmentList) { 95 | fragment.onSearch(newText); 96 | } 97 | return false; 98 | } 99 | }); 100 | } 101 | 102 | @Override 103 | public boolean onCreateOptionsMenu(Menu menu) { 104 | getMenuInflater().inflate(R.menu.menu_file_selector, menu); 105 | MenuItem item = menu.findItem(R.id.upload_file); 106 | Button upload = item.getActionView().findViewById(R.id.btn_upload); 107 | upload.setOnClickListener(v -> { 108 | ArrayList uris = new ArrayList<>(); 109 | for (int i = 0; i < selectedFiles.size(); i++) { 110 | uris.add(selectedFiles.get(i).getUri()); 111 | } 112 | setResult(RESULT_OK, new Intent().putCharSequenceArrayListExtra("files", uris)); 113 | finish(); 114 | }); 115 | return super.onCreateOptionsMenu(menu); 116 | } 117 | 118 | @Override 119 | public boolean onOptionsItemSelected(@NonNull MenuItem item) { 120 | if (item.getItemId() == android.R.id.home) { 121 | finish(); 122 | } 123 | return super.onOptionsItemSelected(item); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/ui/selector/PhoneFileActivity.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.ui.selector; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.os.Environment; 7 | import android.view.Menu; 8 | import android.view.MenuItem; 9 | import android.widget.Button; 10 | 11 | import androidx.annotation.Nullable; 12 | import androidx.appcompat.app.ActionBar; 13 | import androidx.recyclerview.widget.LinearLayoutManager; 14 | import androidx.recyclerview.widget.RecyclerView; 15 | 16 | import com.google.android.material.appbar.MaterialToolbar; 17 | import com.lanzou.cloud.R; 18 | import com.lanzou.cloud.adapter.FileSelectorAdapter; 19 | import com.lanzou.cloud.base.BaseActivity; 20 | import com.lanzou.cloud.data.FileInfo; 21 | import com.lanzou.cloud.databinding.ActivityPhoneFileBinding; 22 | import com.lanzou.cloud.utils.FileUtils; 23 | 24 | import java.io.File; 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | /** 29 | * 手机文件选择器 30 | */ 31 | public class PhoneFileActivity extends BaseActivity { 32 | 33 | private ActivityPhoneFileBinding binding; 34 | 35 | private final List fileInfos = new ArrayList<>(); 36 | 37 | private final List selectedFileInfos = new ArrayList<>(); 38 | 39 | private final List pathList = new ArrayList<>(); 40 | 41 | private final FileSelectorAdapter fileSelectorAdapter = new FileSelectorAdapter(fileInfos); 42 | 43 | private static final String ROOT = Environment.getExternalStorageDirectory().getPath(); 44 | 45 | @Override 46 | protected void onCreate(@Nullable Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | 49 | binding = ActivityPhoneFileBinding.inflate(getLayoutInflater()); 50 | setContentView(binding.getRoot()); 51 | MaterialToolbar toolbar = binding.header.toolBar; 52 | setSupportActionBar(toolbar); 53 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 54 | toolbar.setNavigationOnClickListener(v -> onBackPressed()); 55 | 56 | fileSelectorAdapter.setSelectButtonClickable(true); 57 | 58 | RecyclerView recyclerView = binding.fileRecyclerView; 59 | recyclerView.setLayoutManager(new LinearLayoutManager(this)); 60 | recyclerView.setAdapter(fileSelectorAdapter); 61 | 62 | pathList.add(ROOT); 63 | getFiles(ROOT); 64 | 65 | binding.refreshLayout.setOnRefreshListener(this::getFiles); 66 | 67 | fileSelectorAdapter.setOnItemClickListener((position, view) -> { 68 | FileInfo fileInfo = fileInfos.get(position); 69 | if (fileInfo.getExtension() != null || view.getId() == R.id.select) { 70 | if (fileInfo.isSelected()) { 71 | selectedFileInfos.add(fileInfo); 72 | } else { 73 | selectedFileInfos.remove(fileInfo); 74 | } 75 | return; 76 | } 77 | pathList.add(fileInfo.getUri()); 78 | getFiles(fileInfo.getUri()); 79 | }); 80 | } 81 | 82 | @Override 83 | public void onBackPressed() { 84 | if (pathList.size() == 1) { 85 | super.onBackPressed(); 86 | return; 87 | } 88 | String beforePath = pathList.get(pathList.size() - 2); 89 | pathList.remove(pathList.size() - 1); 90 | getFiles(beforePath); 91 | } 92 | 93 | @Override 94 | public boolean onCreateOptionsMenu(Menu menu) { 95 | getMenuInflater().inflate(R.menu.menu_file_selector, menu); 96 | MenuItem item = menu.findItem(R.id.upload_file); 97 | Button upload = item.getActionView().findViewById(R.id.btn_upload); 98 | upload.setOnClickListener(v -> { 99 | ArrayList uris = new ArrayList<>(); 100 | for (int i = 0; i < selectedFileInfos.size(); i++) { 101 | File file = new File(selectedFileInfos.get(i).getUri()); 102 | if (file.isDirectory()) { 103 | File[] files = file.listFiles(File::isFile); 104 | if (files == null) { 105 | continue; 106 | } 107 | for (File child : files) { 108 | uris.add(child.getPath()); 109 | } 110 | } else { 111 | uris.add(file.getPath()); 112 | } 113 | } 114 | setResult(RESULT_OK, new Intent().putCharSequenceArrayListExtra("files", uris)); 115 | finish(); 116 | }); 117 | return super.onCreateOptionsMenu(menu); 118 | } 119 | 120 | private void getFiles() { 121 | getFiles(pathList.get(pathList.size() - 1)); 122 | } 123 | 124 | @SuppressLint("NotifyDataSetChanged") 125 | private void getFiles(String path) { 126 | File file = new File(path); 127 | ActionBar toolBar = getSupportActionBar(); 128 | assert toolBar != null; 129 | if (ROOT.equals(path)) { 130 | toolBar.setTitle("内部储存"); 131 | } else { 132 | toolBar.setTitle(file.getName()); 133 | } 134 | toolBar.setSubtitle(path); 135 | binding.refreshLayout.setRefreshing(true); 136 | new Thread(() -> { 137 | List fileInfoList = FileUtils.getFileInfosForPath(file, selectedFileInfos::contains); 138 | fileInfos.clear(); 139 | fileInfos.addAll(fileInfoList); 140 | runOnUiThread(() -> { 141 | fileSelectorAdapter.notifyDataSetChanged(); 142 | binding.refreshLayout.setRefreshing(false); 143 | binding.fileRecyclerView.scrollToPosition(0); 144 | }); 145 | }).start(); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/ui/selector/PhoneFileSelectorFragment.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.ui.selector; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.annotation.Nullable; 10 | import androidx.fragment.app.Fragment; 11 | 12 | public class PhoneFileSelectorFragment extends Fragment { 13 | 14 | @Nullable 15 | @Override 16 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 17 | return super.onCreateView(inflater, container, savedInstanceState); 18 | } 19 | 20 | @Override 21 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 22 | super.onViewCreated(view, savedInstanceState); 23 | } 24 | 25 | @Override 26 | public void onDestroyView() { 27 | super.onDestroyView(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/ui/transmission/TransmissionFragment.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.ui.transmission; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.annotation.Nullable; 10 | import androidx.fragment.app.Fragment; 11 | import androidx.fragment.app.FragmentManager; 12 | import androidx.lifecycle.Lifecycle; 13 | import androidx.viewpager2.adapter.FragmentStateAdapter; 14 | import androidx.viewpager2.widget.ViewPager2; 15 | 16 | import com.google.android.material.tabs.TabLayout; 17 | import com.google.android.material.tabs.TabLayoutMediator; 18 | import com.lanzou.cloud.databinding.FragmentTransmissionBinding; 19 | import com.lanzou.cloud.ui.download.DownloadListFragment; 20 | import com.lanzou.cloud.ui.upload.UploadListFragment; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | public class TransmissionFragment extends Fragment { 26 | 27 | private FragmentTransmissionBinding binding; 28 | 29 | private final List fragments = new ArrayList<>(); 30 | 31 | @Nullable 32 | @Override 33 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 34 | binding = FragmentTransmissionBinding.inflate(inflater, container, false); 35 | return binding.getRoot(); 36 | } 37 | 38 | @Override 39 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 40 | super.onViewCreated(view, savedInstanceState); 41 | 42 | fragments.add(new DownloadListFragment()); 43 | fragments.add(new UploadListFragment()); 44 | 45 | ViewPager2 viewPager2 = binding.viewPager2; 46 | viewPager2.setAdapter(new TransmissionAdapter(getChildFragmentManager(), getLifecycle())); 47 | 48 | new TabLayoutMediator(binding.tabLayout, viewPager2, new TabLayoutMediator.TabConfigurationStrategy() { 49 | @Override 50 | public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) { 51 | if (position == 0) { 52 | tab.setText("下载"); 53 | } else { 54 | tab.setText("上传"); 55 | } 56 | 57 | } 58 | }).attach(); 59 | } 60 | 61 | private class TransmissionAdapter extends FragmentStateAdapter { 62 | 63 | public TransmissionAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) { 64 | super(fragmentManager, lifecycle); 65 | } 66 | 67 | @NonNull 68 | @Override 69 | public Fragment createFragment(int position) { 70 | return fragments.get(position); 71 | } 72 | 73 | 74 | @Override 75 | public int getItemCount() { 76 | return fragments.size(); 77 | } 78 | } 79 | 80 | @Override 81 | public void onDestroyView() { 82 | super.onDestroyView(); 83 | binding = null; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/ui/transmission/TransmissionListActivity.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.ui.transmission; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.annotation.Nullable; 7 | import androidx.fragment.app.Fragment; 8 | import androidx.fragment.app.FragmentManager; 9 | import androidx.lifecycle.Lifecycle; 10 | import androidx.viewpager2.adapter.FragmentStateAdapter; 11 | import androidx.viewpager2.widget.ViewPager2; 12 | 13 | import com.google.android.material.tabs.TabLayoutMediator; 14 | import com.lanzou.cloud.base.BaseActivity; 15 | import com.lanzou.cloud.databinding.ActivityTransmissionListBinding; 16 | import com.lanzou.cloud.ui.download.DownloadListFragment; 17 | import com.lanzou.cloud.ui.upload.UploadListFragment; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | public class TransmissionListActivity extends BaseActivity { 23 | 24 | private ActivityTransmissionListBinding binding; 25 | 26 | private final List fragments = new ArrayList<>(); 27 | 28 | @Override 29 | protected void onCreate(@Nullable Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | binding = ActivityTransmissionListBinding.inflate(getLayoutInflater()); 32 | setContentView(binding.getRoot()); 33 | setSupportActionBar(binding.header.toolBar); 34 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 35 | 36 | fragments.add(new DownloadListFragment()); 37 | fragments.add(new UploadListFragment()); 38 | 39 | ViewPager2 viewPager2 = binding.viewPager2; 40 | viewPager2.setAdapter(new TransmissionAdapter(getSupportFragmentManager(), getLifecycle())); 41 | 42 | new TabLayoutMediator(binding.tabLayout, viewPager2, (tab, position) -> { 43 | if (position == 0) { 44 | tab.setText("下载"); 45 | } else { 46 | tab.setText("上传"); 47 | } 48 | 49 | }).attach(); 50 | } 51 | 52 | private class TransmissionAdapter extends FragmentStateAdapter { 53 | 54 | public TransmissionAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) { 55 | super(fragmentManager, lifecycle); 56 | } 57 | 58 | @NonNull 59 | @Override 60 | public Fragment createFragment(int position) { 61 | return fragments.get(position); 62 | } 63 | 64 | 65 | @Override 66 | public int getItemCount() { 67 | return fragments.size(); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/ui/upload/ExternalUploadActivity.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.ui.upload; 2 | 3 | import android.content.ClipData; 4 | import android.content.ComponentName; 5 | import android.content.Intent; 6 | import android.content.ServiceConnection; 7 | import android.os.Bundle; 8 | import android.os.IBinder; 9 | import android.view.Menu; 10 | import android.view.MenuItem; 11 | 12 | import androidx.annotation.Nullable; 13 | import androidx.appcompat.app.AppCompatActivity; 14 | import androidx.appcompat.widget.SearchView; 15 | import androidx.recyclerview.widget.StaggeredGridLayoutManager; 16 | 17 | import com.lanzou.cloud.R; 18 | import com.lanzou.cloud.adapter.FolderListAdapter; 19 | import com.lanzou.cloud.data.LanzouFolder; 20 | import com.lanzou.cloud.data.LanzouPage; 21 | import com.lanzou.cloud.databinding.ActivityExternalUploadBinding; 22 | import com.lanzou.cloud.network.Repository; 23 | import com.lanzou.cloud.service.UploadService; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | public class ExternalUploadActivity extends AppCompatActivity implements ServiceConnection { 29 | 30 | private UploadService uploadService; 31 | 32 | private ActivityExternalUploadBinding binding; 33 | 34 | private List folders; 35 | 36 | private FolderListAdapter adapter; 37 | 38 | @Override 39 | protected void onCreate(@Nullable Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | startService(new Intent(this, UploadService.class)); 42 | bindService(new Intent(this, UploadService.class), this, BIND_AUTO_CREATE); 43 | binding = ActivityExternalUploadBinding.inflate(getLayoutInflater()); 44 | setContentView(binding.getRoot()); 45 | setSupportActionBar(binding.header.toolBar); 46 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 47 | 48 | binding.fileRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); 49 | 50 | adapter = new FolderListAdapter(); 51 | binding.fileRecyclerView.setAdapter(adapter); 52 | new Thread(() -> { 53 | folders = Repository.getInstance().getAllFolder(); 54 | if (folders == null) { 55 | finish(); 56 | return; 57 | } 58 | runOnUiThread(() -> adapter.submitList(folders)); 59 | }).start(); 60 | 61 | adapter.setOnItemClickListener((position, view) -> { 62 | LanzouPage lanzouPage = new LanzouPage(); 63 | LanzouFolder lanzouFolder = adapter.getCurrentList().get(position); 64 | lanzouPage.setName(lanzouFolder.getFolder_name()); 65 | lanzouPage.setFolderId(lanzouFolder.getFolder_id()); 66 | 67 | Intent intent = getIntent(); 68 | if (intent.getData() != null) { 69 | uploadService.uploadFile(intent.getData().toString(), lanzouPage); 70 | return; 71 | } 72 | 73 | ClipData clipData = intent.getClipData(); 74 | if (clipData == null) { 75 | return; 76 | } 77 | for (int i = 0; i < clipData.getItemCount(); i++) { 78 | ClipData.Item item = clipData.getItemAt(i); 79 | uploadService.uploadFile(item.getUri().toString(), lanzouPage); 80 | } 81 | 82 | finish(); 83 | }); 84 | 85 | } 86 | 87 | @Override 88 | public void onServiceConnected(ComponentName name, IBinder service) { 89 | uploadService = ((UploadService.UploadBinder) service).getService(); 90 | 91 | } 92 | 93 | @Override 94 | public void onServiceDisconnected(ComponentName name) { 95 | 96 | } 97 | 98 | @Override 99 | public boolean onCreateOptionsMenu(Menu menu) { 100 | MenuItem search = menu.add("搜索"); 101 | search.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW | MenuItem.SHOW_AS_ACTION_ALWAYS); 102 | search.setIcon(R.drawable.baseline_search_24); 103 | SearchView searchView = new SearchView(this); 104 | search.setActionView(searchView); 105 | searchView.setQueryHint("输入关键字搜索"); 106 | searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { 107 | @Override 108 | public boolean onQueryTextSubmit(String query) { 109 | return false; 110 | } 111 | 112 | @Override 113 | public boolean onQueryTextChange(String newText) { 114 | List filteredList = new ArrayList<>(); 115 | for (LanzouFolder lanzouFolder : folders) { 116 | if (lanzouFolder.getFolder_name().toLowerCase().contains(newText.toLowerCase())) { 117 | filteredList.add(lanzouFolder); 118 | } 119 | } 120 | adapter.submitList(filteredList); 121 | return false; 122 | } 123 | }); 124 | return super.onCreateOptionsMenu(menu); 125 | } 126 | 127 | @Override 128 | protected void onDestroy() { 129 | super.onDestroy(); 130 | unbindService(this); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/ui/upload/UploadListFragment.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.ui.upload; 2 | 3 | import android.content.ComponentName; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.ServiceConnection; 7 | import android.os.Bundle; 8 | import android.os.IBinder; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | import androidx.annotation.NonNull; 14 | import androidx.annotation.Nullable; 15 | import androidx.fragment.app.Fragment; 16 | import androidx.recyclerview.widget.LinearLayoutManager; 17 | import androidx.recyclerview.widget.RecyclerView; 18 | 19 | import com.lanzou.cloud.R; 20 | import com.lanzou.cloud.adapter.UploadAdapter; 21 | import com.lanzou.cloud.data.Upload; 22 | import com.lanzou.cloud.event.OnItemClickListener; 23 | import com.lanzou.cloud.event.OnUploadListener; 24 | import com.lanzou.cloud.service.UploadService; 25 | 26 | import java.util.ArrayList; 27 | import java.util.List; 28 | 29 | public class UploadListFragment extends Fragment implements ServiceConnection, OnUploadListener { 30 | 31 | private UploadService uploadService; 32 | 33 | private final List uploadList = new ArrayList<>(); 34 | 35 | private final UploadAdapter uploadAdapter = new UploadAdapter(uploadList); 36 | 37 | @Override 38 | public void onCreate(@Nullable Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | requireContext().bindService(new Intent(requireContext(), UploadService.class), this, Context.BIND_AUTO_CREATE); 41 | } 42 | 43 | @Nullable 44 | @Override 45 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 46 | return inflater.inflate(R.layout.fragment_transmission_list, container, false); 47 | } 48 | 49 | @Override 50 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 51 | super.onViewCreated(view, savedInstanceState); 52 | RecyclerView recyclerView = (RecyclerView) view; 53 | recyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); 54 | recyclerView.setAdapter(uploadAdapter); 55 | 56 | uploadAdapter.setToggleTransmissionListener(new OnItemClickListener() { 57 | @Override 58 | public void onItemClick(int position, View view) { 59 | Upload upload = uploadList.get(position); 60 | uploadService.toggleUpload(upload); 61 | } 62 | }); 63 | 64 | uploadAdapter.setItemClickListener(new OnItemClickListener() { 65 | @Override 66 | public void onItemClick(int position, View view) { 67 | UploadInfoActivity.start(requireContext(), uploadList.get(position)); 68 | } 69 | }); 70 | } 71 | 72 | @Override 73 | public void onUpload(Upload upload) { 74 | if (upload.isInsert()) { 75 | uploadList.add(0, upload); 76 | uploadAdapter.notifyItemInserted(0); 77 | return; 78 | } 79 | int index = uploadList.indexOf(upload); 80 | if (index != -1) { 81 | uploadAdapter.notifyItemChanged(index, 1); 82 | } else { 83 | uploadList.add(0, upload); 84 | uploadAdapter.notifyItemInserted(0); 85 | } 86 | 87 | } 88 | 89 | @Override 90 | public void onServiceConnected(ComponentName name, IBinder service) { 91 | uploadService = ((UploadService.UploadBinder) service).getService(); 92 | uploadService.addUploadListener(this); 93 | uploadList.addAll(uploadService.getUploadList()); 94 | // 服务连接时对内容进行加载 95 | uploadAdapter.notifyDataSetChanged(); 96 | } 97 | 98 | @Override 99 | public void onServiceDisconnected(ComponentName name) { 100 | // uploadService.removeUploadListener(this); 101 | } 102 | 103 | @Override 104 | public void onDestroy() { 105 | super.onDestroy(); 106 | requireContext().unbindService(this); 107 | uploadService.removeUploadListener(this); 108 | uploadService = null; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/utils/ApkLoaderFactory.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.utils; 2 | 3 | import android.content.Context; 4 | import android.content.pm.ApplicationInfo; 5 | import android.content.pm.PackageManager; 6 | import android.graphics.Bitmap; 7 | import android.graphics.Canvas; 8 | import android.graphics.drawable.BitmapDrawable; 9 | import android.graphics.drawable.Drawable; 10 | import android.text.TextUtils; 11 | 12 | import androidx.annotation.NonNull; 13 | import androidx.annotation.Nullable; 14 | 15 | import com.bumptech.glide.Priority; 16 | import com.bumptech.glide.load.DataSource; 17 | import com.bumptech.glide.load.Options; 18 | import com.bumptech.glide.load.data.DataFetcher; 19 | import com.bumptech.glide.load.model.ModelLoader; 20 | import com.bumptech.glide.load.model.ModelLoaderFactory; 21 | import com.bumptech.glide.load.model.MultiModelLoaderFactory; 22 | import com.bumptech.glide.signature.ObjectKey; 23 | import com.lanzou.cloud.data.FileInfo; 24 | 25 | import java.io.ByteArrayInputStream; 26 | import java.io.ByteArrayOutputStream; 27 | import java.io.InputStream; 28 | 29 | public class ApkLoaderFactory implements ModelLoaderFactory { 30 | 31 | private final Context context; 32 | 33 | public ApkLoaderFactory(Context context) { 34 | this.context = context; 35 | } 36 | 37 | @NonNull 38 | @Override 39 | public ModelLoader build(@NonNull MultiModelLoaderFactory multiFactory) { 40 | return new ApkIconLoader(context); 41 | } 42 | 43 | @Override 44 | public void teardown() { 45 | 46 | } 47 | 48 | static class ApkIconLoader implements ModelLoader { 49 | 50 | private final Context context; 51 | 52 | public ApkIconLoader(Context context) { 53 | this.context = context; 54 | } 55 | 56 | @Nullable 57 | @Override 58 | public LoadData buildLoadData(@NonNull FileInfo fileInfo, int width, int height, @NonNull Options options) { 59 | Object key; 60 | if (!TextUtils.isEmpty(fileInfo.getPkgName())) { 61 | key = fileInfo.getPkgName(); 62 | } else if (fileInfo.getId() != null) { 63 | key = fileInfo.getId(); 64 | } else if (fileInfo.getUri() != null) { 65 | key = fileInfo.getUri(); 66 | } else { 67 | key = fileInfo.hashCode(); 68 | } 69 | return new LoadData<>(new ObjectKey(key), new ApkIconFetcher(context, fileInfo)); 70 | 71 | } 72 | 73 | @Override 74 | public boolean handles(@NonNull FileInfo fileInfo) { 75 | return true; 76 | } 77 | } 78 | 79 | static class ApkIconFetcher implements DataFetcher { 80 | 81 | private final Context context; 82 | private final FileInfo fileInfo; 83 | 84 | public ApkIconFetcher(Context context, FileInfo fileInfo) { 85 | this.context = context; 86 | this.fileInfo = fileInfo; 87 | } 88 | 89 | @Override 90 | public void loadData(@NonNull Priority priority, @NonNull DataCallback callback) { 91 | ApplicationInfo applicationInfo; 92 | try { 93 | PackageManager packageManager = context.getPackageManager(); 94 | Drawable drawable; 95 | if (fileInfo.getPkgName() == null) { 96 | applicationInfo = packageManager.getPackageArchiveInfo(fileInfo.getUri(), 0).applicationInfo; 97 | applicationInfo.sourceDir = fileInfo.getUri(); 98 | applicationInfo.publicSourceDir = fileInfo.getUri(); 99 | drawable = applicationInfo.loadIcon(packageManager); 100 | } else { 101 | applicationInfo = packageManager.getApplicationInfo(fileInfo.getPkgName(), 0); 102 | drawable = packageManager.getApplicationIcon(applicationInfo); //xxx根据自己的情况获取drawable 103 | } 104 | 105 | InputStream inputStream = bitmap2InputStream(drawable2Bitmap(drawable)); 106 | callback.onDataReady(inputStream); 107 | } catch (Exception e) { 108 | callback.onLoadFailed(e); 109 | } 110 | } 111 | 112 | private InputStream bitmap2InputStream(Bitmap bm) { 113 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 114 | bm.compress(Bitmap.CompressFormat.PNG, 100, bos); 115 | return new ByteArrayInputStream(bos.toByteArray()); 116 | } 117 | 118 | private Bitmap drawable2Bitmap(Drawable drawable) { 119 | if (drawable instanceof BitmapDrawable) { 120 | return ((BitmapDrawable) drawable).getBitmap(); 121 | } 122 | Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), 123 | drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 124 | Canvas canvas = new Canvas(bitmap); 125 | drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); 126 | drawable.draw(canvas); 127 | return bitmap; 128 | } 129 | 130 | @Override 131 | public void cleanup() { 132 | 133 | } 134 | 135 | @Override 136 | public void cancel() { 137 | 138 | } 139 | 140 | @NonNull 141 | @Override 142 | public Class getDataClass() { 143 | return InputStream.class; 144 | } 145 | 146 | @NonNull 147 | @Override 148 | public DataSource getDataSource() { 149 | return DataSource.LOCAL; 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/utils/DisplayUtils.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.utils; 2 | 3 | import android.content.Context; 4 | import android.os.Build; 5 | import android.view.WindowManager; 6 | 7 | import com.lanzou.cloud.LanzouApplication; 8 | 9 | public class DisplayUtils { 10 | 11 | public static int getWindowWidth() { 12 | WindowManager windowManager = (WindowManager) LanzouApplication.context 13 | .getSystemService(Context.WINDOW_SERVICE); 14 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 15 | return windowManager.getCurrentWindowMetrics().getBounds().width(); 16 | } 17 | return windowManager.getDefaultDisplay().getWidth(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/utils/SpUtils.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.utils; 2 | 3 | import android.content.SharedPreferences; 4 | import android.preference.PreferenceManager; 5 | 6 | import androidx.annotation.NonNull; 7 | import androidx.annotation.Nullable; 8 | 9 | import com.lanzou.cloud.LanzouApplication; 10 | 11 | public class SpUtils { 12 | 13 | private static final SharedPreferences sharedPreferences = 14 | PreferenceManager.getDefaultSharedPreferences(LanzouApplication.context); 15 | 16 | private static final SharedPreferences.Editor editor = sharedPreferences.edit(); 17 | 18 | public static void save(@NonNull String key, String value) { 19 | editor.putString(key, value); 20 | } 21 | 22 | @Nullable 23 | public static String get(@NonNull String key, @Nullable String def) { 24 | return sharedPreferences.getString(key, def); 25 | } 26 | 27 | public static Long getLong(@NonNull String key) { 28 | return getLong(key, 0L); 29 | } 30 | 31 | public static Long getLong(@NonNull String key, Long def) { 32 | return sharedPreferences.getLong(key, def); 33 | } 34 | 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/lanzou/cloud/utils/UpdateUtils.java: -------------------------------------------------------------------------------- 1 | package com.lanzou.cloud.utils; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.content.Intent; 6 | import android.content.pm.PackageInfo; 7 | import android.content.pm.PackageManager; 8 | import android.net.Uri; 9 | import android.util.Log; 10 | import android.widget.Toast; 11 | 12 | import androidx.annotation.NonNull; 13 | import androidx.core.content.pm.PackageInfoCompat; 14 | 15 | import org.json.JSONException; 16 | import org.json.JSONObject; 17 | 18 | import java.io.IOException; 19 | 20 | import okhttp3.Call; 21 | import okhttp3.Callback; 22 | import okhttp3.OkHttpClient; 23 | import okhttp3.Request; 24 | import okhttp3.Response; 25 | import okhttp3.ResponseBody; 26 | 27 | /** 28 | * App 更新工具类 29 | */ 30 | public class UpdateUtils { 31 | 32 | private static final String TAG = "UpdateUtils"; 33 | 34 | /** 35 | * 更新地址(github pages 部署的静态 json 地址) 36 | */ 37 | private static final String URL = "https://yu2002s.github.io/SplitLanzou/version.json"; 38 | 39 | /** 40 | * 检查更新 41 | * 42 | * @param context activity 43 | */ 44 | public static void checkUpdate(Activity context) { 45 | OkHttpClient okHttpClient = new OkHttpClient(); 46 | Request request = new Request.Builder() 47 | .url(URL) 48 | .build(); 49 | okHttpClient.newCall(request).enqueue(new Callback() { 50 | @Override 51 | public void onFailure(@NonNull Call call, @NonNull IOException e) { 52 | context.runOnUiThread(() -> 53 | Toast.makeText(context, "网络被墙,检查更新失败\n" + e.getMessage(), 54 | Toast.LENGTH_SHORT).show() 55 | ); 56 | } 57 | 58 | @Override 59 | public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { 60 | ResponseBody body = response.body(); 61 | if (body == null) { 62 | Log.i(TAG, "update -> responseBody is null."); 63 | return; 64 | } 65 | String json = body.string(); 66 | handleUpdate(context, json); 67 | } 68 | }); 69 | } 70 | 71 | /** 72 | * 处理更新 73 | * 74 | * @param context activity 75 | * @param json 返回的 json 内容 76 | */ 77 | private static void handleUpdate(Activity context, String json) { 78 | try { 79 | PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); 80 | long currentVersionCode = PackageInfoCompat.getLongVersionCode(packageInfo); 81 | 82 | JSONObject jsonObject = new JSONObject(json); 83 | int versionCode = jsonObject.getInt("versionCode"); 84 | String versionName = jsonObject.getString("version"); 85 | String content = jsonObject.getString("content"); 86 | String url = jsonObject.getString("url"); 87 | context.runOnUiThread(() -> { 88 | if (versionCode > currentVersionCode) { 89 | Log.i(TAG, "发现新版本: " + versionName); 90 | showUpdateDialog(context, versionName, content, url); 91 | } 92 | }); 93 | } catch (JSONException | PackageManager.NameNotFoundException e) { 94 | Log.e(TAG, "处理更新失败: " + e.getMessage()); 95 | } 96 | } 97 | 98 | /** 99 | * 显示更新弹窗 100 | * 101 | * @param context activity 102 | * @param versionName 版本名 103 | * @param content 更新内容 104 | * @param url 更新地址 105 | */ 106 | private static void showUpdateDialog(Activity context, String versionName, String content, String url) { 107 | // 需要更新了 108 | new AlertDialog.Builder(context) 109 | .setTitle("发现新版本-" + versionName) 110 | .setMessage(content) 111 | .setPositiveButton("取消", null) 112 | .setNegativeButton("更新", (dialog, which) -> 113 | context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))) 114 | ).show(); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /app/src/main/res/color/color_card.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_add_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_chevron_right_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_delete_outline_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_done_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_folder_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_get_app_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_home_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_insert_drive_file_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_pause_circle_filled_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_person_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_play_circle_filled_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_search_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_settings_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_share_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_sync_alt_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_card.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_corner_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_corner_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_select.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_select_icon.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_toggle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_download_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 10 | 11 | 17 | 18 | 24 | 25 | 26 | 27 |