├── .gitignore ├── .idea ├── .gitignore ├── .name ├── compiler.xml ├── gradle.xml ├── inspectionProfiles │ └── Project_Default.xml ├── kotlinc.xml ├── misc.xml └── vcs.xml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ └── json.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── clearpole │ │ └── videoyou │ │ └── ExampleInstrumentedTest.kt │ ├── debug │ ├── AndroidManifest.xml │ └── res │ │ └── values │ │ └── strings.xml │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── clearpole │ │ │ └── videoyou │ │ │ ├── BaseActivity.kt │ │ │ ├── ErrorCrashActivity.kt │ │ │ ├── MainActivity.kt │ │ │ ├── PlayListActivity.kt │ │ │ ├── SearchActivity.kt │ │ │ ├── SettingActivity.kt │ │ │ ├── VideoInfoActivity.kt │ │ │ ├── VideoPlayerActivity.kt │ │ │ ├── WebDavActivity.kt │ │ │ ├── adapter │ │ │ └── MainViewPager.kt │ │ │ ├── code │ │ │ ├── MarqueeTextView.java │ │ │ └── PlayList.kt │ │ │ ├── model │ │ │ ├── FolderModel.kt │ │ │ ├── FolderTreeModel.kt │ │ │ ├── MainSettingModel.kt │ │ │ ├── MediaStoreListModel.kt │ │ │ ├── PlayListModel.kt │ │ │ ├── PlayListNameModel.kt │ │ │ ├── PlayerSideSheetModel.kt │ │ │ ├── SearchModel.kt │ │ │ ├── SettingThemeModel.kt │ │ │ ├── VideoInfoModel.kt │ │ │ ├── VideoUtilsModel.kt │ │ │ └── WebDavModel.kt │ │ │ ├── objects │ │ │ ├── AppObjects.kt │ │ │ ├── MainObjects.kt │ │ │ ├── VideoPlayObjects.kt │ │ │ └── VideoPlayerObjects.kt │ │ │ ├── ui │ │ │ └── theme │ │ │ │ ├── Color.kt │ │ │ │ └── Theme.kt │ │ │ └── utils │ │ │ ├── ByteToString.kt │ │ │ ├── DatabaseStorage.kt │ │ │ ├── DeleteVideo.kt │ │ │ ├── DepthFieldTransformer.kt │ │ │ ├── GetVideoThumbnail.kt │ │ │ ├── IsNightMode.kt │ │ │ ├── NoSwipeViewPager.kt │ │ │ ├── ReadMediaStore.kt │ │ │ ├── RefreshMediaStore.kt │ │ │ ├── SeekBarAnim.kt │ │ │ ├── SetBarTransparent.kt │ │ │ ├── SettingsItemsUntil.kt │ │ │ ├── SubStringX.kt │ │ │ └── TimeParse.kt │ └── res │ │ ├── anim │ │ ├── alpha_0_1.xml │ │ └── alpha_1_0.xml │ │ ├── drawable-v24 │ │ ├── ic_launcher_foreground.xml │ │ └── ripple.xml │ │ ├── drawable │ │ ├── baseline_arrow_back_24.xml │ │ ├── baseline_arrow_back_small.xml │ │ ├── baseline_auto_fix_high_24.xml │ │ ├── baseline_cached_24.xml │ │ ├── baseline_check_24.xml │ │ ├── baseline_checklist_rtl_24.xml │ │ ├── baseline_chevron_right_24.xml │ │ ├── baseline_code_24.xml │ │ ├── baseline_delete_forever_24.xml │ │ ├── baseline_explore_24.xml │ │ ├── baseline_extension_24.xml │ │ ├── baseline_folder_open_24.xml │ │ ├── baseline_format_list_bulleted_24.xml │ │ ├── baseline_fullscreen_24.xml │ │ ├── baseline_fullscreen_exit_24.xml │ │ ├── baseline_gesture_24.xml │ │ ├── baseline_hearing_24.xml │ │ ├── baseline_help_24.xml │ │ ├── baseline_home_24.xml │ │ ├── baseline_keyboard_arrow_down_24.xml │ │ ├── baseline_keyboard_arrow_right_24.xml │ │ ├── baseline_lock_open_24.xml │ │ ├── baseline_map_24.xml │ │ ├── baseline_mark_unread_chat_alt_24.xml │ │ ├── baseline_menu_24.xml │ │ ├── baseline_note_add_24.xml │ │ ├── baseline_notifications_none_24.xml │ │ ├── baseline_pause_24.xml │ │ ├── baseline_picture_in_picture_24.xml │ │ ├── baseline_play_arrow_24.xml │ │ ├── baseline_playlist_add_24.xml │ │ ├── baseline_playlist_add_check_24.xml │ │ ├── baseline_refresh_24.xml │ │ ├── baseline_screen_rotation_24.xml │ │ ├── baseline_search_24.xml │ │ ├── baseline_settings_24.xml │ │ ├── baseline_skip_next_24.xml │ │ ├── baseline_skip_previous_24.xml │ │ ├── baseline_web_24.xml │ │ ├── baseline_webhook_24.xml │ │ ├── baseline_wifi_tethering_24.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── outline_auto_fix_high_24.xml │ │ ├── outline_chat_24.xml │ │ ├── outline_delete_forever_24.xml │ │ ├── outline_exit_to_app_24.xml │ │ ├── outline_explore_24.xml │ │ ├── outline_file_copy_24.xml │ │ ├── outline_gesture_24.xml │ │ ├── outline_hearing_disabled_24.xml │ │ ├── outline_light_mode_24.xml │ │ ├── outline_lock_24.xml │ │ ├── outline_mode_night_24.xml │ │ ├── outline_monetization_on_24.xml │ │ ├── outline_speed_24.xml │ │ ├── player_bottom_background.xml │ │ ├── player_top_background.xml │ │ ├── twotone_attach_file_24.xml │ │ ├── twotone_drive_folder_upload_24.xml │ │ ├── twotone_folder_24.xml │ │ └── video_player_toolbar_background.xml │ │ ├── layout │ │ ├── activity_error_crash.xml │ │ ├── activity_main.xml │ │ ├── activity_play_list.xml │ │ ├── activity_search.xml │ │ ├── activity_setting.xml │ │ ├── activity_video_info.xml │ │ ├── activity_web_dav.xml │ │ ├── app_is_activation.xml │ │ ├── compose_videolist.xml │ │ ├── compose_videoplayer.xml │ │ ├── compose_videoslider.xml │ │ ├── folder_list_item.xml │ │ ├── folder_list_tree_item.xml │ │ ├── main_drawer_header.xml │ │ ├── main_page_folder.xml │ │ ├── main_page_mediastore.xml │ │ ├── main_page_playlist.xml │ │ ├── main_page_setting.xml │ │ ├── main_page_setting_item.xml │ │ ├── material_dialog_edit_1.xml │ │ ├── material_dialog_edit_4.xml │ │ ├── media_store_list_item.xml │ │ ├── play_list_name_item.xml │ │ ├── play_list_videos_item.xml │ │ ├── player_side_sheet.xml │ │ ├── search_item.xml │ │ ├── setting_about.xml │ │ ├── setting_about_do.xml │ │ ├── setting_currency.xml │ │ ├── setting_show.xml │ │ ├── setting_theme.xml │ │ ├── setting_theme_item.xml │ │ ├── video_info_item.xml │ │ ├── video_info_utils_item.xml │ │ └── webdav_list_item.xml │ │ ├── menu │ │ ├── main_choose.xml │ │ ├── main_drawer.xml │ │ ├── main_navigation.xml │ │ ├── main_toolbar.xml │ │ ├── playlist_toolbar.xml │ │ ├── video_info.xml │ │ └── webdav_menu.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ ├── ic_launcher_round.webp │ │ └── twox.gif │ │ ├── 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-night │ │ └── themes.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ └── data_extraction_rules.xml │ └── test │ └── java │ └── com │ └── clearpole │ └── videoyou │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.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 16 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # 默认忽略的文件 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | VideoYou - opt -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 36 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 项目已迁移至 https://github.com/Clearpole/VideoYouX 2 | # 项目已迁移至 https://github.com/Clearpole/VideoYouX 3 | # 项目已迁移至 https://github.com/Clearpole/VideoYouX 4 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'org.jetbrains.kotlin.android' 4 | } 5 | apply plugin: 'com.android.application' 6 | android { 7 | namespace 'com.clearpole.videoyou' 8 | compileSdk 33 9 | buildFeatures { 10 | dataBinding true 11 | viewBinding true 12 | compose true 13 | } 14 | 15 | apply plugin: 'kotlin-kapt' 16 | 17 | kapt { 18 | generateStubs = true 19 | } 20 | 21 | defaultConfig { 22 | applicationId "com.clearpole.videoyou" 23 | minSdk 21 24 | targetSdk 33 25 | versionCode 1 26 | if (isCanary()) { 27 | versionName version() + " - " + canary() 28 | } else { 29 | versionName version() 30 | } 31 | 32 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 33 | vectorDrawables { 34 | useSupportLibrary true 35 | } 36 | resConfigs "zh-rCN" 37 | } 38 | 39 | buildTypes { 40 | release { 41 | zipAlignEnabled true 42 | applicationVariants.configureEach { variant -> 43 | variant.outputs.configureEach { 44 | def fileName = "${appName()}-${version()}" 45 | fileName = fileName + "-${releaseTime()}" 46 | if (!isCanary()) { 47 | // 如果是release版本,直接显示 48 | fileName = fileName + "-release.apk" 49 | } else { 50 | fileName = fileName + "-" + canary() + ".apk" 51 | } 52 | outputFileName = fileName 53 | } 54 | } 55 | 56 | } 57 | } 58 | sourceSets { 59 | main { 60 | jniLibs.srcDirs = ['libs'] 61 | } 62 | } 63 | 64 | compileOptions { 65 | sourceCompatibility JavaVersion.VERSION_19 66 | targetCompatibility JavaVersion.VERSION_19 67 | } 68 | kotlinOptions { 69 | jvmTarget = '19' 70 | } 71 | composeOptions { 72 | kotlinCompilerExtensionVersion '1.4.0' 73 | } 74 | packagingOptions { 75 | resources { 76 | excludes += '/META-INF/{AL2.0,LGPL2.1}' 77 | } 78 | } 79 | } 80 | 81 | static def version() { 82 | return "0.5.5" 83 | } 84 | 85 | static def isCanary() { 86 | return true 87 | } 88 | 89 | static def appName() { 90 | return "VideoYou" 91 | } 92 | 93 | static def canary() { 94 | return "Beta03" 95 | } 96 | 97 | static def releaseTime() { 98 | return new Date().format("yyyyMMdd", TimeZone.getTimeZone("UTC")) 99 | } 100 | 101 | dependencies { 102 | implementation 'androidx.core:core-ktx:1.9.0' 103 | implementation 'androidx.appcompat:appcompat:1.6.0' 104 | implementation 'com.google.android.material:material:1.9.0-alpha01' 105 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4' 106 | implementation 'androidx.compose.compiler:compiler:1.4.0' 107 | implementation 'androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha05' 108 | implementation 'androidx.preference:preference:1.2.0' 109 | api fileTree(include: ['*.jar'], dir: 'libs') 110 | implementation files('libs/json.jar') 111 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1' 112 | implementation 'androidx.activity:activity-compose:1.5.1' 113 | implementation platform('androidx.compose:compose-bom:2022.10.00') 114 | implementation 'androidx.compose.ui:ui' 115 | implementation 'androidx.compose.ui:ui-graphics' 116 | implementation 'androidx.compose.ui:ui-tooling-preview' 117 | implementation 'androidx.compose.material3:material3:1.1.0-alpha06' 118 | testImplementation 'junit:junit:4.13.2' 119 | androidTestImplementation 'androidx.test.ext:junit:1.1.5' 120 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' 121 | implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" 122 | //依赖协程核心库 123 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4' 124 | //依赖当前平台所对应的平台库 125 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4' 126 | 127 | // ViewBindingKTX:https://github.com/DylanCaiCoding/ViewBindingKTX 128 | implementation 'com.github.DylanCaiCoding.ViewBindingKTX:viewbinding-ktx:2.1.0' 129 | implementation 'com.github.DylanCaiCoding.ViewBindingKTX:viewbinding-base:2.1.0' 130 | // 状态栏:https://github.com/gyf-dev/ImmersionBar 131 | implementation 'com.geyifeng.immersionbar:immersionbar:3.2.2' 132 | // OkHttp 框架:https://github.com/square/okhttp 133 | implementation 'com.squareup.okhttp3:okhttp:4.10.0' 134 | // 强大的列表组件 https://github.com/liangjingkanji/BRV 135 | implementation 'com.github.liangjingkanji:BRV:1.3.88' 136 | // 权限请求框架:https://github.com/getActivity/XXPermissions 137 | implementation 'com.github.getActivity:XXPermissions:16.6' 138 | // Glide图片加载框架:https://github.com/bumptech/glide 139 | implementation 'com.github.bumptech.glide:glide:4.14.2' 140 | androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00') 141 | androidTestImplementation 'androidx.compose.ui:ui-test-junit4' 142 | annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2' 143 | // MMKV —— 基于 mmap 的高性能通用 key-value 组件:https://github.com/Tencent/MMKV/ 144 | implementation 'com.tencent:mmkv:1.2.15' 145 | // exoplayer 视频播放框架 146 | implementation 'com.google.android.exoplayer:exoplayer:2.18.2' 147 | // webdav框架:https://github.com/thegrizzlylabs/sardine-android 148 | implementation 'com.thegrizzlylabs.sardine-android:sardine-android:0.8' 149 | // https://github.com/Blankj/AndroidUtilCode/ 150 | implementation 'com.blankj:utilcodex:1.31.1' 151 | implementation 'com.github.TutorialsAndroid:crashx:v6.0.19' 152 | debugImplementation 'androidx.compose.ui:ui-tooling' 153 | debugImplementation 'androidx.compose.ui:ui-test-manifest' 154 | } -------------------------------------------------------------------------------- /app/libs/json.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clearpole/VideoYou/ea93e09dee20d777dacd1942cca294e5aecf901c/app/libs/json.jar -------------------------------------------------------------------------------- /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 22 | 23 | -dontwarn org.bouncycastle.jsse.BCSSLSocket 24 | -dontwarn org.bouncycastle.jsse.BCSSLParameters 25 | -dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider 26 | -dontwarn org.conscrypt.* 27 | -dontwarn org.openjsse.javax.net.ssl.SSLParameters 28 | -dontwarn org.openjsse.javax.net.ssl.SSLSocket 29 | -dontwarn org.openjsse.net.ssl.OpenJSSE 30 | -dontwarn com.hjq.permissions.** 31 | #keep 类名和类成员都不会被移除和混淆 32 | -keep class * implements androidx.viewbinding.ViewBinding { 33 | *; 34 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/clearpole/videoyou/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.clearpole.videoyou", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/debug/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 17 | 18 | 19 | 30 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 53 | 56 | 59 | 60 | 61 | 62 | 63 | 66 | 69 | 73 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou 2 | 3 | import android.os.Build 4 | import android.os.Bundle 5 | import androidx.appcompat.app.AppCompatActivity 6 | import androidx.appcompat.app.AppCompatDelegate 7 | import androidx.viewbinding.ViewBinding 8 | import com.clearpole.videoyou.objects.AppObjects 9 | import com.clearpole.videoyou.utils.SettingsItemsUntil 10 | import com.developer.crashx.config.CrashConfig 11 | import com.dylanc.viewbinding.base.ViewBindingUtil 12 | import com.google.android.material.color.DynamicColors 13 | import com.tencent.mmkv.MMKV 14 | 15 | 16 | abstract class BaseActivity : AppCompatActivity() { 17 | lateinit var binding: VB 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | MMKV.initialize(this) 21 | val kv = MMKV.mmkvWithID("theme") 22 | val theme = kv.decodeInt("theme") 23 | if (theme.toString().isEmpty()) { 24 | // 第一次进入 25 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { 26 | // 安卓版本大于12 27 | kv.encode("theme", 0) 28 | // 动态颜色 29 | DynamicColors.applyToActivityIfAvailable(this) 30 | } else { 31 | // 安卓版本小于12 32 | kv.encode("theme", R.style.hzt) 33 | setTheme(R.style.hzt) 34 | // 默认主题和紫棠 35 | } 36 | } else { 37 | // 不是第一次进入 38 | when (theme) { 39 | 0 -> { 40 | DynamicColors.applyToActivityIfAvailable(this) 41 | AppObjects.theme = 0 42 | } 43 | 44 | R.style.hzt -> { 45 | setTheme(R.style.hzt) 46 | AppObjects.theme = 1 47 | } 48 | 49 | R.style.cxw -> { 50 | setTheme(R.style.cxw) 51 | AppObjects.theme = 2 52 | } 53 | 54 | R.style.szy -> { 55 | setTheme(R.style.szy) 56 | AppObjects.theme = 3 57 | } 58 | 59 | R.style.xfy -> { 60 | setTheme(R.style.xfy) 61 | AppObjects.theme = 4 62 | } 63 | } 64 | } 65 | try { 66 | when (SettingsItemsUntil.readSettingData("darkMode")?.toInt()!!) { 67 | 0 -> { 68 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) 69 | } 70 | 71 | 1 -> { 72 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) 73 | } 74 | 75 | 2 -> { 76 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) 77 | } 78 | } 79 | } catch (_: Exception) { 80 | } 81 | binding = ViewBindingUtil.inflateWithGeneric(this, layoutInflater) 82 | SettingsItemsUntil.fixItems() 83 | setContentView(binding.root) 84 | CrashConfig.Builder.create().errorActivity(ErrorCrashActivity::class.java) 85 | } 86 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/ErrorCrashActivity.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import com.clearpole.videoyou.databinding.ActivityErrorCrashBinding 6 | import com.clearpole.videoyou.utils.IsNightMode 7 | import com.developer.crashx.CrashActivity 8 | import com.gyf.immersionbar.ImmersionBar 9 | 10 | class ErrorCrashActivity : BaseActivity() { 11 | @SuppressLint("RestrictedApi") 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | super.onCreate(savedInstanceState) 14 | ImmersionBar.with(this).transparentBar() 15 | .statusBarDarkFont(!IsNightMode.isNightMode(resources)).init() 16 | binding.errorLog.text = CrashActivity.getAllErrorDetailsFromIntent(this,intent) 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/PlayListActivity.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou 2 | 3 | import android.media.MediaMetadataRetriever 4 | import android.os.Bundle 5 | import com.blankj.utilcode.util.ToastUtils 6 | import com.clearpole.videoyou.code.PlayList 7 | import com.clearpole.videoyou.databinding.ActivityPlayListBinding 8 | import com.clearpole.videoyou.model.PlayListModel 9 | import com.clearpole.videoyou.utils.IsNightMode 10 | import com.clearpole.videoyou.utils.SubStringX.Companion.subStringX 11 | import com.drake.brv.utils.linear 12 | import com.drake.brv.utils.setup 13 | import com.google.android.material.R.style.MaterialAlertDialog_Material3 14 | import com.google.android.material.dialog.MaterialAlertDialogBuilder 15 | import com.gyf.immersionbar.ImmersionBar 16 | import kotlinx.coroutines.CoroutineScope 17 | import kotlinx.coroutines.Dispatchers 18 | import kotlinx.coroutines.launch 19 | import kotlinx.coroutines.withContext 20 | import org.json.JSONObject 21 | 22 | 23 | class PlayListActivity : BaseActivity() { 24 | override fun onCreate(savedInstanceState: Bundle?) { 25 | super.onCreate(savedInstanceState) 26 | ImmersionBar.with(this).transparentBar() 27 | .statusBarDarkFont(!IsNightMode.isNightMode(resources)).init() 28 | val name = intent.getStringExtra("name") 29 | binding.topAppBar.title = name 30 | CoroutineScope(Dispatchers.IO).launch { 31 | val model = getData() 32 | withContext(Dispatchers.Main) { 33 | binding.listview.linear().setup { 34 | addType { R.layout.media_store_list_item } 35 | }.models = model 36 | } 37 | } 38 | binding.topAppBar.setOnMenuItemClickListener { 39 | when (it.itemId) { 40 | R.id.removePlayList -> { 41 | MaterialAlertDialogBuilder(this, MaterialAlertDialog_Material3) 42 | .setTitle("删除播放列表") 43 | .setMessage("是否删除播放列表《$name》?") 44 | .setNegativeButton("删除") { _, _ -> 45 | PlayList.removeList(name!!) 46 | finish() 47 | ToastUtils.showShort("刷新后生效") 48 | } 49 | .setNeutralButton("取消") { _, _ -> } 50 | .show() 51 | true 52 | } 53 | 54 | else -> false 55 | } 56 | } 57 | } 58 | 59 | private fun getData(): MutableList { 60 | return mutableListOf().apply { 61 | try { 62 | val list = 63 | JSONObject(PlayList.readPlayListContent(intent.getStringExtra("name")!!)!!) 64 | val keys = list.keys() 65 | val retriever = MediaMetadataRetriever() 66 | while (keys.hasNext()) { 67 | val key = keys.next().toString() 68 | val uri = list.getString(key) 69 | retriever.setDataSource(uri) 70 | val title = uri.substring(uri.lastIndexOf("/") + 1, uri.lastIndexOf(".")) 71 | val duration = 72 | retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION) 73 | val time = key.subStringX(null, ":") 74 | add(PlayListModel(uri, title, duration, time,list)) 75 | } 76 | } catch (_: Exception) { 77 | 78 | } 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/SearchActivity.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou 2 | 3 | import android.annotation.SuppressLint 4 | import android.net.Uri 5 | import android.os.Bundle 6 | import androidx.recyclerview.widget.StaggeredGridLayoutManager 7 | import com.blankj.utilcode.util.ScreenUtils 8 | import com.clearpole.videoyou.databinding.ActivitySearchBinding 9 | import com.clearpole.videoyou.databinding.SearchItemBinding 10 | import com.clearpole.videoyou.model.SearchModel 11 | import com.clearpole.videoyou.utils.DatabaseStorage 12 | import com.clearpole.videoyou.utils.IsNightMode 13 | import com.drake.brv.utils.linear 14 | import com.drake.brv.utils.setup 15 | import com.gyf.immersionbar.ImmersionBar 16 | import kotlinx.coroutines.CoroutineScope 17 | import kotlinx.coroutines.Dispatchers 18 | import kotlinx.coroutines.launch 19 | import org.json.JSONArray 20 | import org.json.JSONObject 21 | 22 | 23 | class SearchActivity : BaseActivity() { 24 | override fun onCreate(savedInstanceState: Bundle?) { 25 | super.onCreate(savedInstanceState) 26 | ImmersionBar.with(this).transparentBar() 27 | .statusBarDarkFont(!IsNightMode.isNightMode(resources)).init() 28 | binding.catSearchView.editText.setOnEditorActionListener { v, _, _ -> 29 | binding.catSearchBar.text = v.text 30 | setSearchList(v.text.toString()) 31 | binding.catSearchView.hide() 32 | false 33 | } 34 | binding.searchRv.layoutParams.height = ScreenUtils.getAppScreenHeight() 35 | } 36 | 37 | @SuppressLint("CutPasteId", "SetTextI18n") 38 | private fun setSearchList(key: String) { 39 | CoroutineScope(Dispatchers.IO).launch { 40 | val models = getDataForSearch(key, DatabaseStorage.readDataByData()!!) 41 | launch(Dispatchers.Main) { 42 | binding.searchRv.linear().setup { 43 | addType { R.layout.search_item } 44 | onCreate { 45 | val binding = SearchItemBinding.bind(itemView) 46 | binding.itemImg.layoutParams.height = (160..300).random() 47 | } 48 | }.models = models 49 | binding.searchRv.layoutManager = StaggeredGridLayoutManager( 50 | 2, 51 | StaggeredGridLayoutManager.VERTICAL 52 | ) 53 | } 54 | } 55 | } 56 | 57 | private fun getDataForSearch(key: String, kv: JSONArray): MutableList { 58 | return mutableListOf().apply { 59 | for (index in 0 until kv.length()) { 60 | val jsonObject = JSONObject(kv.getString(index)) 61 | if (jsonObject.getString("title").contains(key)) { 62 | add( 63 | SearchModel( 64 | title = jsonObject.getString("title"), 65 | size = jsonObject.getString("size"), 66 | uri = Uri.parse(jsonObject.getString("uri")), 67 | path = jsonObject.getString("path"), 68 | ) 69 | ) 70 | } 71 | } 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/adapter/MainViewPager.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.adapter 2 | 3 | import android.view.View 4 | import android.view.ViewGroup 5 | import androidx.viewpager.widget.PagerAdapter 6 | 7 | class MainViewPager : PagerAdapter { 8 | // 定义视图列表 9 | private var viewList: List = ArrayList() 10 | 11 | // 构造方法传入数据 12 | constructor(viewList: List) { 13 | this.viewList = viewList 14 | } 15 | 16 | constructor() 17 | 18 | //初始化指定位置的页面 19 | override fun instantiateItem(container: ViewGroup, position: Int): Any { 20 | 21 | //将页面加入容器 22 | container.addView(viewList[position]) 23 | //返回加载的页面 24 | return viewList[position] 25 | } 26 | 27 | //销毁指定位置的页面 28 | override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { 29 | container.removeView(viewList[position]) //删除页面 30 | } 31 | 32 | //显示多少个页面 33 | override fun getCount(): Int { 34 | return viewList.size 35 | } 36 | 37 | //判断view 是否是object 38 | override fun isViewFromObject(view: View, `object`: Any): Boolean { 39 | return view === `object` 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/code/MarqueeTextView.java: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.code; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.util.AttributeSet; 6 | 7 | import androidx.annotation.Nullable; 8 | 9 | import com.google.android.material.textview.MaterialTextView; 10 | 11 | @SuppressLint("AppCompatCustomView") 12 | public class MarqueeTextView extends MaterialTextView { 13 | 14 | public MarqueeTextView(Context context) { 15 | super(context); 16 | } 17 | 18 | public MarqueeTextView(Context context, @Nullable AttributeSet attrs) { 19 | super(context, attrs); 20 | } 21 | 22 | public MarqueeTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 23 | super(context, attrs, defStyleAttr); 24 | } 25 | 26 | public MarqueeTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 27 | super(context, attrs, defStyleAttr, defStyleRes); 28 | } 29 | 30 | @Override 31 | public boolean isFocused() { 32 | return true; 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/code/PlayList.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.code 2 | 3 | import android.annotation.SuppressLint 4 | import com.blankj.utilcode.util.TimeUtils 5 | import com.tencent.mmkv.MMKV 6 | import kotlinx.coroutines.CoroutineScope 7 | import kotlinx.coroutines.Dispatchers 8 | import kotlinx.coroutines.launch 9 | import kotlinx.coroutines.withContext 10 | import org.json.JSONObject 11 | 12 | class PlayList { 13 | companion object { 14 | private val mainKv = MMKV.mmkvWithID("videoyou-playlist-name") 15 | private val nextKv = MMKV.mmkvWithID("videoyou-playlist-content") 16 | 17 | // 用于存放视频列表的名称,仅存放名称 18 | fun addList(name: String) { 19 | val json = JSONObject() 20 | json.put( 21 | "time", TimeUtils.getNowMills() 22 | ) 23 | json.put("index", mainKv.count() + 1) 24 | json.put("count", 0) 25 | mainKv.putString(name, json.toString()) 26 | // 将名称存入储存库,赋值的是它的索引 27 | } 28 | 29 | @SuppressLint("SimpleDateFormat") 30 | fun readList(): List { 31 | return mainKv.allKeys()!!.sortedBy { 32 | TimeUtils.millis2Date( 33 | JSONObject( 34 | mainKv.decodeString(it).toString() 35 | ).getLong("time") 36 | ) 37 | }.reversed() 38 | // 返回名称存储库内所有的名称 39 | } 40 | 41 | fun readListContent(name: String): String? { 42 | return mainKv.decodeString(name) 43 | } 44 | 45 | fun removeList(name: String) { 46 | mainKv.remove(name) 47 | nextKv.remove(name) 48 | } 49 | 50 | fun addPlayListContent(name: String, list: ArrayList) { 51 | if (!nextKv.decodeString(name).isNullOrEmpty()) { 52 | CoroutineScope(Dispatchers.IO).launch { 53 | val late = JSONObject(nextKv.decodeString(name)!!) 54 | val keys = JSONObject(nextKv.decodeString(name)!!).keys() 55 | while (keys.hasNext()) { 56 | val time = keys.next().toString() 57 | val uri = late.getString(time) 58 | if (list.contains(uri)) { 59 | late.remove(time) 60 | } 61 | } 62 | withContext(Dispatchers.IO) { 63 | list.forEachIndexed { _, s -> 64 | late.put( 65 | TimeUtils.getNowMills().toString() + ":${(0..9999999).random()}", s 66 | ) 67 | nextKv.encode(name, late.toString()) 68 | } 69 | } 70 | } 71 | } else { 72 | val json = JSONObject() 73 | list.forEachIndexed { _, s -> 74 | json.put(TimeUtils.getNowMills().toString() + ":${(0..9999999).random()}", s) 75 | nextKv.encode(name, json.toString()) 76 | } 77 | } 78 | } 79 | 80 | fun readPlayListContent(name: String): String? { 81 | return nextKv.decodeString(name) 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/model/FolderModel.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.model 2 | 3 | import android.content.ContentResolver 4 | import android.net.Uri 5 | import android.view.View 6 | import androidx.databinding.BaseObservable 7 | import com.bumptech.glide.Glide 8 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions 9 | import com.clearpole.videoyou.databinding.FolderListItemBinding 10 | import com.clearpole.videoyou.utils.GetVideoThumbnail 11 | import com.drake.brv.BindingAdapter 12 | import com.drake.brv.item.ItemBind 13 | import com.drake.brv.item.ItemExpand 14 | import kotlinx.coroutines.CoroutineScope 15 | import kotlinx.coroutines.Dispatchers 16 | import kotlinx.coroutines.cancel 17 | import kotlinx.coroutines.launch 18 | import kotlinx.coroutines.withContext 19 | 20 | 21 | open class FolderModel( 22 | override var itemGroupPosition: Int = 0, 23 | override var itemExpand: Boolean = false, 24 | override var itemSublist: List? = null, 25 | var checked: Boolean = false, 26 | var vis: Int = View.GONE, 27 | val title: String, 28 | val uri: Uri, 29 | val path: String 30 | ) : ItemExpand, ItemBind, BaseObservable() { 31 | val videoTitle get() = title 32 | override fun onBind(holder: BindingAdapter.BindingViewHolder) { 33 | 34 | val binding = holder.getBinding() 35 | CoroutineScope(Dispatchers.IO).launch { 36 | withContext(Dispatchers.Main) { 37 | Glide.with(holder.context) 38 | .load(uri) 39 | .transition(DrawableTransitionOptions.withCrossFade()) 40 | .into(binding.page2RvItemImg) 41 | } 42 | this.cancel() 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/model/FolderTreeModel.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.model 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.ContentResolver 5 | import android.graphics.drawable.Drawable 6 | import android.net.Uri 7 | import androidx.databinding.BaseObservable 8 | import com.clearpole.videoyou.objects.MainObjects 9 | import com.drake.brv.item.ItemExpand 10 | import com.drake.brv.item.ItemHover 11 | import com.drake.brv.item.ItemPosition 12 | import org.json.JSONArray 13 | import org.json.JSONObject 14 | 15 | open class FolderTreeModel( 16 | private val contentResolver: ContentResolver, 17 | val path: String?, 18 | private val json: JSONArray, 19 | private val openImg: Drawable, 20 | private val closeImg: Drawable 21 | ) : ItemExpand, ItemHover, ItemPosition, 22 | BaseObservable() { 23 | 24 | override var itemGroupPosition: Int = 0 25 | override var itemExpand: Boolean = false 26 | set(value) { 27 | field = value 28 | notifyChange() 29 | } 30 | 31 | override var itemSublist: List? 32 | get() = jsonSublist 33 | set(value) { 34 | @Suppress("UNCHECKED_CAST") 35 | jsonSublist = value as List 36 | } 37 | private var jCount = 0 38 | private var jsonSublist: List = mutableListOf().apply { 39 | for (index in 0 until json.length()) { 40 | val objects = JSONObject(json.getString(index)) 41 | var folder = "根目录" 42 | try { 43 | folder = objects.getString("folder") 44 | } catch (_: Exception) { 45 | } 46 | if (folder == title) { 47 | add( 48 | FolderModel( 49 | title = objects.getString("title"), 50 | uri = Uri.parse(objects.getString("uri")), 51 | path = objects.getString("path") 52 | ) 53 | ) 54 | jCount += 1 55 | MainObjects.count = jCount 56 | } 57 | } 58 | } 59 | 60 | override var itemHover: Boolean = true 61 | override var itemPosition: Int = 0 62 | 63 | 64 | val title get() = path 65 | val expandIcon 66 | @SuppressLint("ResourceType") 67 | get() = if (itemExpand) openImg else closeImg 68 | val count get() = jCount 69 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/model/MainSettingModel.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.model 2 | 3 | import android.content.Intent 4 | import android.graphics.drawable.Drawable 5 | import com.bumptech.glide.Glide 6 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions 7 | import com.clearpole.videoyou.SettingActivity 8 | import com.clearpole.videoyou.databinding.MainPageSettingItemBinding 9 | import com.drake.brv.BindingAdapter 10 | import com.drake.brv.item.ItemBind 11 | 12 | data class MainSettingModel(val title: String, val info: String, val img: Drawable) : ItemBind { 13 | override fun onBind(holder: BindingAdapter.BindingViewHolder) { 14 | val binding = holder.getBinding() 15 | binding.title.text = title 16 | binding.info.text = info 17 | Glide.with(holder.context).load(img).transition(DrawableTransitionOptions.withCrossFade()) 18 | .into(binding.sLI) 19 | binding.root.setOnClickListener { 20 | val intent = Intent(holder.context,SettingActivity::class.java) 21 | intent.putExtra("name",title) 22 | holder.context.startActivity(intent) 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/model/MediaStoreListModel.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.model 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.net.Uri 6 | import android.os.Bundle 7 | import android.view.View 8 | import androidx.core.app.ActivityOptionsCompat 9 | import com.blankj.utilcode.util.ActivityUtils.startActivity 10 | import com.bumptech.glide.Glide 11 | import com.bumptech.glide.load.engine.DiskCacheStrategy 12 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions 13 | import com.clearpole.videoyou.VideoInfoActivity 14 | import com.clearpole.videoyou.VideoPlayerActivity 15 | import com.clearpole.videoyou.databinding.ActivityMainBinding 16 | import com.clearpole.videoyou.databinding.MediaStoreListItemBinding 17 | import com.clearpole.videoyou.objects.VideoPlayObjects 18 | import com.clearpole.videoyou.utils.GetVideoThumbnail 19 | import com.drake.brv.BindingAdapter 20 | import com.drake.brv.item.ItemBind 21 | import kotlinx.coroutines.CoroutineScope 22 | import kotlinx.coroutines.Dispatchers 23 | import kotlinx.coroutines.cancel 24 | import kotlinx.coroutines.launch 25 | import kotlinx.coroutines.withContext 26 | 27 | 28 | data class MediaStoreListModel( 29 | val title: String, 30 | val size: String, 31 | val uri: Uri, 32 | val path: String, 33 | val mainBind: ActivityMainBinding?, 34 | val activity: Activity 35 | ) : ItemBind { 36 | override fun onBind(holder: BindingAdapter.BindingViewHolder) { 37 | val binding = MediaStoreListItemBinding.bind(holder.itemView) 38 | binding.itemName.text = title 39 | binding.itemSize.text = size 40 | binding.itemRoot.setOnClickListener { 41 | VideoPlayObjects.paths = path 42 | VideoPlayObjects.title = title 43 | VideoPlayObjects.type = "LOCAL" 44 | VideoPlayObjects.list = mutableListOf(path) 45 | VideoPlayObjects.uri = uri 46 | val intent = Intent(holder.context, VideoInfoActivity::class.java) 47 | val bundle: Bundle = ActivityOptionsCompat.makeSceneTransitionAnimation( 48 | activity, 49 | binding.card, 50 | "VideoYouInfoImageName" 51 | ).toBundle()!! 52 | intent.data = uri 53 | intent.putExtra("int","0") 54 | startActivity(intent, bundle) 55 | } 56 | 57 | CoroutineScope(Dispatchers.IO).launch { 58 | withContext(Dispatchers.Main) { 59 | Glide.with(holder.context).load(uri) 60 | .transition(DrawableTransitionOptions.withCrossFade()).into(binding.itemCover) 61 | } 62 | this.cancel() 63 | } 64 | 65 | } 66 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/model/PlayListModel.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.model 2 | 3 | import android.content.Intent 4 | import com.blankj.utilcode.util.ActivityUtils 5 | import com.bumptech.glide.Glide 6 | import com.bumptech.glide.load.engine.DiskCacheStrategy 7 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions 8 | import com.clearpole.videoyou.VideoPlayerActivity 9 | import com.clearpole.videoyou.databinding.MediaStoreListItemBinding 10 | import com.clearpole.videoyou.objects.VideoPlayObjects 11 | import com.clearpole.videoyou.objects.VideoPlayerObjects 12 | import com.clearpole.videoyou.utils.TimeParse 13 | import com.drake.brv.BindingAdapter 14 | import com.drake.brv.item.ItemBind 15 | import kotlinx.coroutines.CoroutineScope 16 | import kotlinx.coroutines.Dispatchers 17 | import kotlinx.coroutines.launch 18 | import kotlinx.coroutines.withContext 19 | import org.json.JSONObject 20 | 21 | data class PlayListModel( 22 | val uri: String, 23 | val title: String?, 24 | val duration: String?, 25 | val time: String?, 26 | val list: JSONObject 27 | ) : ItemBind { 28 | override fun onBind(holder: BindingAdapter.BindingViewHolder) { 29 | val binding = MediaStoreListItemBinding.bind(holder.itemView) 30 | binding.itemName.text = title 31 | Glide.with(holder.context).load(uri).diskCacheStrategy(DiskCacheStrategy.RESOURCE) 32 | .transition( 33 | DrawableTransitionOptions.withCrossFade() 34 | ).into(binding.itemCover) 35 | binding.itemSize.text = TimeParse.timeParse(duration!!.toLong()) 36 | binding.itemRoot.setOnClickListener { 37 | CoroutineScope(Dispatchers.IO).launch { 38 | val array = arrayListOf() 39 | val keys = list.keys() 40 | while (keys.hasNext()) { 41 | val key = keys.next().toString() 42 | val uri = list.getString(key) 43 | array.add(uri) 44 | VideoPlayObjects.list = array.toMutableList() 45 | } 46 | VideoPlayObjects.title = title.toString() 47 | VideoPlayObjects.type = "LOCAL" 48 | VideoPlayerObjects.newItem = holder.layoutPosition 49 | withContext(Dispatchers.Main) { 50 | val intent = Intent(holder.context, VideoPlayerActivity::class.java) 51 | ActivityUtils.startActivity(intent) 52 | } 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/model/PlayListNameModel.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.model 2 | 3 | import android.content.Intent 4 | import com.bumptech.glide.Glide 5 | import com.bumptech.glide.load.engine.DiskCacheStrategy 6 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions 7 | import com.clearpole.videoyou.PlayListActivity 8 | import com.clearpole.videoyou.code.PlayList 9 | import com.clearpole.videoyou.databinding.PlayListNameItemBinding 10 | import com.clearpole.videoyou.utils.SubStringX.Companion.subStringX 11 | import com.drake.brv.BindingAdapter 12 | import com.drake.brv.item.ItemBind 13 | import org.json.JSONObject 14 | 15 | data class PlayListNameModel(val title: String, val time: String, val count: String) : ItemBind { 16 | override fun onBind(holder: BindingAdapter.BindingViewHolder) { 17 | val binding = PlayListNameItemBinding.bind(holder.itemView) 18 | try { 19 | val list = JSONObject(PlayList.readPlayListContent(title)!!) 20 | val key = list.toString().subStringX("\"", "\"") 21 | val uri = list.getString(key!!) 22 | 23 | binding.playListFilesTitle.text = title 24 | binding.webDavFilesPath.text = buildString { 25 | append(time) 26 | append(" · ") 27 | append(list.length()) 28 | } 29 | Glide.with(holder.context).load(uri).diskCacheStrategy(DiskCacheStrategy.RESOURCE) 30 | .transition( 31 | DrawableTransitionOptions.withCrossFade() 32 | ).into(binding.cover) 33 | binding.playListFilesRoot.setOnClickListener { 34 | val int = Intent(holder.context, PlayListActivity::class.java) 35 | int.putExtra("name", title) 36 | holder.context.startActivity(int) 37 | } 38 | }catch (e:Exception){ 39 | binding.playListFilesTitle.text = title 40 | binding.webDavFilesPath.text = buildString { 41 | append(time) 42 | append(" · ") 43 | append(0) 44 | } 45 | binding.playListFilesRoot.setOnClickListener { 46 | val int = Intent(holder.context, PlayListActivity::class.java) 47 | int.putExtra("name", title) 48 | holder.context.startActivity(int) 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/model/PlayerSideSheetModel.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("DEPRECATION") 2 | 3 | package com.clearpole.videoyou.model 4 | 5 | import android.annotation.SuppressLint 6 | import android.content.res.Resources 7 | import com.blankj.utilcode.util.ToastUtils 8 | import com.clearpole.videoyou.R 9 | import com.clearpole.videoyou.databinding.PlayListVideosItemBinding 10 | import com.clearpole.videoyou.objects.AppObjects 11 | import com.clearpole.videoyou.objects.VideoPlayObjects 12 | import com.clearpole.videoyou.objects.VideoPlayerObjects 13 | import com.drake.brv.BindingAdapter 14 | import com.drake.brv.item.ItemBind 15 | import com.drake.brv.utils.bindingAdapter 16 | import com.drake.brv.utils.mutable 17 | 18 | data class PlayerSideSheetModel( 19 | val path: String, 20 | val resources: Resources, 21 | val item:Int 22 | ) : ItemBind { 23 | @SuppressLint("ResourceAsColor", "UseCompatLoadingForDrawables") 24 | override fun onBind(holder: BindingAdapter.BindingViewHolder) { 25 | val binding = PlayListVideosItemBinding.bind(holder.itemView) 26 | val chose = when (AppObjects.theme) { 27 | 0 -> { 28 | resources.getColor(R.color.color3) 29 | } 30 | 31 | 1 -> { 32 | resources.getColor(R.color.hzt_theme_dark_primary) 33 | } 34 | 35 | 2 -> { 36 | resources.getColor(R.color.cxw_theme_dark_primary) 37 | } 38 | 39 | 3 -> { 40 | resources.getColor(R.color.szy_theme_dark_primary) 41 | } 42 | 43 | 4 -> { 44 | resources.getColor(R.color.xfy_theme_dark_primary) 45 | } 46 | 47 | else -> { 48 | resources.getColor(R.color.chose) 49 | } 50 | } 51 | if (item==holder.layoutPosition){ 52 | binding.title.setTextColor(chose) 53 | VideoPlayerObjects.chose = binding.title 54 | }else{ 55 | binding.title.setTextColor(android.graphics.Color.parseColor("#ffffff")) 56 | } 57 | binding.title.text = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf(".")) 58 | binding.title.maxLines = 3 59 | binding.title.textSize = 14f 60 | binding.root.setOnClickListener { 61 | if (item!=holder.layoutPosition) { 62 | VideoPlayerObjects.player.seekToDefaultPosition(holder.layoutPosition) 63 | VideoPlayerObjects.chose = binding.title 64 | } 65 | } 66 | binding.close.setOnClickListener { 67 | try { 68 | VideoPlayerObjects.player.removeMediaItem(holder.layoutPosition) 69 | VideoPlayerObjects.rv!!.mutable.removeAt(holder.layoutPosition) 70 | VideoPlayerObjects.rv!!.bindingAdapter.notifyItemRemoved(holder.layoutPosition) 71 | VideoPlayObjects.list.removeAt(holder.layoutPosition) 72 | if (VideoPlayerObjects.player.mediaItemCount==0){ 73 | ToastUtils.showLong("无播放项目") 74 | } 75 | }catch (_:Exception){ 76 | ToastUtils.showShort("删除失败,请重试") 77 | } 78 | false 79 | } 80 | 81 | } 82 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/model/SearchModel.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.model 2 | 3 | import android.content.Intent 4 | import android.net.Uri 5 | import com.blankj.utilcode.util.ActivityUtils 6 | import com.bumptech.glide.Glide 7 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions 8 | import com.clearpole.videoyou.VideoPlayerActivity 9 | import com.clearpole.videoyou.databinding.SearchItemBinding 10 | import com.clearpole.videoyou.objects.VideoPlayObjects 11 | import com.clearpole.videoyou.utils.GetVideoThumbnail 12 | import com.drake.brv.BindingAdapter 13 | import com.drake.brv.item.ItemBind 14 | import kotlinx.coroutines.CoroutineScope 15 | import kotlinx.coroutines.Dispatchers 16 | import kotlinx.coroutines.cancel 17 | import kotlinx.coroutines.launch 18 | import kotlinx.coroutines.withContext 19 | 20 | data class SearchModel( 21 | val title: String, 22 | val size: String, 23 | val uri: Uri, 24 | val path: String 25 | ) : 26 | ItemBind { 27 | override fun onBind(holder: BindingAdapter.BindingViewHolder) { 28 | val binding = holder.getBinding() 29 | binding.itemText.text = title 30 | binding.itemRoot.setOnClickListener { 31 | VideoPlayObjects.paths = path 32 | VideoPlayObjects.title = title 33 | VideoPlayObjects.type = "LOCAL" 34 | VideoPlayObjects.list = mutableListOf(path) 35 | val intent = Intent(holder.context, VideoPlayerActivity::class.java) 36 | ActivityUtils.startActivity(intent) 37 | } 38 | CoroutineScope(Dispatchers.IO).launch { 39 | val bitmap = 40 | GetVideoThumbnail.getVideoThumbnail(holder.context.contentResolver, uri) 41 | withContext(Dispatchers.Main) { 42 | Glide.with(holder.context) 43 | .load(bitmap) 44 | .transition(DrawableTransitionOptions.withCrossFade()) 45 | .into(binding.itemImg) 46 | } 47 | this.cancel() 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/model/SettingThemeModel.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.model 2 | 3 | import android.annotation.SuppressLint 4 | import com.blankj.utilcode.util.AppUtils 5 | import com.clearpole.videoyou.R 6 | import com.clearpole.videoyou.databinding.SettingThemeItemBinding 7 | import com.drake.brv.BindingAdapter 8 | import com.drake.brv.item.ItemBind 9 | import com.google.android.material.R.style.MaterialAlertDialog_Material3 10 | import com.google.android.material.dialog.MaterialAlertDialogBuilder 11 | import com.tencent.mmkv.MMKV 12 | 13 | data class SettingThemeModel(val name: String, val type: Int) : ItemBind { 14 | @SuppressLint("ResourceAsColor", "UseCompatLoadingForDrawables") 15 | override fun onBind(holder: BindingAdapter.BindingViewHolder) { 16 | val binding = holder.getBinding() 17 | binding.name.text = name 18 | val theme = MMKV.mmkvWithID("theme").decodeInt("theme") 19 | if (type == theme) { 20 | binding.cardView.isChecked = true 21 | } 22 | when (type) { 23 | 0 -> { 24 | binding.mainBack.background = holder.context.getDrawable(R.color.color1) 25 | binding.floating.background = holder.context.getDrawable(R.color.color4) 26 | } 27 | 28 | R.style.hzt -> { 29 | binding.mainBack.background = holder.context.getDrawable(R.color.hzt_theme_dark_primary) 30 | binding.floating.background = holder.context.getDrawable(R.color.hzt_theme_light_primary) 31 | } 32 | 33 | R.style.cxw -> { 34 | binding.mainBack.background = holder.context.getDrawable(R.color.cxw_theme_dark_primary) 35 | binding.floating.background = holder.context.getDrawable(R.color.cxw_theme_light_primary) 36 | } 37 | 38 | R.style.szy -> { 39 | binding.mainBack.background = holder.context.getDrawable(R.color.szy_theme_dark_primary) 40 | binding.floating.background = holder.context.getDrawable(R.color.szy_theme_light_primary) 41 | } 42 | 43 | R.style.xfy -> { 44 | binding.mainBack.background = holder.context.getDrawable(R.color.xfy_theme_dark_primary) 45 | binding.floating.background = holder.context.getDrawable(R.color.xfy_theme_light_primary) 46 | } 47 | } 48 | binding.cardView.setOnClickListener { 49 | if (theme != type) { 50 | MMKV.mmkvWithID("theme").encode("theme", type) 51 | MaterialAlertDialogBuilder(holder.context, MaterialAlertDialog_Material3) 52 | .setTitle(name) 53 | .setMessage("您已选择主题:$name,重启即可生效。") 54 | .setNegativeButton("重启") { _, _ -> 55 | AppUtils.relaunchApp() 56 | } 57 | .setCancelable(false) 58 | .show() 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/model/VideoInfoModel.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.model 2 | 3 | import com.blankj.utilcode.util.ClipboardUtils 4 | import com.clearpole.videoyou.databinding.VideoInfoItemBinding 5 | import com.drake.brv.BindingAdapter 6 | import com.drake.brv.item.ItemBind 7 | import com.google.android.material.dialog.MaterialAlertDialogBuilder 8 | 9 | data class VideoInfoModel(val title: String, val info: String) : ItemBind { 10 | override fun onBind(holder: BindingAdapter.BindingViewHolder) { 11 | val binding = holder.getBinding() 12 | binding.name.text = title 13 | binding.info.text = info 14 | binding.root.setOnClickListener { 15 | MaterialAlertDialogBuilder(holder.context).setTitle( 16 | title 17 | ).setMessage(info).setPositiveButton("复制") { _, _ -> 18 | ClipboardUtils.copyText(info) 19 | }.show() 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/model/VideoUtilsModel.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.model 2 | 3 | import android.graphics.drawable.Drawable 4 | import com.bumptech.glide.Glide 5 | import com.clearpole.videoyou.databinding.VideoInfoUtilsItemBinding 6 | import com.drake.brv.BindingAdapter 7 | import com.drake.brv.item.ItemBind 8 | 9 | data class VideoUtilsModel(val icon:Drawable,val name:String, val util:()->Unit):ItemBind { 10 | override fun onBind(holder: BindingAdapter.BindingViewHolder) { 11 | val binding = holder.getBinding() 12 | Glide.with(holder.context).load(icon).into(binding.icon) 13 | binding.name.text = name 14 | binding.root.setOnClickListener { 15 | util() 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/model/WebDavModel.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.model; 2 | 3 | import com.drake.brv.BindingAdapter 4 | import com.drake.brv.item.ItemBind 5 | import com.thegrizzlylabs.sardineandroid.DavResource 6 | 7 | data class WebDavModel( 8 | val title: DavResource 9 | ) : 10 | ItemBind { 11 | override fun onBind(holder: BindingAdapter.BindingViewHolder) { 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/objects/AppObjects.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.objects 2 | 3 | class AppObjects { 4 | companion object{ 5 | var theme = 0 6 | } 7 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/objects/MainObjects.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.objects 2 | 3 | import android.net.Uri 4 | import android.view.View 5 | import org.json.JSONObject 6 | 7 | class MainObjects { 8 | companion object{ 9 | var allSize : Long = 0 10 | var isChoose = false 11 | val chooseList = ArrayList() 12 | var count : Int = 0 13 | } 14 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/objects/VideoPlayObjects.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.objects 2 | 3 | import android.graphics.Bitmap 4 | import android.net.Uri 5 | import com.thegrizzlylabs.sardineandroid.DavResource 6 | import org.json.JSONObject 7 | 8 | class VideoPlayObjects { 9 | companion object { 10 | lateinit var type: String 11 | lateinit var paths: String 12 | lateinit var title: String 13 | lateinit var cover: Bitmap 14 | lateinit var uri: Uri 15 | var list = mutableListOf() 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/objects/VideoPlayerObjects.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.objects 2 | 3 | import android.annotation.SuppressLint 4 | import android.widget.TextView 5 | import androidx.constraintlayout.widget.ConstraintLayout 6 | import androidx.recyclerview.widget.RecyclerView 7 | import com.google.android.exoplayer2.ExoPlayer 8 | import com.google.android.material.slider.Slider 9 | 10 | class VideoPlayerObjects { 11 | companion object{ 12 | var videoWidth : Int = 0 13 | var videoHeight : Int = 0 14 | var isAutoFinish : Boolean = false 15 | var newItem : Int = 0 16 | var isSpeedMode : Boolean = false 17 | var isPauseMode : Boolean = false 18 | var isToolBarOpen : Boolean = false 19 | var isInFullScreen : Boolean = false 20 | var isIntoHome : Boolean = false 21 | var isCrash : Boolean = false 22 | var isMove : Boolean = false 23 | var fingerX : Long = 0L 24 | var slider : Slider? = null 25 | var pausing : Boolean = false 26 | var first : Boolean = true 27 | var speed : Float = 2f 28 | var playMode : Int = ExoPlayer.REPEAT_MODE_ALL 29 | @SuppressLint("StaticFieldLeak") 30 | var chose : TextView? = null 31 | var rv: RecyclerView? = null 32 | lateinit var player: ExoPlayer 33 | fun fix(){ 34 | videoWidth = 0 35 | videoHeight = 0 36 | isAutoFinish = false 37 | newItem = 0 38 | isSpeedMode = false 39 | isPauseMode = false 40 | isToolBarOpen = false 41 | isInFullScreen = false 42 | isIntoHome = false 43 | fingerX = 0L 44 | isCrash = true 45 | isMove = false 46 | slider = null 47 | first = true 48 | pausing = false 49 | chose = null 50 | rv = null 51 | speed = 2f 52 | playMode = ExoPlayer.REPEAT_MODE_ALL 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/utils/ByteToString.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.utils 2 | 3 | import java.text.DecimalFormat 4 | 5 | class ByteToString { 6 | companion object { 7 | fun byteToString(size: Long): String { 8 | val gB = (1024 * 1024 * 1024).toLong() 9 | val mB = (1024 * 1024).toLong() 10 | val kB: Long = 1024 11 | val df = DecimalFormat("0.00") 12 | val resultSize: String = if (size / gB >= 1) { 13 | df.format(size / gB.toFloat()) + " GB " 14 | } else if (size / mB >= 1) { 15 | df.format(size / mB.toFloat()) + " MB " 16 | } else if (size / kB >= 1) { 17 | df.format(size / kB.toFloat()) + " KB " 18 | } else { 19 | "$size B " 20 | } 21 | return resultSize 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/utils/DatabaseStorage.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.utils 2 | 3 | import android.content.ContentResolver 4 | import com.tencent.mmkv.MMKV 5 | import kotlinx.coroutines.CoroutineScope 6 | import kotlinx.coroutines.Dispatchers 7 | import kotlinx.coroutines.launch 8 | import org.json.JSONArray 9 | 10 | class DatabaseStorage { 11 | companion object { 12 | private val kv = MMKV.mmkvWithID("MediaStore") 13 | fun writeDataToData(list: JSONArray): Boolean { 14 | var isSuccess = false 15 | CoroutineScope(Dispatchers.IO).launch { 16 | for (index in 0 until list.length()) { 17 | isSuccess = kv.encode(index.toString(), list[index].toString()) 18 | } 19 | } 20 | return isSuccess 21 | } 22 | 23 | fun readDataByData(): JSONArray? = try { 24 | val kV = kv.allKeys() 25 | val array = JSONArray() 26 | for (index in kV!!.indices) { 27 | val jsonObject = kv.decodeString(kV[index]) 28 | array.put(jsonObject) 29 | } 30 | array 31 | } catch (e: Exception) { 32 | null 33 | } 34 | 35 | fun clearData(contentResolver: ContentResolver) { 36 | kv.clear() 37 | writeDataToData(ReadMediaStore.start(contentResolver)) 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/utils/DeleteVideo.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.utils 2 | 3 | import android.content.Context 4 | import android.provider.MediaStore 5 | import com.blankj.utilcode.util.ToastUtils 6 | import java.io.File 7 | 8 | 9 | public fun deleteVideo(file: File,context: Context) { 10 | if (file.isFile) { 11 | val filePath = file.path 12 | val res: Int = context.contentResolver.delete( 13 | MediaStore.Video.Media.EXTERNAL_CONTENT_URI, 14 | MediaStore.Audio.Media.DATA + "= \"" + filePath + "\"", 15 | null 16 | ) 17 | if (res > 0) { 18 | file.delete() 19 | } else { 20 | ToastUtils.showShort("删除失败") 21 | } 22 | return 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/utils/DepthFieldTransformer.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.utils 2 | 3 | import android.view.View 4 | import androidx.viewpager.widget.ViewPager 5 | import androidx.viewpager2.widget.ViewPager2 6 | import kotlin.math.abs 7 | 8 | private const val MIN_SCALE = 0.8f 9 | 10 | class DepthFieldTransformer : ViewPager2.PageTransformer, ViewPager.PageTransformer { 11 | override fun transformPage(page: View, position: Float) { 12 | page.apply { 13 | when { 14 | position < -1 -> { 15 | alpha = 1f - MIN_SCALE 16 | scaleX = MIN_SCALE 17 | scaleY = MIN_SCALE 18 | } 19 | position <= 1 -> { 20 | val absPos = abs(position) 21 | val scale = if (absPos > 1) 0F else 1 - absPos 22 | page.scaleX = MIN_SCALE + (1f - MIN_SCALE) * scale 23 | page.scaleY = MIN_SCALE + (1f - MIN_SCALE) * scale 24 | page.alpha = MIN_SCALE + (1f - MIN_SCALE) * scale 25 | } 26 | else -> { 27 | page.scaleX = 0f 28 | page.scaleY = 0f 29 | page.alpha = 0f 30 | } 31 | } 32 | } 33 | 34 | 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/utils/GetVideoThumbnail.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.utils 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.ContentResolver 5 | import android.graphics.Bitmap 6 | import android.graphics.BitmapFactory 7 | import android.net.Uri 8 | import android.provider.MediaStore 9 | 10 | 11 | class GetVideoThumbnail { 12 | companion object { 13 | @Suppress("DEPRECATION", "UNUSED_EXPRESSION") 14 | @SuppressLint("Range") 15 | fun getVideoThumbnail(cr: ContentResolver, uri: Uri?): Bitmap? { 16 | return try { 17 | var bitmap: Bitmap? 18 | val options = BitmapFactory.Options() 19 | options.inDither = false 20 | options.inPreferredConfig = Bitmap.Config.RGB_565 21 | val cursor = cr.query(uri!!, arrayOf(MediaStore.Video.Media._ID), null, null, null) 22 | if (cursor == null || cursor.count == 0) { 23 | null 24 | } 25 | cursor!!.moveToFirst() 26 | val videoId = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media._ID)) 27 | ?: null //image id in image table.s 28 | cursor.close() 29 | val videoIdLong = videoId!!.toLong() 30 | bitmap = MediaStore.Video.Thumbnails.getThumbnail( 31 | cr, videoIdLong, MediaStore.Images.Thumbnails.MINI_KIND, options 32 | ) 33 | bitmap 34 | } catch (e: Exception) { 35 | null 36 | } 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/utils/IsNightMode.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.utils 2 | 3 | import android.content.res.Configuration 4 | import android.content.res.Resources 5 | 6 | class IsNightMode { 7 | companion object{ 8 | fun isNightMode(resources: Resources): Boolean { 9 | return when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) { 10 | Configuration.UI_MODE_NIGHT_YES -> true 11 | else -> false 12 | } 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/utils/NoSwipeViewPager.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.utils 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.MotionEvent 6 | import androidx.viewpager.widget.ViewPager 7 | 8 | 9 | //禁止滑动的viewpager 10 | class NoSwipeViewPager(context: Context?, attributeSet: AttributeSet?) : 11 | ViewPager(context!!, attributeSet) { 12 | private var canSwipe = true 13 | 14 | //是否禁止滑动 15 | fun setCanSwipe(canSwipe: Boolean) { 16 | this.canSwipe = canSwipe 17 | } 18 | 19 | override fun onTouchEvent(ev: MotionEvent?): Boolean { 20 | return canSwipe && super.onTouchEvent(ev) 21 | } 22 | 23 | override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { 24 | return canSwipe && super.onInterceptTouchEvent(ev) 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/utils/ReadMediaStore.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.utils 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.ContentResolver 5 | import android.database.Cursor 6 | import android.net.Uri 7 | import android.provider.MediaStore 8 | import kotlinx.coroutines.Dispatchers 9 | import kotlinx.coroutines.withContext 10 | import org.json.JSONArray 11 | import org.json.JSONObject 12 | 13 | 14 | class ReadMediaStore { 15 | companion object { 16 | @SuppressLint("Recycle") 17 | fun start(contentResolver: ContentResolver): JSONArray { 18 | val cursor: Cursor = contentResolver.query( 19 | MediaStore.Video.Media.EXTERNAL_CONTENT_URI, null, null, null, null 20 | )!! 21 | val indexVideoId = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID) 22 | val indexVideoSize = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE) 23 | val indexVideoTitle = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.TITLE) 24 | val indexVideoPath = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA) 25 | val indexVideoFolder = 26 | cursor.getColumnIndexOrThrow(MediaStore.Video.Media.BUCKET_DISPLAY_NAME) 27 | cursor.moveToPosition(-1) 28 | val array = JSONArray() 29 | while (cursor.moveToNext()) { 30 | val title = cursor.getString(indexVideoTitle) 31 | val size = cursor.getString(indexVideoSize) 32 | val path = cursor.getString(indexVideoPath) 33 | val videoUri = Uri.withAppendedPath( 34 | MediaStore.Video.Media.EXTERNAL_CONTENT_URI, cursor.getString(indexVideoId) 35 | ) 36 | val folder = cursor.getString(indexVideoFolder) 37 | val itemJson = JSONObject() 38 | itemJson.put("title", title) 39 | itemJson.put("size", size) 40 | itemJson.put("path", path) 41 | itemJson.put("uri", videoUri.toString()) 42 | itemJson.put("folder", folder) 43 | array.put(itemJson) 44 | } 45 | cursor.close() 46 | return array 47 | } 48 | 49 | suspend fun getFolder(contentResolver: ContentResolver): ArrayList { 50 | val array = ArrayList() 51 | withContext(Dispatchers.IO) { 52 | try { 53 | val cursor: Cursor = contentResolver.query( 54 | MediaStore.Video.Media.EXTERNAL_CONTENT_URI, null, null, null, null 55 | )!! 56 | val indexVideoFolder = 57 | cursor.getColumnIndexOrThrow(MediaStore.Video.Media.BUCKET_DISPLAY_NAME) 58 | cursor.moveToPosition(-1) 59 | while (cursor.moveToNext()) { 60 | val folder = cursor.getString(indexVideoFolder)?:"根目录" 61 | if (!array.contains(folder)) { 62 | if (folder.isNotEmpty()) { 63 | array.add(folder) 64 | } 65 | } 66 | } 67 | cursor.close() 68 | } catch (e: Exception) { 69 | array.add("") 70 | withContext(Dispatchers.Main) { 71 | //ToastUtils.show("文件所属加载错误") 72 | } 73 | } 74 | } 75 | return array 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/utils/RefreshMediaStore.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.utils 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.media.MediaScannerConnection 6 | 7 | 8 | class RefreshMediaStore { 9 | companion object { 10 | @Suppress("DEPRECATION") 11 | fun updateMedia(context: Context, path: String) { 12 | MediaScannerConnection.scanFile( 13 | context, arrayOf(path), null 14 | ) { _, uri -> 15 | val mediaScanIntent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE) 16 | mediaScanIntent.data = uri 17 | context.sendBroadcast(mediaScanIntent) 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/utils/SeekBarAnim.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.utils 2 | 3 | import android.animation.ValueAnimator 4 | import com.google.android.material.slider.Slider 5 | 6 | class SeekBarAnim { 7 | companion object { 8 | fun progressAnim(progress: Float, view: Slider) { 9 | val lastProgress: String = view.value.toString() + "f" 10 | val dh = ValueAnimator.ofFloat(lastProgress.toFloat(), progress) 11 | dh.duration = java.lang.String.valueOf(500).toLong() 12 | dh.addUpdateListener { 13 | val nowAnimatedValue = dh.animatedValue as Float 14 | if (nowAnimatedValue == progress) { 15 | dh.cancel() 16 | } 17 | view.value = nowAnimatedValue 18 | } 19 | dh.start() 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/utils/SetBarTransparent.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.utils 2 | 3 | import android.app.Activity 4 | import android.content.res.Resources 5 | import android.widget.LinearLayout 6 | import com.gyf.immersionbar.ImmersionBar 7 | 8 | class SetBarTransparent { 9 | companion object { 10 | fun setBarTransparent(statusBarView: LinearLayout, activity: Activity,resources: Resources) { 11 | ImmersionBar.with(activity).transparentBar().statusBarDarkFont(!IsNightMode.isNightMode(resources)) 12 | .init() 13 | val statusBarHeight = ImmersionBar.getStatusBarHeight(activity) 14 | statusBarView.layoutParams.height = statusBarHeight 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/utils/SettingsItemsUntil.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.utils 2 | 3 | import com.tencent.mmkv.MMKV 4 | 5 | class SettingsItemsUntil { 6 | companion object { 7 | private val kV = MMKV.mmkvWithID("Setting")!! 8 | private val settings = arrayListOf( 9 | arrayListOf("darkMode", "0"), 10 | arrayListOf("isAutoPicture", "false"), 11 | arrayListOf("isDialogPlayer", "false"), 12 | arrayListOf("isScreenOn", "true"), 13 | arrayListOf("isAutoExit", "false") 14 | ) 15 | 16 | fun writeSettingData(key: String, value: String) { 17 | kV.encode(key, value) 18 | } 19 | 20 | fun readSettingData(key: String): String? { 21 | return kV.decodeString(key) 22 | } 23 | 24 | fun fixItems() { 25 | for (index in 0 until settings.size) { 26 | if (kV.decodeString(settings[index][0]).isNullOrEmpty()) { 27 | kV.encode(settings[index][0], settings[index][1]) 28 | } 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/utils/SubStringX.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.utils 2 | 3 | class SubStringX { 4 | companion object{ 5 | fun String.subStringX(beforeString: String?, afterString: String?): String? { 6 | return if (beforeString == null && afterString != null) { 7 | this.substring(0, this.indexOf(afterString)) 8 | } else if (beforeString != null && afterString == null) { 9 | this.substring(this.indexOf(beforeString) + beforeString.length, this.length) 10 | } else if (beforeString != null && afterString != null) { 11 | this.subStringX(beforeString, null)!!.subStringX(null, afterString) 12 | } else { 13 | null 14 | } 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/clearpole/videoyou/utils/TimeParse.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou.utils 2 | 3 | import kotlin.math.roundToInt 4 | 5 | class TimeParse { 6 | companion object { 7 | fun timeParse(duration: Long): String? { 8 | var time: String? = "" 9 | val minute = duration / 60000 10 | val seconds = duration % 60000 11 | val second = (seconds.toFloat() / 1000).roundToInt().toLong() 12 | if (minute < 10) { 13 | time += "0" 14 | } 15 | time += "$minute:" 16 | if (second < 10) { 17 | time += "0" 18 | } 19 | time += second 20 | return time!!.trim() 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/alpha_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/anim/alpha_1_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 13 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ripple.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_arrow_back_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_arrow_back_small.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_auto_fix_high_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_cached_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_check_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_checklist_rtl_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_chevron_right_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_code_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_delete_forever_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_explore_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_extension_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_folder_open_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_format_list_bulleted_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_fullscreen_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_fullscreen_exit_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_gesture_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_hearing_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_help_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_home_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_keyboard_arrow_down_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_keyboard_arrow_right_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_lock_open_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_map_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_mark_unread_chat_alt_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_menu_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_note_add_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_notifications_none_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_pause_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_picture_in_picture_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_play_arrow_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_playlist_add_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_playlist_add_check_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_refresh_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_screen_rotation_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_search_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_settings_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_skip_next_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_skip_previous_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_web_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_webhook_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_wifi_tethering_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 13 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_auto_fix_high_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_chat_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_delete_forever_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_exit_to_app_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_explore_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_file_copy_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_gesture_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_hearing_disabled_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_light_mode_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_lock_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_mode_night_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_monetization_on_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_speed_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/player_bottom_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/player_top_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/twotone_attach_file_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/twotone_drive_folder_upload_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/twotone_folder_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/video_player_toolbar_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_error_crash.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | 25 | 26 | 31 | 32 | 35 | 36 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 21 | 22 | 23 | 29 | 30 | 37 | 38 | 39 | 44 | 45 | 52 | 53 | 61 | 62 | 63 | 68 | 69 | 73 | 74 | 79 | 80 | 83 | 84 | 85 | 86 | 87 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_play_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 20 | 21 | 31 | 32 | 33 | 34 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 18 | 19 | 23 | 24 | 25 | 26 | 31 | 32 | 41 | 42 | 48 | 49 | 50 | 56 | 57 | 61 | 62 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_setting.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 21 | 22 | 31 | 32 | 33 | 34 | 38 | 39 | 43 | 44 | 48 | 52 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_web_dav.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 19 | 20 | 30 | 31 | 32 | 33 | 37 | 38 | 42 | 43 | 51 | 52 | 62 | 63 | 64 | 70 | 71 | 74 | 75 | 80 | 81 | 82 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /app/src/main/res/layout/app_is_activation.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/compose_videolist.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/compose_videoplayer.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/compose_videoslider.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/folder_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 24 | 25 | 29 | 30 | 33 | 38 | 45 | 46 | 47 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/layout/folder_list_tree_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 10 | 11 | 12 | 15 | 16 | 21 | 22 | 30 | 31 | 40 | 41 | 46 | 47 | 48 | 59 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /app/src/main/res/layout/main_drawer_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 14 | 22 | 31 | 32 | 40 | 47 | 51 | 57 | 63 | 68 | 69 | 75 | 81 | 86 | 87 | 88 | 89 | 97 | 103 | 109 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /app/src/main/res/layout/main_page_folder.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 17 | 18 | 22 | 23 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/main_page_mediastore.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 11 | 15 | 16 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/main_page_playlist.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 9 | 15 | 16 | 26 | 27 | 31 | 32 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/main_page_setting.xml: -------------------------------------------------------------------------------- 1 | 2 | s 7 | 12 | 16 | 23 | 29 | 36 | 37 | 45 | 46 | 47 | 54 | 58 | 59 | -------------------------------------------------------------------------------- /app/src/main/res/layout/main_page_setting_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 14 | 21 | 29 | 36 | 37 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/material_dialog_edit_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/material_dialog_edit_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 22 | 23 | 24 | 32 | 33 | 38 | 39 | 40 | 49 | 50 | 55 | 56 | 57 | 65 | 66 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /app/src/main/res/layout/media_store_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | 27 | 28 | 33 | 34 | 35 | 44 | 45 | 54 | 55 | 63 | 64 | 65 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /app/src/main/res/layout/play_list_name_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 23 | 28 | 29 | 30 | 40 | 41 | 49 | 50 | 59 | 60 | 61 | 70 | -------------------------------------------------------------------------------- /app/src/main/res/layout/play_list_videos_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 16 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/player_side_sheet.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/search_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 18 | 19 | 23 | 24 | 29 | 30 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/setting_about_do.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/setting_show.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/setting_theme.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 17 | 18 | 25 | 26 | 34 | 35 | 42 | 43 | 44 | 45 | 49 | 50 | 57 | 58 | 67 | 68 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /app/src/main/res/layout/setting_theme_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 20 | 21 | 30 | 31 | 36 | 37 | 38 | 42 | 43 | 51 | 52 | 60 | 61 | 62 | 63 | 64 | 70 | 71 | -------------------------------------------------------------------------------- /app/src/main/res/layout/video_info_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 19 | 20 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/video_info_utils_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/webdav_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 27 | 28 | 35 | 36 | 44 | 45 | 46 | 55 | -------------------------------------------------------------------------------- /app/src/main/res/menu/main_choose.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 13 | 18 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/menu/main_drawer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 13 | 17 | 18 | 19 | 20 | 21 | 25 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/menu/main_navigation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 13 | 18 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/menu/main_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/menu/playlist_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/menu/video_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/menu/webdav_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clearpole/VideoYou/ea93e09dee20d777dacd1942cca294e5aecf901c/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clearpole/VideoYou/ea93e09dee20d777dacd1942cca294e5aecf901c/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/twox.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clearpole/VideoYou/ea93e09dee20d777dacd1942cca294e5aecf901c/app/src/main/res/mipmap-hdpi/twox.gif -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clearpole/VideoYou/ea93e09dee20d777dacd1942cca294e5aecf901c/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clearpole/VideoYou/ea93e09dee20d777dacd1942cca294e5aecf901c/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clearpole/VideoYou/ea93e09dee20d777dacd1942cca294e5aecf901c/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clearpole/VideoYou/ea93e09dee20d777dacd1942cca294e5aecf901c/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clearpole/VideoYou/ea93e09dee20d777dacd1942cca294e5aecf901c/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clearpole/VideoYou/ea93e09dee20d777dacd1942cca294e5aecf901c/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clearpole/VideoYou/ea93e09dee20d777dacd1942cca294e5aecf901c/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clearpole/VideoYou/ea93e09dee20d777dacd1942cca294e5aecf901c/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | VideoYou 3 | 刷新媒体库 4 | 进入开发者调试 5 | 界面导航 6 | 主页 7 | 设置 8 | 功能 9 | 视频搜索 10 | 网络串流 11 | WebDav 12 | 已通知系统尝试刷新!\n这将需要数秒的时间\n请耐心等待... 13 | 本地没有播放列表 14 | 设置项目 15 | 更多 16 | 文件管理 17 | 隐私文件 18 | 播放时退出二次确认 19 | 在播放视频的时候退出会显示弹窗 20 | 深色模式 21 | 应用主题 22 | 崩溃了!\n我真的崩溃了! 23 | 离开播放器自动打开画中画 24 | 此功能仅限安卓9以上使用 25 | 播放界面常亮 26 | 播放界面屏幕永不自动熄灭 27 | 播放完毕自动退出 28 | 在播放完毕时自动退出 29 | 删除播放列表 30 | VideoPlayerActivity 31 | -------------------------------------------------------------------------------- /app/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /app/src/test/java/com/clearpole/videoyou/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.clearpole.videoyou 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | plugins { 3 | id 'com.android.application' version '8.1.0-alpha06' apply false 4 | id 'com.android.library' version '8.1.0-alpha06' apply false 5 | id 'org.jetbrains.kotlin.android' version '1.8.0' apply false 6 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Kotlin code style for this project: "official" or "obsolete": 19 | kotlin.code.style=official 20 | # Enables namespacing of each library's R class so that its R class includes only the 21 | # resources declared in the library itself and none from the library's dependencies, 22 | # thereby reducing the size of the R class for that library 23 | android.nonTransitiveRClass=true 24 | android.enableJetifier=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clearpole/VideoYou/ea93e09dee20d777dacd1942cca294e5aecf901c/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Jan 26 16:53:33 CST 2023 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | google() 5 | mavenLocal() 6 | mavenCentral() 7 | maven { url 'https://jitpack.io' } 8 | maven { url 'https://repo1.maven.org/maven2/' } 9 | maven { 10 | url 'https://repo.huaweicloud.com/repository/maven/' 11 | } 12 | } 13 | } 14 | dependencyResolutionManagement { 15 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 16 | repositories { 17 | gradlePluginPortal() 18 | google() 19 | mavenLocal() 20 | mavenCentral() 21 | maven { url 'https://jitpack.io' } 22 | maven { url 'https://repo1.maven.org/maven2/' } 23 | maven { 24 | url 'https://repo.huaweicloud.com/repository/maven/' 25 | } 26 | } 27 | } 28 | rootProject.name = "VideoYou - opt" 29 | include ':app' 30 | --------------------------------------------------------------------------------