V1.0(1)
15
.gitignore
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
*.iml
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/caches
|
||||||
|
/.idea/libraries
|
||||||
|
/.idea/modules.xml
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/navEditor.xml
|
||||||
|
/.idea/assetWizardSettings.xml
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
||||||
|
.externalNativeBuild
|
||||||
|
.cxx
|
||||||
|
local.properties
|
||||||
1
app/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
BIN
app/DynamicCartoonWallpaper.jks
Normal file
79
app/build.gradle.kts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import java.util.Date
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
val timestamp = SimpleDateFormat("MM_dd_HH_mm").format(Date())
|
||||||
|
plugins {
|
||||||
|
alias(libs.plugins.android.application)
|
||||||
|
alias(libs.plugins.kotlin.android)
|
||||||
|
id ("kotlin-parcelize")
|
||||||
|
id("io.objectbox")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "com.video.mobile.wallpaper"
|
||||||
|
compileSdk = 35
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId = "com.video.mobile.wallpaper"
|
||||||
|
minSdk = 24
|
||||||
|
targetSdk = 35
|
||||||
|
versionCode = 1
|
||||||
|
versionName = "1.0"
|
||||||
|
setProperty(
|
||||||
|
"archivesBaseName",
|
||||||
|
"Dynamic Cartoon Wallpaper_V" + versionName + "(${versionCode})_$timestamp"
|
||||||
|
)
|
||||||
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
isMinifyEnabled = true
|
||||||
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
"proguard-rules.pro"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "11"
|
||||||
|
}
|
||||||
|
buildFeatures{
|
||||||
|
viewBinding = true
|
||||||
|
buildConfig = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
implementation(libs.androidx.core.ktx)
|
||||||
|
implementation(libs.androidx.appcompat)
|
||||||
|
implementation(libs.material)
|
||||||
|
implementation(libs.androidx.activity)
|
||||||
|
implementation(libs.androidx.constraintlayout)
|
||||||
|
testImplementation(libs.junit)
|
||||||
|
androidTestImplementation(libs.androidx.junit)
|
||||||
|
androidTestImplementation(libs.androidx.espresso.core)
|
||||||
|
|
||||||
|
|
||||||
|
implementation ("androidx.paging:paging-runtime-ktx:3.3.6")
|
||||||
|
|
||||||
|
implementation ("com.google.code.gson:gson:2.12.1")
|
||||||
|
implementation("com.github.bumptech.glide:glide:4.16.0")
|
||||||
|
|
||||||
|
// ViewModel + LiveData KTX
|
||||||
|
// implementation ("androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.2")
|
||||||
|
// implementation ("androidx.lifecycle:lifecycle-livedata-ktx:2.9.2")
|
||||||
|
// Fragment KTX(提供 viewModels 扩展)
|
||||||
|
implementation ("androidx.fragment:fragment-ktx:1.8.9")
|
||||||
|
|
||||||
|
implementation("androidx.media3:media3-exoplayer:1.8.0")
|
||||||
|
implementation ("androidx.media3:media3-ui:1.8.0")
|
||||||
|
|
||||||
|
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||||
|
implementation("com.squareup.retrofit2:adapter-rxjava2:2.9.0")
|
||||||
|
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
|
||||||
|
}
|
||||||
116
app/objectbox-models/default.json
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
{
|
||||||
|
"_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.",
|
||||||
|
"_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.",
|
||||||
|
"_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"id": "1:5861365936442707683",
|
||||||
|
"lastPropertyId": "6:8474641495170349359",
|
||||||
|
"name": "LikeWallpaper",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "1:1896367441224580523",
|
||||||
|
"name": "objectId",
|
||||||
|
"type": 6,
|
||||||
|
"flags": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2:518404838438816658",
|
||||||
|
"name": "description",
|
||||||
|
"type": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3:8610300359262444087",
|
||||||
|
"name": "id",
|
||||||
|
"type": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4:1799690089661510919",
|
||||||
|
"name": "image",
|
||||||
|
"type": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5:3735709230659931937",
|
||||||
|
"name": "wallpapertype",
|
||||||
|
"type": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6:8474641495170349359",
|
||||||
|
"name": "thumbnail",
|
||||||
|
"type": 9
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"relations": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2:7214743200838441355",
|
||||||
|
"lastPropertyId": "10:5928432456802213941",
|
||||||
|
"name": "VideoWallpaper",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "1:8404628459774998577",
|
||||||
|
"name": "objectId",
|
||||||
|
"type": 6,
|
||||||
|
"flags": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2:2199034792582915578",
|
||||||
|
"name": "category",
|
||||||
|
"type": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3:8906378192469633251",
|
||||||
|
"name": "description",
|
||||||
|
"type": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4:4298057389705852700",
|
||||||
|
"name": "downloads",
|
||||||
|
"type": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5:5956110026349494870",
|
||||||
|
"name": "id",
|
||||||
|
"type": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6:6267621209200928594",
|
||||||
|
"name": "image",
|
||||||
|
"type": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "7:8054649528453649863",
|
||||||
|
"name": "pro",
|
||||||
|
"type": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8:6813789647380825500",
|
||||||
|
"name": "resolution",
|
||||||
|
"type": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9:3370332525900065977",
|
||||||
|
"name": "thumbnail",
|
||||||
|
"type": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "10:5928432456802213941",
|
||||||
|
"name": "wallpapertype",
|
||||||
|
"type": 6
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"relations": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lastEntityId": "2:7214743200838441355",
|
||||||
|
"lastIndexId": "0:0",
|
||||||
|
"lastRelationId": "0:0",
|
||||||
|
"lastSequenceId": "0:0",
|
||||||
|
"modelVersion": 5,
|
||||||
|
"modelVersionParserMinimum": 5,
|
||||||
|
"retiredEntityUids": [],
|
||||||
|
"retiredIndexUids": [],
|
||||||
|
"retiredPropertyUids": [],
|
||||||
|
"retiredRelationUids": [],
|
||||||
|
"version": 1
|
||||||
|
}
|
||||||
194
app/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
||||||
|
|
||||||
|
|
||||||
|
# 保持 Gson 和 TypeToken 不被混淆
|
||||||
|
-keep class com.google.gson.** { *; }
|
||||||
|
-keep class com.google.gson.reflect.TypeToken { *; }
|
||||||
|
|
||||||
|
# 保留与泛型相关的 TypeToken 使用,避免泛型信息丢失
|
||||||
|
-keep class * extends com.google.gson.reflect.TypeToken { *; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 保持 Gson 序列化相关的字段不被混淆
|
||||||
|
-keepclassmembers class * {
|
||||||
|
@com.google.gson.annotations.SerializedName <fields>;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 保持 Gson 构造方法不被混淆
|
||||||
|
-keepclassmembers class com.google.gson.Gson {
|
||||||
|
public <init>(...);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#-------------------------Gson
|
||||||
|
# Gson 反射需要保留字段名
|
||||||
|
-keep class com.google.gson.stream.** { *; }
|
||||||
|
-keepattributes Signature
|
||||||
|
-keepattributes *Annotation*
|
||||||
|
|
||||||
|
# 保留实体类字段(根据需要,你可以只针对自己的 model 包)
|
||||||
|
-keepclassmembers class com.video.mobile.wallpaper.database.VideoWallpaper {
|
||||||
|
<fields>;
|
||||||
|
}
|
||||||
|
#-------------------------Gson
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#-------------------------Serializable
|
||||||
|
-keepclassmembers class * implements java.io.Serializable {
|
||||||
|
static final long serialVersionUID;
|
||||||
|
private static final java.io.ObjectStreamField[] serialPersistentFields;
|
||||||
|
private void writeObject(java.io.ObjectOutputStream);
|
||||||
|
private void readObject(java.io.ObjectInputStream);
|
||||||
|
java.lang.Object writeReplace();
|
||||||
|
java.lang.Object readResolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
-keep class com.video.mobile.wallpaper.database.VideoWallpaper implements java.io.Serializable { *; }
|
||||||
|
-keep class com.video.mobile.wallpaper.database.LikeWallpaper implements java.io.Serializable { *; }
|
||||||
|
|
||||||
|
#-------------------------Serializable
|
||||||
|
|
||||||
|
|
||||||
|
#-------------------------Glide
|
||||||
|
# Glide v4 混淆规则
|
||||||
|
-keep public class * implements com.bumptech.glide.module.GlideModule
|
||||||
|
-keep public class * extends com.bumptech.glide.AppGlideModule
|
||||||
|
-keep class com.bumptech.glide.GeneratedAppGlideModuleImpl { *; }
|
||||||
|
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** { **[] $VALUES; public *; }
|
||||||
|
|
||||||
|
#-------------------------Glide
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Retrofit
|
||||||
|
-dontwarn retrofit2.**
|
||||||
|
-keep class retrofit2.** { *; }
|
||||||
|
-keepattributes Signature
|
||||||
|
-keepattributes Exceptions
|
||||||
|
|
||||||
|
# OkHttp
|
||||||
|
-dontwarn okhttp3.**
|
||||||
|
-keep class okhttp3.** { *; }
|
||||||
|
|
||||||
|
# RxJava(如果用 RxJava2)
|
||||||
|
-dontwarn io.reactivex.**
|
||||||
|
|
||||||
|
|
||||||
|
-keep class androidx.media3.** { *; }
|
||||||
|
-dontwarn androidx.media3.**
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 保留 Retrofit 接口
|
||||||
|
-keep interface com.video.mobile.wallpaper.network.VideoApi { *; }
|
||||||
|
-keep class com.video.mobile.wallpaper.database.LikeWallpaper { *; }
|
||||||
|
-keep class com.video.mobile.wallpaper.database.VideoWallpaper { *; }
|
||||||
|
|
||||||
|
|
||||||
|
# 保留 Retrofit 的所有类
|
||||||
|
-keep class retrofit2.** { *; }
|
||||||
|
|
||||||
|
# 保留 RxJava2 的所有类
|
||||||
|
-keep class io.reactivex.** { *; }
|
||||||
|
|
||||||
|
# 保留 CallAdapter 和 Converter 相关类
|
||||||
|
-keep class retrofit2.adapter.** { *; }
|
||||||
|
-keep class retrofit2.converter.** { *; }
|
||||||
|
|
||||||
|
# 保留类型 Token、类型适配器等相关类
|
||||||
|
-keepclassmembers class * {
|
||||||
|
@retrofit2.http.* <methods>;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 保留 Retrofit 和 OkHttp 的类和构造方法
|
||||||
|
-keep class retrofit2.** { *; }
|
||||||
|
-keep class okhttp3.** { *; }
|
||||||
|
|
||||||
|
# 保留 Retrofit 接口和方法
|
||||||
|
-keep class retrofit2.Retrofit { *; }
|
||||||
|
-keep class retrofit2.Call { *; }
|
||||||
|
-keep class retrofit2.http.** { *; }
|
||||||
|
|
||||||
|
# 保留所有使用 Retrofit 注解的字段、方法和类
|
||||||
|
-keepclassmembers class * {
|
||||||
|
@retrofit2.http.* <methods>;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 保留 Converter 和 CallAdapter 相关类
|
||||||
|
-keep class retrofit2.converter.** { *; }
|
||||||
|
-keep class retrofit2.adapter.** { *; }
|
||||||
|
|
||||||
|
# 保留 `@GET`, `@POST` 等注解
|
||||||
|
-keepclassmembers class * {
|
||||||
|
@retrofit2.http.GET <methods>;
|
||||||
|
@retrofit2.http.POST <methods>;
|
||||||
|
@retrofit2.http.PUT <methods>;
|
||||||
|
@retrofit2.http.DELETE <methods>;
|
||||||
|
@retrofit2.http.PATCH <methods>;
|
||||||
|
@retrofit2.http.Headers <methods>;
|
||||||
|
@retrofit2.http.Query <methods>;
|
||||||
|
@retrofit2.http.Body <methods>;
|
||||||
|
@retrofit2.http.Path <methods>;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 保留 OkHttp 相关类
|
||||||
|
-keep class okhttp3.Request { *; }
|
||||||
|
-keep class okhttp3.Response { *; }
|
||||||
|
-keep class okhttp3.OkHttpClient { *; }
|
||||||
|
|
||||||
|
# 保留 OkHttp 相关的拦截器
|
||||||
|
-keep class okhttp3.Interceptor { *; }
|
||||||
|
-keep class okhttp3.logging.HttpLoggingInterceptor { *; }
|
||||||
|
|
||||||
|
# 保留 OkHttp 的构造方法
|
||||||
|
-keepclassmembers class okhttp3.** {
|
||||||
|
public <init>(...);
|
||||||
|
}
|
||||||
|
|
||||||
|
# 保留 OkHttpClient 的链式构建方式
|
||||||
|
-keepclassmembers class okhttp3.OkHttpClient {
|
||||||
|
public okhttp3.OkHttpClient$Builder newBuilder(...);
|
||||||
|
}
|
||||||
|
|
||||||
|
# 保留 HttpLoggingInterceptor 相关类
|
||||||
|
-keep class okhttp3.logging.HttpLoggingInterceptor { *; }
|
||||||
|
|
||||||
|
# 保留 Call 和 Request 方法
|
||||||
|
-keepclassmembers class okhttp3.Call {
|
||||||
|
public *;
|
||||||
|
}
|
||||||
|
-keepclassmembers class okhttp3.Request {
|
||||||
|
public *;
|
||||||
|
}
|
||||||
|
-keepclassmembers class okhttp3.Response {
|
||||||
|
public *;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package com.video.mobile.wallpaper
|
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
import org.junit.Assert.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* See [testing documentation](http://d.android.com/tools/testing).
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class ExampleInstrumentedTest {
|
||||||
|
@Test
|
||||||
|
fun useAppContext() {
|
||||||
|
// Context of the app under test.
|
||||||
|
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
assertEquals("com.video.mobile.wallpaper", appContext.packageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
65
app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.SET_WALLPAPER" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.BIND_WALLPAPER"
|
||||||
|
tools:ignore="ProtectedPermissions" />
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:name=".App"
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
|
android:icon="@mipmap/logo"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:roundIcon="@mipmap/logo"
|
||||||
|
android:supportsRtl="true"
|
||||||
|
android:theme="@style/Theme.DynamicCartoonWallpaper"
|
||||||
|
tools:targetApi="31">
|
||||||
|
<activity
|
||||||
|
android:name=".favorite.FavoriteActivity"
|
||||||
|
android:exported="false" />
|
||||||
|
<activity
|
||||||
|
android:name=".preview.DisplayVideoActivity"
|
||||||
|
android:exported="false" />
|
||||||
|
<activity
|
||||||
|
android:name=".SplashActivity"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".main.MainActivity"
|
||||||
|
android:screenOrientation="portrait" />
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".preview.VideoWallpaperService"
|
||||||
|
android:exported="true"
|
||||||
|
android:permission="android.permission.BIND_WALLPAPER">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.service.wallpaper.WallpaperService" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="android.service.wallpaper"
|
||||||
|
android:resource="@xml/video_wallpaper" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/file_paths" />
|
||||||
|
</provider>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
4832
app/src/main/assets/Explore.json
Normal file
1037
app/src/main/assets/Shift.json
Normal file
4834
app/src/main/assets/Trending.json
Normal file
19
app/src/main/java/com/video/mobile/wallpaper/App.kt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package com.video.mobile.wallpaper
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import com.video.mobile.wallpaper.database.DataBaseManager
|
||||||
|
|
||||||
|
class App : Application(){
|
||||||
|
companion object{
|
||||||
|
val TAG = "============"
|
||||||
|
lateinit var mApp :App
|
||||||
|
}
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
mApp = this
|
||||||
|
DataBaseManager.init(this)
|
||||||
|
Helper.loadJson(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package com.video.mobile.wallpaper
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.viewbinding.ViewBinding
|
||||||
|
|
||||||
|
|
||||||
|
class BaseViewHolder<T : ViewBinding>(
|
||||||
|
itemVb: T
|
||||||
|
) : RecyclerView.ViewHolder(itemVb.root)
|
||||||
185
app/src/main/java/com/video/mobile/wallpaper/Helper.kt
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
package com.video.mobile.wallpaper
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Parcelable
|
||||||
|
import android.util.Log
|
||||||
|
import android.widget.Toast
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
import com.video.mobile.wallpaper.database.DataBaseManager
|
||||||
|
import com.video.mobile.wallpaper.database.VideoWallpaper
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
import java.io.BufferedReader
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.InputStreamReader
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.io.Reader
|
||||||
|
import java.io.StringWriter
|
||||||
|
import java.lang.reflect.Type
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
|
object Helper {
|
||||||
|
|
||||||
|
val thumbnailStr: String = "https://neutrolabgames.com/LiveLoop/CpanelPix/VideoThumb/"
|
||||||
|
fun showMyLog(message: String) {
|
||||||
|
Log.d(App.TAG, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadJson(context: Context) {
|
||||||
|
val name = arrayOf("Trending.json", "Explore.json", "Shift.json")
|
||||||
|
val cachedThreadPool = Executors.newFixedThreadPool(3)
|
||||||
|
for (i in 0..2) {
|
||||||
|
val task = i
|
||||||
|
cachedThreadPool.execute {
|
||||||
|
val gson: Gson = Gson()
|
||||||
|
var open = context.assets.open(name[task])
|
||||||
|
|
||||||
|
val type: Type =
|
||||||
|
object : TypeToken<List<VideoWallpaper?>?>() {
|
||||||
|
}.type
|
||||||
|
val covertStr: String = getJsonStr(open)
|
||||||
|
val data: List<VideoWallpaper> =
|
||||||
|
gson.fromJson(covertStr, type)
|
||||||
|
for (wallpaper in data) {
|
||||||
|
DataBaseManager.insertDb(wallpaper)
|
||||||
|
}
|
||||||
|
// Shared.INSTANCE.setDbinit("1")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showToast(context: Context,message: String){
|
||||||
|
Toast.makeText(context,message, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getJsonStr(stream: InputStream): String {
|
||||||
|
var covertStr = ""
|
||||||
|
try {
|
||||||
|
val writer = StringWriter()
|
||||||
|
val buffer = CharArray(stream.available())
|
||||||
|
val reader: Reader = BufferedReader(InputStreamReader(stream, StandardCharsets.UTF_8))
|
||||||
|
var a = 0
|
||||||
|
while ((reader.read(buffer).also { a = it }) != -1) {
|
||||||
|
writer.write(buffer, 0, a)
|
||||||
|
}
|
||||||
|
covertStr = writer.toString()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
return covertStr
|
||||||
|
}
|
||||||
|
return covertStr
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
inline fun <reified T : java.io.Serializable> Intent.getSerializableExtraCompat(key: String): T? {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
getSerializableExtra(key, T::class.java)
|
||||||
|
} else {
|
||||||
|
getSerializableExtra(key) as? T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun writeFile(input: InputStream, filePath: String): Boolean {
|
||||||
|
try {
|
||||||
|
val byteArray = ByteArray(4096)
|
||||||
|
val output = ByteArrayOutputStream()
|
||||||
|
var bytesRead: Int
|
||||||
|
while ((input.read(byteArray).also { bytesRead = it }) != -1) {
|
||||||
|
output.write(byteArray, 0, bytesRead)
|
||||||
|
}
|
||||||
|
|
||||||
|
val file = File(filePath)
|
||||||
|
if (!file.exists()) {
|
||||||
|
file.createNewFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
val fileOutputStream = FileOutputStream(filePath)
|
||||||
|
fileOutputStream.write(output.toByteArray())
|
||||||
|
output.close()
|
||||||
|
fileOutputStream.close()
|
||||||
|
return true
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
showMyLog("---------ex=${ex.message}" )
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun writeResponseBodyToDisk(body: ResponseBody, filePath: String): Boolean {
|
||||||
|
return try {
|
||||||
|
val file = File(filePath)
|
||||||
|
var inputStream: InputStream? = null
|
||||||
|
var outputStream: OutputStream? = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
val buffer = ByteArray(8 * 1024)
|
||||||
|
var bytesRead: Int
|
||||||
|
inputStream = body.byteStream()
|
||||||
|
outputStream = FileOutputStream(file)
|
||||||
|
|
||||||
|
var totalBytes: Long = 0
|
||||||
|
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
|
||||||
|
outputStream.write(buffer, 0, bytesRead)
|
||||||
|
totalBytes += bytesRead
|
||||||
|
}
|
||||||
|
outputStream.flush()
|
||||||
|
|
||||||
|
showMyLog("downloaded=$totalBytes contentType = ${body.contentType()}")
|
||||||
|
val bytes = body.bytes()
|
||||||
|
showMyLog("bytes = ${String(bytes.take(100).toByteArray())}")
|
||||||
|
|
||||||
|
// 这里不能用 contentLength,因为 chunked = -1
|
||||||
|
totalBytes > 0
|
||||||
|
} finally {
|
||||||
|
inputStream?.close()
|
||||||
|
outputStream?.close()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fun writeResponseBodyToDisk(body: ResponseBody, filePath: String): Boolean {
|
||||||
|
// return try {
|
||||||
|
// val file = File(filePath)
|
||||||
|
// var inputStream: InputStream? = null
|
||||||
|
// var outputStream: OutputStream? = null
|
||||||
|
//
|
||||||
|
// try {
|
||||||
|
// val buffer = ByteArray(8 * 1024)
|
||||||
|
// var bytesRead: Int
|
||||||
|
// inputStream = body.byteStream()
|
||||||
|
// outputStream = FileOutputStream(file)
|
||||||
|
//
|
||||||
|
// while (inputStream.read(buffer).also { bytesRead = it } != -1) {
|
||||||
|
// outputStream.write(buffer, 0, bytesRead)
|
||||||
|
// }
|
||||||
|
// outputStream.flush()
|
||||||
|
//
|
||||||
|
// // ✅ 校验完整性
|
||||||
|
// val downloaded = file.length()
|
||||||
|
// val expected = body.contentLength()
|
||||||
|
// showMyLog("downloaded=$downloaded , expected=$expected")
|
||||||
|
//
|
||||||
|
// downloaded == expected || expected == -1L
|
||||||
|
// } finally {
|
||||||
|
// inputStream?.close()
|
||||||
|
// outputStream?.close()
|
||||||
|
// }
|
||||||
|
// } catch (e: Exception) {
|
||||||
|
// e.printStackTrace()
|
||||||
|
// false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
package com.video.mobile.wallpaper
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.CountDownTimer
|
||||||
|
import android.widget.ProgressBar
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import com.video.mobile.wallpaper.main.MainActivity
|
||||||
|
|
||||||
|
|
||||||
|
class SplashActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private var countDownTimer: CountDownTimer? = null
|
||||||
|
private val timer = 2000L
|
||||||
|
|
||||||
|
private lateinit var progressBar: ProgressBar
|
||||||
|
private lateinit var textProgress: TextView
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
// installSplashScreen()
|
||||||
|
// }
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enableEdgeToEdge()
|
||||||
|
setContentView(R.layout.activity_splash)
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||||
|
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
|
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||||
|
insets
|
||||||
|
}
|
||||||
|
progressBar = findViewById(R.id.progress_bar)
|
||||||
|
textProgress = findViewById(R.id.textview_progress)
|
||||||
|
countDownTimer = object : CountDownTimer(timer, 100) {
|
||||||
|
override fun onTick(millisUntilFinished: Long) {
|
||||||
|
val v: Float =
|
||||||
|
100 - millisUntilFinished.toFloat() / timer * 100
|
||||||
|
val v1 = v.toInt()
|
||||||
|
progressBar.progress = v1
|
||||||
|
textProgress.text = getString(R.string.splash_progress_text, v1)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFinish() {
|
||||||
|
launchMain()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
countDownTimer?.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun launchMain() {
|
||||||
|
val max = 100
|
||||||
|
textProgress.text = getString(R.string.splash_progress_text, max)
|
||||||
|
progressBar.progress = max
|
||||||
|
startActivity(Intent(this@SplashActivity, MainActivity::class.java))
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,143 @@
|
|||||||
|
package com.video.mobile.wallpaper.database
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.video.mobile.wallpaper.BuildConfig
|
||||||
|
import com.video.mobile.wallpaper.Helper
|
||||||
|
import io.objectbox.Box
|
||||||
|
import io.objectbox.BoxStore
|
||||||
|
import io.objectbox.android.AndroidScheduler
|
||||||
|
import io.objectbox.config.DebugFlags
|
||||||
|
import io.objectbox.query.Query
|
||||||
|
import io.objectbox.reactive.DataSubscription
|
||||||
|
import io.objectbox.reactive.DataSubscriptionList
|
||||||
|
|
||||||
|
object DataBaseManager {
|
||||||
|
val pageSize = 10
|
||||||
|
|
||||||
|
var boxStore: BoxStore? = null
|
||||||
|
|
||||||
|
|
||||||
|
var videoWallpaperBox: Box<VideoWallpaper>? = null
|
||||||
|
|
||||||
|
var likeWallpaperBox: Box<LikeWallpaper>? = null
|
||||||
|
|
||||||
|
|
||||||
|
val observer: DataSubscription? = null
|
||||||
|
|
||||||
|
|
||||||
|
fun init(context: Context?) {
|
||||||
|
boxStore = MyObjectBox.builder().androidContext(context)
|
||||||
|
.debugFlags(DebugFlags.LOG_QUERIES or DebugFlags.LOG_QUERY_PARAMETERS)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDataBox(): Box<VideoWallpaper>? {
|
||||||
|
videoWallpaperBox = videoWallpaperBox ?: boxStore?.boxFor<VideoWallpaper>(VideoWallpaper::class.java)
|
||||||
|
|
||||||
|
return videoWallpaperBox
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLikeBox(): Box<LikeWallpaper>? {
|
||||||
|
likeWallpaperBox = likeWallpaperBox ?: boxStore?.boxFor<LikeWallpaper>(LikeWallpaper::class.java)
|
||||||
|
return likeWallpaperBox
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setLikeUpdateListener(queryAllLike:(List<LikeWallpaper>)->Unit): DataSubscription {
|
||||||
|
val likeBox: Box<LikeWallpaper>? = getLikeBox()
|
||||||
|
val build: Query<LikeWallpaper> = likeBox!!.query()
|
||||||
|
.build()
|
||||||
|
return build.subscribe(DataSubscriptionList())
|
||||||
|
.on(AndroidScheduler.mainThread())
|
||||||
|
.observer { data ->
|
||||||
|
Helper.showMyLog("---OnLikeUpdateListener-------------" + data.size)
|
||||||
|
queryAllLike(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun insertDb(resultData: VideoWallpaper) {
|
||||||
|
val objectBox: Box<VideoWallpaper>? = getDataBox()
|
||||||
|
val first: VideoWallpaper? = objectBox!!.query()
|
||||||
|
.equal(VideoWallpaper_.wallpapertype, resultData.wallpapertype)
|
||||||
|
.equal(VideoWallpaper_.id, resultData.id)
|
||||||
|
.build()
|
||||||
|
.findFirst()
|
||||||
|
if (first == null) {
|
||||||
|
// Common.logMsg("---insertDb------Wallpapertype------" + resultData.getWallpapertype() + "-------id=" + resultData.getId());
|
||||||
|
Helper.showMyLog("--------insertDb ${resultData.wallpapertype} + ${resultData.id}")
|
||||||
|
objectBox.put(resultData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun insertLike(favoriteData: LikeWallpaper) {
|
||||||
|
val likeBox: Box<LikeWallpaper>? = getLikeBox()
|
||||||
|
val first: LikeWallpaper? = likeBox!!.query()
|
||||||
|
.equal(LikeWallpaper_.id, favoriteData.id)
|
||||||
|
.build()
|
||||||
|
.findFirst()
|
||||||
|
if (first == null) {
|
||||||
|
Helper.showMyLog("---insertLike-----------------id=" + favoriteData.id)
|
||||||
|
likeBox.put(favoriteData)
|
||||||
|
} else {
|
||||||
|
Helper.showMyLog("---insertLike-----------------id=" + favoriteData.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun deleteLike(id: Long,deleteResult:(b: Boolean)-> Unit) {
|
||||||
|
val likeBox: Box<LikeWallpaper>? = getLikeBox()
|
||||||
|
val first: LikeWallpaper? = likeBox!!.query()
|
||||||
|
.equal(LikeWallpaper_.id, id)
|
||||||
|
.build()
|
||||||
|
.findFirst()
|
||||||
|
if (first != null) {
|
||||||
|
val remove = likeBox.remove(first.objectId)
|
||||||
|
deleteResult(remove)
|
||||||
|
Helper.showMyLog("---deleteLike-----------------id=$id")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun queryIsLike(id: Long): Boolean {
|
||||||
|
val likeBox: Box<LikeWallpaper>? = getLikeBox()
|
||||||
|
val first: LikeWallpaper? = likeBox!!.query()
|
||||||
|
.equal(LikeWallpaper_.id, id)
|
||||||
|
.build()
|
||||||
|
.findFirst()
|
||||||
|
return first != null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fun queryData(wallpaperType: Long, currentPage: Int): List<VideoWallpaper> {
|
||||||
|
val offset: Int = (currentPage - 1) * pageSize
|
||||||
|
|
||||||
|
val objectBoxLike: Box<VideoWallpaper>? = getDataBox()
|
||||||
|
val data: List<VideoWallpaper> = objectBoxLike!!.query()
|
||||||
|
.equal(VideoWallpaper_.wallpapertype, wallpaperType)
|
||||||
|
.build()
|
||||||
|
.find(offset.toLong(), pageSize.toLong())
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
fun queryLike(currentPage: Int): List<LikeWallpaper> {
|
||||||
|
val offset: Int = (currentPage - 1) * pageSize
|
||||||
|
val likeBox: Box<LikeWallpaper>? = getLikeBox()
|
||||||
|
val data: List<LikeWallpaper> = likeBox!!.query()
|
||||||
|
.build()
|
||||||
|
.find(offset.toLong(), pageSize.toLong())
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
fun queryAllData(wallpaperType: Long): List<VideoWallpaper> {
|
||||||
|
val objectBoxLike: Box<VideoWallpaper>? = getDataBox()
|
||||||
|
val data: List<VideoWallpaper> = objectBoxLike!!.query()
|
||||||
|
.equal(VideoWallpaper_.wallpapertype, wallpaperType)
|
||||||
|
.build()
|
||||||
|
.find()
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package com.video.mobile.wallpaper.database
|
||||||
|
|
||||||
|
import io.objectbox.annotation.Entity
|
||||||
|
import io.objectbox.annotation.Id
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
data class LikeWallpaper(
|
||||||
|
|
||||||
|
@Id
|
||||||
|
var objectId: Long = 0,
|
||||||
|
var description: String? = null,
|
||||||
|
|
||||||
|
var id: Long = 0,
|
||||||
|
|
||||||
|
var image: String? = null,
|
||||||
|
|
||||||
|
//0 :trending 1:dnamic 2:shift 3:explore
|
||||||
|
var wallpapertype: Long = 0,
|
||||||
|
|
||||||
|
var thumbnail: String? = null
|
||||||
|
) : Serializable
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package com.video.mobile.wallpaper.database
|
||||||
|
|
||||||
|
import io.objectbox.annotation.Entity
|
||||||
|
import io.objectbox.annotation.Id
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
data class VideoWallpaper(
|
||||||
|
@Id
|
||||||
|
var objectId: Long = 0,
|
||||||
|
var category: String? = null,
|
||||||
|
|
||||||
|
var description: String? = null,
|
||||||
|
|
||||||
|
var downloads: String? = null,
|
||||||
|
var id: Long = 0,
|
||||||
|
var image: String? = null,
|
||||||
|
var pro: Int = 0,
|
||||||
|
var resolution: String? = null,
|
||||||
|
var thumbnail: String? = null,
|
||||||
|
//0 :trending 1:dnamic 2:shift 3:explore
|
||||||
|
var wallpapertype: Long = 0
|
||||||
|
): Serializable
|
||||||
@ -0,0 +1,124 @@
|
|||||||
|
package com.video.mobile.wallpaper.favorite
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.paging.Pager
|
||||||
|
import androidx.paging.PagingConfig
|
||||||
|
import androidx.paging.PagingData
|
||||||
|
import androidx.paging.liveData
|
||||||
|
import androidx.paging.map
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.video.mobile.wallpaper.Helper
|
||||||
|
import com.video.mobile.wallpaper.R
|
||||||
|
import com.video.mobile.wallpaper.database.DataBaseManager
|
||||||
|
import com.video.mobile.wallpaper.database.LikeWallpaper
|
||||||
|
import com.video.mobile.wallpaper.page.LikePageSource
|
||||||
|
import com.video.mobile.wallpaper.preview.DisplayVideoActivity
|
||||||
|
import com.video.mobile.wallpaper.utils.RecyclerViewSpace
|
||||||
|
|
||||||
|
class FavoriteActivity : AppCompatActivity() {
|
||||||
|
private lateinit var imageBack: ImageView
|
||||||
|
private lateinit var recyclerView: RecyclerView
|
||||||
|
private lateinit var layoutEmpty: LinearLayout
|
||||||
|
private lateinit var favoriteAdapter: FavoriteAdapter
|
||||||
|
|
||||||
|
private val launcher = registerForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) { result ->
|
||||||
|
if (result.resultCode == RESULT_OK) {
|
||||||
|
val deleteSuccess = result.data?.getBooleanExtra(DisplayVideoActivity.IS_REFRESH, false) ?: false
|
||||||
|
if (deleteSuccess) {
|
||||||
|
favoriteAdapter.refresh()
|
||||||
|
Helper.showMyLog("--------- favoriteAdapter.refresh()")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enableEdgeToEdge()
|
||||||
|
setContentView(R.layout.activity_favorite)
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||||
|
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
|
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||||
|
insets
|
||||||
|
}
|
||||||
|
|
||||||
|
imageBack = findViewById(R.id.image_back)
|
||||||
|
imageBack.setOnClickListener { finish() }
|
||||||
|
recyclerView = findViewById(R.id.favorite_recyclerview)
|
||||||
|
layoutEmpty = findViewById(R.id.layout_empty)
|
||||||
|
|
||||||
|
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun init() {
|
||||||
|
favoriteAdapter = FavoriteAdapter(this@FavoriteActivity) { data, strImage ->
|
||||||
|
launcher.launch(Intent(this@FavoriteActivity, DisplayVideoActivity::class.java).apply {
|
||||||
|
putExtra(DisplayVideoActivity.KEY_LIKE_WALLPAPER, data)
|
||||||
|
putExtra(DisplayVideoActivity.THUMBNAIL_STRING, strImage)
|
||||||
|
putExtra(DisplayVideoActivity.KEY_TYPE, DisplayVideoActivity.SOURCE_LIKE)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
recyclerView.run {
|
||||||
|
adapter = favoriteAdapter
|
||||||
|
layoutManager = GridLayoutManager(this@FavoriteActivity, 2)
|
||||||
|
addItemDecoration(RecyclerViewSpace(3, 3, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
getPagingData().observe(this@FavoriteActivity,
|
||||||
|
object : Observer<PagingData<LikeWallpaper>> {
|
||||||
|
override fun onChanged(value: PagingData<LikeWallpaper>) {
|
||||||
|
value.map { item ->
|
||||||
|
Helper.showMyLog("---------LikeWallpaper = ${item.id}") // 打印每条数据
|
||||||
|
item
|
||||||
|
}.let { favoriteAdapter.submitData(lifecycle, it) }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
favoriteAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
||||||
|
override fun onChanged() {
|
||||||
|
checkEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
||||||
|
checkEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
|
||||||
|
checkEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkEmpty() {
|
||||||
|
Helper.showMyLog("---------checkEmpty") // 打印每条数据
|
||||||
|
layoutEmpty.isVisible = favoriteAdapter.itemCount == 0
|
||||||
|
recyclerView.isVisible = favoriteAdapter.itemCount != 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getPagingData(): LiveData<PagingData<LikeWallpaper>> {
|
||||||
|
|
||||||
|
return Pager<Int, LikeWallpaper>(
|
||||||
|
PagingConfig(DataBaseManager.pageSize)
|
||||||
|
) { LikePageSource() }.liveData
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
package com.video.mobile.wallpaper.favorite
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.constraintlayout.utils.widget.ImageFilterView
|
||||||
|
import androidx.paging.PagingDataAdapter
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.load.DataSource
|
||||||
|
import com.bumptech.glide.load.engine.GlideException
|
||||||
|
import com.bumptech.glide.request.RequestListener
|
||||||
|
import com.bumptech.glide.request.target.Target
|
||||||
|
import com.video.mobile.wallpaper.Helper
|
||||||
|
import com.video.mobile.wallpaper.R
|
||||||
|
import com.video.mobile.wallpaper.database.LikeWallpaper
|
||||||
|
import com.video.mobile.wallpaper.database.VideoWallpaper
|
||||||
|
|
||||||
|
class FavoriteAdapter(var context: Context,var clickWallpaper:(wallpaper: LikeWallpaper,thumbnailStr: String)-> Unit) :
|
||||||
|
PagingDataAdapter<LikeWallpaper, FavoriteAdapter.FavoriteAdapterViewHolder>(DIFF_CALLBACK) {
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FavoriteAdapterViewHolder {
|
||||||
|
Helper.showMyLog("-----onCreateViewHolder- ")
|
||||||
|
return FavoriteAdapterViewHolder(
|
||||||
|
LayoutInflater.from(parent.context).inflate(R.layout.favorite_adapter, parent, false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: FavoriteAdapterViewHolder, position: Int) {
|
||||||
|
Helper.showMyLog("-----${position}-- ")
|
||||||
|
val likeWallpaper = getItem(position)
|
||||||
|
|
||||||
|
likeWallpaper?.run {
|
||||||
|
Helper.showMyLog("-----${position}--${Helper.thumbnailStr + thumbnail}")
|
||||||
|
val string = Helper.thumbnailStr + thumbnail
|
||||||
|
holder.imageFilterView.setOnClickListener {
|
||||||
|
clickWallpaper(likeWallpaper,string)
|
||||||
|
}
|
||||||
|
Glide.with(context)
|
||||||
|
.asDrawable()
|
||||||
|
.load(string)
|
||||||
|
.placeholder(R.drawable.thumbnail_placeholder)
|
||||||
|
.centerCrop()
|
||||||
|
.listener(object : RequestListener<Drawable> {
|
||||||
|
override fun onLoadFailed(
|
||||||
|
e: GlideException?,
|
||||||
|
model: Any?,
|
||||||
|
target: Target<Drawable>,
|
||||||
|
isFirstResource: Boolean
|
||||||
|
): Boolean {
|
||||||
|
Helper.showMyLog("---onLoadFailed--${e?.message}")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceReady(
|
||||||
|
resource: Drawable,
|
||||||
|
model: Any,
|
||||||
|
target: Target<Drawable>,
|
||||||
|
dataSource: DataSource,
|
||||||
|
isFirstResource: Boolean
|
||||||
|
): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.into(holder.imageFilterView)
|
||||||
|
} ?: Helper.showMyLog("-----erro-- ")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inner class FavoriteAdapterViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
val imageFilterView: ImageFilterView = itemView.findViewById(R.id.thumbnail)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val DIFF_CALLBACK: DiffUtil.ItemCallback<LikeWallpaper> =
|
||||||
|
object : DiffUtil.ItemCallback<LikeWallpaper>() {
|
||||||
|
override fun areItemsTheSame(oldItem: LikeWallpaper, newItem: LikeWallpaper): Boolean {
|
||||||
|
return oldItem.id == newItem.id
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItem: LikeWallpaper, newItem: LikeWallpaper): Boolean {
|
||||||
|
return oldItem.id == newItem.id
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package com.video.mobile.wallpaper.main
|
||||||
|
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
|
|
||||||
|
class FragmentAdapter(context: FragmentActivity, var list: List<Fragment>) :
|
||||||
|
FragmentStateAdapter(context) {
|
||||||
|
override fun getItemCount(): Int = list.size
|
||||||
|
|
||||||
|
override fun createFragment(position: Int): Fragment = list[position]
|
||||||
|
}
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
package com.video.mobile.wallpaper.main
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
|
import com.video.mobile.wallpaper.R
|
||||||
|
import com.video.mobile.wallpaper.favorite.FavoriteActivity
|
||||||
|
|
||||||
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
|
||||||
|
private lateinit var tab1: TextView
|
||||||
|
private lateinit var tab2: TextView
|
||||||
|
private lateinit var tab3: TextView
|
||||||
|
private lateinit var tvList: List<TextView>
|
||||||
|
private lateinit var viewPager: ViewPager2
|
||||||
|
private lateinit var favoriteBtn: ImageView
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enableEdgeToEdge()
|
||||||
|
setContentView(R.layout.activity_main)
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||||
|
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
|
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||||
|
insets
|
||||||
|
}
|
||||||
|
|
||||||
|
tab1 = findViewById(R.id.text_1_explore)
|
||||||
|
tab2 = findViewById(R.id.text_2_shift)
|
||||||
|
tab3 = findViewById(R.id.text_3_trending)
|
||||||
|
viewPager = findViewById(R.id.viewpager2)
|
||||||
|
favoriteBtn = findViewById(R.id.favorite_btn)
|
||||||
|
|
||||||
|
tvList = listOf(tab1, tab2, tab3)
|
||||||
|
setTabSelect(tab1)
|
||||||
|
setClick()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
viewPager.run {
|
||||||
|
adapter = FragmentAdapter(
|
||||||
|
this@MainActivity, listOf(
|
||||||
|
MainFragment.newInstance(3),
|
||||||
|
MainFragment.newInstance(2),
|
||||||
|
MainFragment.newInstance(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
||||||
|
override fun onPageSelected(position: Int) {
|
||||||
|
super.onPageSelected(position)
|
||||||
|
when (position) {
|
||||||
|
0 -> setTabSelect(tab1)
|
||||||
|
1 -> setTabSelect(tab2)
|
||||||
|
2 -> setTabSelect(tab3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setClick() {
|
||||||
|
tab1.setOnClickListener {
|
||||||
|
setTabSelect(tab1)
|
||||||
|
viewPager.currentItem = 0
|
||||||
|
}
|
||||||
|
tab2.setOnClickListener {
|
||||||
|
setTabSelect(tab2)
|
||||||
|
viewPager.currentItem = 1
|
||||||
|
}
|
||||||
|
tab3.setOnClickListener {
|
||||||
|
setTabSelect(tab3)
|
||||||
|
viewPager.currentItem = 2
|
||||||
|
}
|
||||||
|
favoriteBtn.setOnClickListener {
|
||||||
|
startActivity(Intent(this@MainActivity, FavoriteActivity::class.java))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setTabSelect(textView: TextView) {
|
||||||
|
tvList.forEach { it.isSelected = false }
|
||||||
|
textView.isSelected = true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,94 @@
|
|||||||
|
package com.video.mobile.wallpaper.main
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.constraintlayout.utils.widget.ImageFilterView
|
||||||
|
import androidx.paging.PagingDataAdapter
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.load.DataSource
|
||||||
|
import com.bumptech.glide.load.engine.GlideException
|
||||||
|
import com.bumptech.glide.request.RequestListener
|
||||||
|
import com.bumptech.glide.request.target.Target
|
||||||
|
import com.video.mobile.wallpaper.Helper
|
||||||
|
import com.video.mobile.wallpaper.R
|
||||||
|
import com.video.mobile.wallpaper.database.VideoWallpaper
|
||||||
|
|
||||||
|
class MainAdapter(var context: Context,var clickWallpaper:(wallpaper: VideoWallpaper,thumbnailStr: String)-> Unit) :
|
||||||
|
PagingDataAdapter<VideoWallpaper, MainAdapter.MainAdapterViewHolder>(DIFF_CALLBACK) {
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainAdapterViewHolder {
|
||||||
|
Helper.showMyLog("-----onCreateViewHolder- ")
|
||||||
|
return MainAdapterViewHolder(
|
||||||
|
LayoutInflater.from(parent.context).inflate(R.layout.main_adapter, parent, false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: MainAdapterViewHolder, position: Int) {
|
||||||
|
Helper.showMyLog("-----${position}-- ")
|
||||||
|
val videoWallpaper = getItem(position)
|
||||||
|
videoWallpaper?.run {
|
||||||
|
if (position == 0 || position == 1) {
|
||||||
|
holder.viewPlaceholder.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
holder.viewPlaceholder.visibility = View.GONE
|
||||||
|
}
|
||||||
|
Helper.showMyLog("-----${position}--${Helper.thumbnailStr + thumbnail}")
|
||||||
|
val string = Helper.thumbnailStr + thumbnail
|
||||||
|
holder.imageFilterView.setOnClickListener {
|
||||||
|
clickWallpaper(videoWallpaper,string)
|
||||||
|
}
|
||||||
|
Glide.with(context)
|
||||||
|
.asDrawable()
|
||||||
|
.load(string)
|
||||||
|
.placeholder(R.drawable.thumbnail_placeholder)
|
||||||
|
.centerCrop()
|
||||||
|
.listener(object : RequestListener<Drawable> {
|
||||||
|
override fun onLoadFailed(
|
||||||
|
e: GlideException?,
|
||||||
|
model: Any?,
|
||||||
|
target: Target<Drawable>,
|
||||||
|
isFirstResource: Boolean
|
||||||
|
): Boolean {
|
||||||
|
Helper.showMyLog("---onLoadFailed--${e?.message}")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceReady(
|
||||||
|
resource: Drawable,
|
||||||
|
model: Any,
|
||||||
|
target: Target<Drawable>,
|
||||||
|
dataSource: DataSource,
|
||||||
|
isFirstResource: Boolean
|
||||||
|
): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.into(holder.imageFilterView)
|
||||||
|
} ?: Helper.showMyLog("-----erro-- ")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inner class MainAdapterViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
val imageFilterView: ImageFilterView = itemView.findViewById(R.id.thumbnail)
|
||||||
|
|
||||||
|
val viewPlaceholder: View = itemView.findViewById(R.id.view_placeholder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val DIFF_CALLBACK: DiffUtil.ItemCallback<VideoWallpaper> =
|
||||||
|
object : DiffUtil.ItemCallback<VideoWallpaper>() {
|
||||||
|
override fun areItemsTheSame(oldItem: VideoWallpaper, newItem: VideoWallpaper): Boolean {
|
||||||
|
return oldItem.id == newItem.id
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItem: VideoWallpaper, newItem: VideoWallpaper): Boolean {
|
||||||
|
return oldItem.id == newItem.id
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,110 @@
|
|||||||
|
package com.video.mobile.wallpaper.main
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.paging.Pager
|
||||||
|
import androidx.paging.PagingConfig
|
||||||
|
import androidx.paging.PagingData
|
||||||
|
import androidx.paging.liveData
|
||||||
|
import androidx.paging.map
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.video.mobile.wallpaper.Helper
|
||||||
|
import com.video.mobile.wallpaper.R
|
||||||
|
import com.video.mobile.wallpaper.database.DataBaseManager
|
||||||
|
import com.video.mobile.wallpaper.database.VideoWallpaper
|
||||||
|
import com.video.mobile.wallpaper.page.AllWallpaperPageSource
|
||||||
|
import com.video.mobile.wallpaper.preview.DisplayVideoActivity
|
||||||
|
import com.video.mobile.wallpaper.utils.RecyclerViewSpace
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
|
private const val ARG_PARAM1 = "param1"
|
||||||
|
|
||||||
|
class MainFragment : Fragment() {
|
||||||
|
|
||||||
|
private var type by Delegates.notNull<Long>()
|
||||||
|
|
||||||
|
|
||||||
|
private lateinit var recyclerView: RecyclerView
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
arguments?.let {
|
||||||
|
type = it.getLong(ARG_PARAM1)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
val view = inflater.inflate(R.layout.fragment_main, container, false)
|
||||||
|
recyclerView = view.findViewById(R.id.recycler_view)
|
||||||
|
onInit()
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onInit(){
|
||||||
|
val mainAdapter = MainAdapter(requireActivity()){ data,strImage->
|
||||||
|
startActivity( Intent(requireActivity(), DisplayVideoActivity::class.java).apply {
|
||||||
|
putExtra(DisplayVideoActivity.KEY_VIDEO_WALLPAPER,data)
|
||||||
|
putExtra(DisplayVideoActivity.THUMBNAIL_STRING,strImage)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
recyclerView.run {
|
||||||
|
adapter = mainAdapter
|
||||||
|
layoutManager = GridLayoutManager(requireContext(),2)
|
||||||
|
addItemDecoration(RecyclerViewSpace(3,3,2))
|
||||||
|
}
|
||||||
|
// viewModel.initType(type)
|
||||||
|
// lifecycleScope.launch {
|
||||||
|
// viewModel.videoPagingFlow.collectLatest { pagingData ->
|
||||||
|
// pagingData.map { item ->
|
||||||
|
// println("VideoWallpaper = ${item.id}") // 打印每条数据
|
||||||
|
// item
|
||||||
|
// }.let { mainAdapter.submitData(it) }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
getPagingData(type).observe(getViewLifecycleOwner(),object :Observer<PagingData<VideoWallpaper>>{
|
||||||
|
override fun onChanged(value: PagingData<VideoWallpaper>) {
|
||||||
|
// mainAdapter.submitData(lifecycle, value)
|
||||||
|
value.map { item ->
|
||||||
|
Helper.showMyLog("---------VideoWallpaper = ${item.id}") // 打印每条数据
|
||||||
|
item
|
||||||
|
}.let { mainAdapter.submitData(lifecycle,it) }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPagingData(wallpaperType: Long): LiveData<PagingData<VideoWallpaper>> {
|
||||||
|
|
||||||
|
return Pager<Int, VideoWallpaper>(
|
||||||
|
PagingConfig(DataBaseManager.pageSize)
|
||||||
|
) { AllWallpaperPageSource(wallpaperType) }.liveData
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun newInstance(type: Long) =
|
||||||
|
MainFragment().apply {
|
||||||
|
arguments = Bundle().apply {
|
||||||
|
putLong(ARG_PARAM1, type)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
//package com.video.mobile.wallpaper.main
|
||||||
|
//
|
||||||
|
//import androidx.lifecycle.LiveData
|
||||||
|
//import androidx.lifecycle.ViewModel
|
||||||
|
//import androidx.lifecycle.viewModelScope
|
||||||
|
//import androidx.paging.Pager
|
||||||
|
//import androidx.paging.PagingConfig
|
||||||
|
//import androidx.paging.PagingData
|
||||||
|
//import androidx.paging.cachedIn
|
||||||
|
//import androidx.paging.liveData
|
||||||
|
//import com.video.mobile.wallpaper.database.DataBaseManager
|
||||||
|
//import com.video.mobile.wallpaper.database.VideoWallpaper
|
||||||
|
//import com.video.mobile.wallpaper.page.AllWallpaperPageSource
|
||||||
|
//import kotlinx.coroutines.flow.Flow
|
||||||
|
//import kotlin.properties.Delegates
|
||||||
|
//
|
||||||
|
//class MainViewModel : ViewModel() {
|
||||||
|
//
|
||||||
|
// fun getPagingData(wallpaperType: Long): LiveData<PagingData<VideoWallpaper>> {
|
||||||
|
//
|
||||||
|
// return Pager<Int, VideoWallpaper>(
|
||||||
|
// PagingConfig(DataBaseManager.pageSize)
|
||||||
|
// ) { AllWallpaperPageSource(wallpaperType) }.liveData
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// private var type by Delegates.notNull<Long>()
|
||||||
|
//
|
||||||
|
// fun initType(wallpaperType: Long){
|
||||||
|
// type = wallpaperType
|
||||||
|
// }
|
||||||
|
// val videoPagingFlow: Flow<PagingData<VideoWallpaper>> = Pager(
|
||||||
|
// config = PagingConfig(
|
||||||
|
// pageSize = DataBaseManager.pageSize, // 每页加载数量
|
||||||
|
// initialLoadSize = DataBaseManager.pageSize, // 首次加载数量
|
||||||
|
// enablePlaceholders = false // 是否占位符
|
||||||
|
// ),
|
||||||
|
// pagingSourceFactory = { AllWallpaperPageSource(type) }
|
||||||
|
// ).flow
|
||||||
|
// .cachedIn(viewModelScope)
|
||||||
|
//}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package com.video.mobile.wallpaper.network
|
||||||
|
|
||||||
|
import okhttp3.MediaType
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
import okio.Buffer
|
||||||
|
import okio.BufferedSource
|
||||||
|
import okio.ForwardingSource
|
||||||
|
import okio.buffer
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
class CustomResponseBody(
|
||||||
|
var responseBody: ResponseBody,
|
||||||
|
var contentLength: String,
|
||||||
|
var progressListener: (mByte: Long,total: Long,complete: Boolean) -> Unit
|
||||||
|
) :
|
||||||
|
ResponseBody() {
|
||||||
|
|
||||||
|
private var bufferedSource: BufferedSource? = null
|
||||||
|
override fun contentLength(): Long = responseBody.contentLength()
|
||||||
|
|
||||||
|
override fun contentType(): MediaType? = responseBody.contentType()
|
||||||
|
|
||||||
|
override fun source(): BufferedSource =
|
||||||
|
bufferedSource ?: object : ForwardingSource(responseBody.source()) {
|
||||||
|
var totalBytesRead: Long = 0L
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun read(sink: Buffer, byteCount: Long): Long {
|
||||||
|
val bytesRead = super.read(sink, byteCount)
|
||||||
|
totalBytesRead += if (bytesRead != -1L) bytesRead else 0
|
||||||
|
|
||||||
|
progressListener(totalBytesRead, contentLength.toLong(), bytesRead == -1L)
|
||||||
|
|
||||||
|
return bytesRead
|
||||||
|
}
|
||||||
|
}.buffer()
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package com.video.mobile.wallpaper.network
|
||||||
|
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Response
|
||||||
|
|
||||||
|
class HttpInterceptor(var progressListener: (mByte: Long, total: Long, complete: Boolean) -> Unit) :
|
||||||
|
Interceptor {
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val originalResponse = chain.proceed(chain.request())
|
||||||
|
var fileLength = originalResponse.header("File-Length")
|
||||||
|
if (fileLength == null) {
|
||||||
|
fileLength = "0"
|
||||||
|
}
|
||||||
|
return originalResponse.newBuilder()
|
||||||
|
.body(CustomResponseBody(originalResponse.body!!, fileLength, progressListener))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,256 @@
|
|||||||
|
package com.video.mobile.wallpaper.network
|
||||||
|
|
||||||
|
|
||||||
|
import com.video.mobile.wallpaper.BuildConfig
|
||||||
|
import com.video.mobile.wallpaper.Helper
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.disposables.Disposable
|
||||||
|
import io.reactivex.functions.Consumer
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
object RetrofitManager {
|
||||||
|
|
||||||
|
private var clientBuilder: OkHttpClient.Builder? = null
|
||||||
|
|
||||||
|
|
||||||
|
private const val BASE_URL = "https://neutrolabgames.com/"
|
||||||
|
private const val DEFAULT_TIMEOUT = 5L // 秒
|
||||||
|
|
||||||
|
|
||||||
|
val retrofit: Retrofit.Builder by lazy {
|
||||||
|
Retrofit.Builder()
|
||||||
|
.baseUrl("https://neutrolabgames.com/")
|
||||||
|
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createRetrofit(
|
||||||
|
progressListener: (bytesRead: Long, contentLength: Long, done: Boolean) -> Unit
|
||||||
|
): Retrofit {
|
||||||
|
// 日志拦截器
|
||||||
|
val loggingInterceptor = HttpLoggingInterceptor().apply {
|
||||||
|
level = if (BuildConfig.DEBUG)
|
||||||
|
HttpLoggingInterceptor.Level.HEADERS
|
||||||
|
else
|
||||||
|
HttpLoggingInterceptor.Level.NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
// OkHttpClient
|
||||||
|
val client = OkHttpClient.Builder()
|
||||||
|
// .addInterceptor(loggingInterceptor)
|
||||||
|
.addNetworkInterceptor(HttpInterceptor(progressListener))
|
||||||
|
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
|
||||||
|
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
return Retrofit.Builder()
|
||||||
|
.baseUrl(BASE_URL)
|
||||||
|
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
|
||||||
|
.client(client)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
private fun getRetrofit(progressListener: (mByte: Long, total: Long, complete: Boolean) -> Unit): Retrofit? {
|
||||||
|
|
||||||
|
// retrofit = new Retrofit.Builder()
|
||||||
|
// .baseUrl(base_Host)
|
||||||
|
// .client(client)
|
||||||
|
// /**/ .addConverterFactory(ScalarsConverterFactory.create()) // 支持返回 String 类型
|
||||||
|
// * / .addConverterFactory(GsonConverterFactory.create()) */
|
||||||
|
// .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
|
||||||
|
// .build();
|
||||||
|
|
||||||
|
// builder = builder ?: Retrofit.Builder()
|
||||||
|
// .baseUrl(base_Host)
|
||||||
|
// .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
|
||||||
|
|
||||||
|
|
||||||
|
val DEFAULT_TIMEOUT: Long = 5
|
||||||
|
val httpLoggingInterceptor =
|
||||||
|
HttpLoggingInterceptor().apply { setLevel(HttpLoggingInterceptor.Level.BODY) }
|
||||||
|
|
||||||
|
clientBuilder = clientBuilder ?: OkHttpClient.Builder()
|
||||||
|
.addInterceptor(httpLoggingInterceptor)
|
||||||
|
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
|
||||||
|
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
|
||||||
|
|
||||||
|
clientBuilder?.apply {
|
||||||
|
addInterceptor(HttpInterceptor(progressListener))
|
||||||
|
}?.build()?.let {
|
||||||
|
return retrofit.client(it).build()
|
||||||
|
} ?: return null
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMp4(
|
||||||
|
id: Long,
|
||||||
|
image: String,
|
||||||
|
path: String,
|
||||||
|
progressListener: (mByte: Long, total: Long, complete: Boolean) -> Unit,
|
||||||
|
resultListener: (isOK: Boolean, savePath: String) -> Unit
|
||||||
|
): Disposable {
|
||||||
|
// val retrofit = createRetrofit(progressListener)
|
||||||
|
// val api = retrofit.create(VideoApi::class.java)
|
||||||
|
// Helper.showMyLog("----------getMp4----- ")
|
||||||
|
// return download(api.getMP4(id, "5eV6snEwfY7Yv6Ub", image, "DL8", "ViewLive"),path,resultListener)
|
||||||
|
val retrofit = createRetrofit(progressListener)
|
||||||
|
retrofit.let {
|
||||||
|
Helper.showMyLog("----------get Mp4----- ")
|
||||||
|
return it.create<VideoApi?>(VideoApi::class.java)
|
||||||
|
.getMP4(id, "5eV6snEwfY7Yv6Ub", image, "DL8", "ViewLive")
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.unsubscribeOn(Schedulers.io())
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe(
|
||||||
|
{ body -> // onNext
|
||||||
|
val save = Helper.writeResponseBodyToDisk(body, path)
|
||||||
|
|
||||||
|
Helper.showMyLog("-----save =${save}")
|
||||||
|
},
|
||||||
|
{ error -> // onError
|
||||||
|
resultListener(false, error.message ?: "download error")
|
||||||
|
},
|
||||||
|
{ // onComplete
|
||||||
|
resultListener(true, path)
|
||||||
|
Helper.showMyLog( "Download completed")
|
||||||
|
},
|
||||||
|
{ disposable -> // onSubscribe
|
||||||
|
Helper.showMyLog("Subscribed, can cancel if needed")
|
||||||
|
// 例如:保存 disposable 用于取消下载
|
||||||
|
})
|
||||||
|
// .subscribe(object : Consumer<ResponseBody> {
|
||||||
|
// @Throws(Exception::class)
|
||||||
|
// override fun accept(body: ResponseBody) {
|
||||||
|
// val b: Boolean = Helper.writeFile(body.byteStream(), path)
|
||||||
|
// resultListener(b, path)
|
||||||
|
// }
|
||||||
|
// }, object : Consumer<Throwable> {
|
||||||
|
// @Throws(Exception::class)
|
||||||
|
// override fun accept(throwable: Throwable) {
|
||||||
|
// resultListener(false, throwable.message.toString())
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun getShiftMp4(
|
||||||
|
id: Long,
|
||||||
|
image: String,
|
||||||
|
path: String,
|
||||||
|
progressListener: (mByte: Long, total: Long, complete: Boolean) -> Unit,
|
||||||
|
resultListener: (isOK: Boolean, savePath: String) -> Unit
|
||||||
|
): Disposable {
|
||||||
|
//
|
||||||
|
// val retrofit = createRetrofit(progressListener)
|
||||||
|
// val api = retrofit.create(VideoApi::class.java)
|
||||||
|
// Helper.showMyLog("----------getShiftMp4----- ")
|
||||||
|
// return download(
|
||||||
|
// api.getShiftMP4(id, "5eV6snEwfY7Yv6Ub", image, "DL8", "ViewShiftLive"),
|
||||||
|
// path,
|
||||||
|
// resultListener
|
||||||
|
// )
|
||||||
|
val retrofit = createRetrofit(progressListener)
|
||||||
|
|
||||||
|
retrofit.let {
|
||||||
|
Helper.showMyLog("----------getShiftMp4----- ")
|
||||||
|
return it.create<VideoApi?>(VideoApi::class.java)
|
||||||
|
.getShiftMP4(id, "5eV6snEwfY7Yv6Ub", image, "DL8", "ViewShiftLive")
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.unsubscribeOn(Schedulers.io())
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe(object : Consumer<ResponseBody> {
|
||||||
|
@Throws(Exception::class)
|
||||||
|
override fun accept(body: ResponseBody) {
|
||||||
|
val b: Boolean = Helper.writeResponseBodyToDisk(body, path)
|
||||||
|
resultListener(b, path)
|
||||||
|
}
|
||||||
|
}, object : Consumer<Throwable> {
|
||||||
|
@Throws(Exception::class)
|
||||||
|
override fun accept(throwable: Throwable) {
|
||||||
|
resultListener(false, throwable.message.toString())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun download(
|
||||||
|
apiCall: Observable<ResponseBody>,
|
||||||
|
path: String,
|
||||||
|
resultListener: (Boolean, String) -> Unit
|
||||||
|
): Disposable {
|
||||||
|
return apiCall
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe(object : Consumer<ResponseBody> {
|
||||||
|
@Throws(Exception::class)
|
||||||
|
override fun accept(body: ResponseBody) {
|
||||||
|
val success = try {
|
||||||
|
Helper.writeFile(body.byteStream(), path)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
resultListener(success, path)
|
||||||
|
}
|
||||||
|
}, object : Consumer<Throwable> {
|
||||||
|
@Throws(Exception::class)
|
||||||
|
override fun accept(throwable: Throwable) {
|
||||||
|
resultListener(false, throwable.message ?: "unknown error")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void getDnamicMp4(int id, String image,String path, OnVideoResultListener listener) {
|
||||||
|
// musicApi.getDMP4(id,"5eV6snEwfY7Yv6Ub",image,"DL8","ViewTimerLive","1" )
|
||||||
|
// .subscribeOn(Schedulers.io())
|
||||||
|
// .unsubscribeOn(Schedulers.io())
|
||||||
|
// .observeOn(Schedulers.io())
|
||||||
|
// .subscribe(new ObserverWrapper<>(new OnRequestListener<ResponseBody>() {
|
||||||
|
// @Override
|
||||||
|
// public void onFail(String errorMsg) {
|
||||||
|
// listener.onVideoResult(false,errorMsg);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void onSuccess(ResponseBody data) {
|
||||||
|
// boolean b = Common.writeFile(data.byteStream(), path);
|
||||||
|
// listener.onVideoResult(b,path);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }));
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// companion object {
|
||||||
|
// @Volatile
|
||||||
|
// private lateinit var REQUEST_MANAGER: RetrofitManager
|
||||||
|
//
|
||||||
|
// val instance: RetrofitManager
|
||||||
|
// get() {
|
||||||
|
// if (REQUEST_MANAGER == null) {
|
||||||
|
// synchronized(RetrofitManager::class.java) {
|
||||||
|
// if (REQUEST_MANAGER == null) {
|
||||||
|
// REQUEST_MANAGER = RetrofitManager()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return REQUEST_MANAGER
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
package com.video.mobile.wallpaper.network
|
||||||
|
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
import retrofit2.http.Field
|
||||||
|
import retrofit2.http.FormUrlEncoded
|
||||||
|
import retrofit2.http.POST
|
||||||
|
|
||||||
|
interface VideoApi {
|
||||||
|
@POST("LiveLoop/AppData/jmywall.php")
|
||||||
|
@FormUrlEncoded
|
||||||
|
fun getMP4(
|
||||||
|
@Field("pi") pi: Long,
|
||||||
|
@Field("medium") medium: String?,
|
||||||
|
@Field("alpha") alpha: String?,
|
||||||
|
@Field("version") version: String?,
|
||||||
|
@Field("quality") quality: String?
|
||||||
|
): Observable<ResponseBody>
|
||||||
|
|
||||||
|
|
||||||
|
//shift
|
||||||
|
@POST("LiveLoop/AppData/jshiftwall.php")
|
||||||
|
@FormUrlEncoded
|
||||||
|
fun getShiftMP4(
|
||||||
|
@Field("pi") pi: Long,
|
||||||
|
@Field("medium") medium: String?,
|
||||||
|
@Field("alpha") alpha: String?,
|
||||||
|
@Field("version") version: String?,
|
||||||
|
@Field("quality") quality: String?
|
||||||
|
): Observable<ResponseBody> //
|
||||||
|
// //Dnamic
|
||||||
|
// @POST("LiveLoop/AppData/jdaytimewall.php")
|
||||||
|
// @FormUrlEncoded
|
||||||
|
// Observable<ResponseBody> getDMP4(@Field("pi") int pi,
|
||||||
|
// @Field("medium") String medium,
|
||||||
|
// @Field("alpha") String alpha,
|
||||||
|
// @Field("version") String version,
|
||||||
|
// @Field("quality") String quality,
|
||||||
|
// @Field("filenumber") String filenumber);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
package com.video.mobile.wallpaper.page
|
||||||
|
|
||||||
|
import androidx.paging.PagingSource
|
||||||
|
import androidx.paging.PagingState
|
||||||
|
import com.video.mobile.wallpaper.Helper
|
||||||
|
import com.video.mobile.wallpaper.database.DataBaseManager
|
||||||
|
import com.video.mobile.wallpaper.database.VideoWallpaper
|
||||||
|
|
||||||
|
class AllWallpaperPageSource(var wallpaperType: Long) : PagingSource<Int, VideoWallpaper>() {
|
||||||
|
|
||||||
|
override fun getRefreshKey(state: PagingState<Int, VideoWallpaper>): Int? {
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, VideoWallpaper> {
|
||||||
|
|
||||||
|
try {
|
||||||
|
val page = params.key ?: 1
|
||||||
|
|
||||||
|
page.let {
|
||||||
|
val data: List<VideoWallpaper> = DataBaseManager.queryData(wallpaperType, it)
|
||||||
|
Helper.showMyLog("--------load data ${data.size} ")
|
||||||
|
return LoadResult.Page(
|
||||||
|
data,
|
||||||
|
if (it > 1) it - 1 else null,
|
||||||
|
if (data.isEmpty()) null else it + 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Helper.showMyLog("--------load ${e.message} ")
|
||||||
|
return LoadResult.Error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package com.video.mobile.wallpaper.page
|
||||||
|
|
||||||
|
import androidx.paging.PagingSource
|
||||||
|
import androidx.paging.PagingState
|
||||||
|
import com.video.mobile.wallpaper.database.DataBaseManager
|
||||||
|
import com.video.mobile.wallpaper.database.LikeWallpaper
|
||||||
|
import com.video.mobile.wallpaper.database.VideoWallpaper
|
||||||
|
|
||||||
|
class LikePageSource() : PagingSource<Int, LikeWallpaper>() {
|
||||||
|
|
||||||
|
override fun getRefreshKey(state: PagingState<Int, LikeWallpaper>): Int? {
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, LikeWallpaper> {
|
||||||
|
|
||||||
|
try {
|
||||||
|
val page = params.key ?: 1
|
||||||
|
|
||||||
|
page.let {
|
||||||
|
val data: List<LikeWallpaper> = DataBaseManager.queryLike(it)
|
||||||
|
return LoadResult.Page(
|
||||||
|
data,
|
||||||
|
if (it > 1) it - 1 else null,
|
||||||
|
if (data.isEmpty()) null else it + 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return LoadResult.Error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,502 @@
|
|||||||
|
package com.video.mobile.wallpaper.preview
|
||||||
|
|
||||||
|
import android.app.WallpaperManager
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.ProgressBar
|
||||||
|
import android.widget.RelativeLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.activity.OnBackPressedCallback
|
||||||
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.annotation.OptIn
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.media3.common.MediaItem
|
||||||
|
import androidx.media3.common.PlaybackException
|
||||||
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
|
import androidx.media3.ui.PlayerView
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.load.DataSource
|
||||||
|
import com.bumptech.glide.load.engine.GlideException
|
||||||
|
import com.bumptech.glide.request.RequestListener
|
||||||
|
import com.bumptech.glide.request.target.Target
|
||||||
|
import com.video.mobile.wallpaper.App
|
||||||
|
import com.video.mobile.wallpaper.Helper
|
||||||
|
import com.video.mobile.wallpaper.Helper.getSerializableExtraCompat
|
||||||
|
import com.video.mobile.wallpaper.R
|
||||||
|
import com.video.mobile.wallpaper.database.DataBaseManager
|
||||||
|
import com.video.mobile.wallpaper.database.LikeWallpaper
|
||||||
|
import com.video.mobile.wallpaper.database.VideoWallpaper
|
||||||
|
import com.video.mobile.wallpaper.network.RetrofitManager
|
||||||
|
import com.video.mobile.wallpaper.utils.RecyclerViewSpace
|
||||||
|
import io.reactivex.disposables.Disposable
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
|
class DisplayVideoActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val KEY_VIDEO_WALLPAPER = "video_wallpaper"
|
||||||
|
val KEY_LIKE_WALLPAPER = "like_wallpaper"
|
||||||
|
val KEY_TYPE = "source"
|
||||||
|
val SOURCE_MAIN = -1
|
||||||
|
val SOURCE_LIKE = -2
|
||||||
|
val THUMBNAIL_STRING = "thumbnail_string"
|
||||||
|
val IS_REFRESH = "is_refresh"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private var intentVideoWallpaper: VideoWallpaper? = null
|
||||||
|
private var intentLikeWallpaper: LikeWallpaper? = null
|
||||||
|
|
||||||
|
private var sourceType: Int = -1
|
||||||
|
private val loadingType_circle = 0
|
||||||
|
private val loadingType_download = 1
|
||||||
|
private val loadingType_retry = 2
|
||||||
|
private var exoPlayer: ExoPlayer? = null
|
||||||
|
private lateinit var downloadingProgressLayout: LinearLayout
|
||||||
|
private lateinit var backFrameLayout: FrameLayout
|
||||||
|
private lateinit var downloadProgressbar: ProgressBar
|
||||||
|
private lateinit var progressBar: ProgressBar
|
||||||
|
private lateinit var playerView: PlayerView
|
||||||
|
private lateinit var retryLinearLayout: LinearLayout
|
||||||
|
private lateinit var loadingLayout: RelativeLayout
|
||||||
|
private lateinit var retryTextView: TextView
|
||||||
|
|
||||||
|
private var wallpaperId by Delegates.notNull<Long>()
|
||||||
|
|
||||||
|
private var wallpaperType by Delegates.notNull<Long>()
|
||||||
|
private lateinit var thumbnailImageView: ImageView
|
||||||
|
|
||||||
|
private lateinit var cachePath: String
|
||||||
|
private lateinit var cacheFile: File
|
||||||
|
|
||||||
|
private var disposable: Disposable? = null
|
||||||
|
|
||||||
|
private lateinit var networkErrorStr: String
|
||||||
|
private lateinit var playErrorStr: String
|
||||||
|
private lateinit var thumbnailStr: String
|
||||||
|
|
||||||
|
private lateinit var textDescriptor: TextView
|
||||||
|
private lateinit var textBtnSet: TextView
|
||||||
|
private lateinit var frameFavorite: FrameLayout
|
||||||
|
private lateinit var imageFavorite: ImageView
|
||||||
|
|
||||||
|
private lateinit var textRetry: TextView
|
||||||
|
|
||||||
|
private lateinit var bottomLayout: LinearLayout
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enableEdgeToEdge()
|
||||||
|
setContentView(R.layout.activity_display_video)
|
||||||
|
backFrameLayout = findViewById(R.id.back_btn)
|
||||||
|
bottomLayout = findViewById(R.id.layout_btn)
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||||
|
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
|
// v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||||
|
val params = backFrameLayout.layoutParams as ViewGroup.MarginLayoutParams
|
||||||
|
params.topMargin = systemBars.top
|
||||||
|
backFrameLayout.layoutParams = params
|
||||||
|
|
||||||
|
val marginLayoutParams = bottomLayout.layoutParams as ViewGroup.MarginLayoutParams
|
||||||
|
marginLayoutParams.bottomMargin =
|
||||||
|
systemBars.bottom + RecyclerViewSpace.dpToPx(20f).toInt()
|
||||||
|
bottomLayout.layoutParams = marginLayoutParams
|
||||||
|
Helper.showMyLog("---systemBars.top--${systemBars.top} bottom = ${systemBars.bottom}")
|
||||||
|
insets
|
||||||
|
}
|
||||||
|
downloadingProgressLayout = findViewById(R.id.download_progress_layout)
|
||||||
|
downloadProgressbar = findViewById(R.id.horizontal_progressbar)
|
||||||
|
progressBar = findViewById(R.id.normal_progress)
|
||||||
|
playerView = findViewById(R.id.player_view)
|
||||||
|
retryLinearLayout = findViewById(R.id.retry_layout)
|
||||||
|
loadingLayout = findViewById(R.id.loading_bg_layout)
|
||||||
|
retryTextView = findViewById(R.id.tv_load_fail)
|
||||||
|
thumbnailImageView = findViewById(R.id.image_thumbnail)
|
||||||
|
textRetry = findViewById(R.id.tv_retry_button)
|
||||||
|
|
||||||
|
textDescriptor = findViewById(R.id.tv_video_describe)
|
||||||
|
textBtnSet = findViewById(R.id.text_btn_set)
|
||||||
|
frameFavorite = findViewById(R.id.framelayout_favorite)
|
||||||
|
imageFavorite = findViewById(R.id.im_favorite)
|
||||||
|
|
||||||
|
|
||||||
|
networkErrorStr = getString(R.string.download_fail_network)
|
||||||
|
playErrorStr = getString(R.string.download_fail_unknown)
|
||||||
|
getIntentData()
|
||||||
|
setAllClick()
|
||||||
|
initPlayerView()
|
||||||
|
if (cacheFile.exists()) {
|
||||||
|
playVideo(cacheFile)
|
||||||
|
} else {
|
||||||
|
getNetWorkVideo(cachePath)
|
||||||
|
}
|
||||||
|
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
||||||
|
override fun handleOnBackPressed() {
|
||||||
|
Helper.showMyLog("---handleOnBackPressed")
|
||||||
|
backPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setAllClick() {
|
||||||
|
backFrameLayout.setOnClickListener {
|
||||||
|
backPage()
|
||||||
|
|
||||||
|
}
|
||||||
|
textBtnSet.setOnClickListener {
|
||||||
|
if (cacheFile.exists()) {
|
||||||
|
setVideoWallpaper()
|
||||||
|
} else {
|
||||||
|
Helper.showToast(this@DisplayVideoActivity, getString(R.string.cache_file_no_lost))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
textRetry.setOnClickListener {
|
||||||
|
getNetWorkVideo(cachePath)
|
||||||
|
}
|
||||||
|
frameFavorite.setOnClickListener {
|
||||||
|
showCircleLoading(true, loadingType_circle)
|
||||||
|
val newStatus = !imageFavorite.isSelected
|
||||||
|
if (newStatus) {
|
||||||
|
intentVideoWallpaper?.let {
|
||||||
|
Helper.showMyLog("--- Video --insertLike ")
|
||||||
|
DataBaseManager.insertLike(LikeWallpaper().apply {
|
||||||
|
id = it.id
|
||||||
|
description = it.description
|
||||||
|
image = it.image
|
||||||
|
wallpapertype = it.wallpapertype
|
||||||
|
thumbnail = it.thumbnail
|
||||||
|
})
|
||||||
|
}
|
||||||
|
intentLikeWallpaper?.let {
|
||||||
|
Helper.showMyLog("---Like --insertLike ")
|
||||||
|
DataBaseManager.insertLike(it)
|
||||||
|
}
|
||||||
|
imageFavorite.isSelected = newStatus
|
||||||
|
showCircleLoading(false)
|
||||||
|
} else {
|
||||||
|
DataBaseManager.deleteLike(wallpaperId) { deleteOk ->
|
||||||
|
showCircleLoading(false)
|
||||||
|
if (deleteOk) {
|
||||||
|
imageFavorite.isSelected = newStatus
|
||||||
|
Helper.showToast(
|
||||||
|
this@DisplayVideoActivity,
|
||||||
|
getString(R.string.remove_favorite_ok)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Helper.showToast(
|
||||||
|
this@DisplayVideoActivity,
|
||||||
|
getString(R.string.remove_favorite_fail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun backPage() {
|
||||||
|
val resultIntent = Intent()
|
||||||
|
resultIntent.putExtra(IS_REFRESH, !imageFavorite.isSelected)
|
||||||
|
setResult(RESULT_OK, resultIntent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getIntentData() {
|
||||||
|
sourceType = intent.getIntExtra(KEY_TYPE, SOURCE_MAIN)
|
||||||
|
when (sourceType) {
|
||||||
|
SOURCE_MAIN -> {
|
||||||
|
intentVideoWallpaper = intent.getSerializableExtraCompat(KEY_VIDEO_WALLPAPER)
|
||||||
|
Helper.showMyLog("---序列化 intentVideoWallpaper=${intentVideoWallpaper} ")
|
||||||
|
intentVideoWallpaper?.let {
|
||||||
|
wallpaperId = it.id
|
||||||
|
wallpaperType = it.wallpapertype
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SOURCE_LIKE -> {
|
||||||
|
intentLikeWallpaper = intent.getSerializableExtraCompat(KEY_LIKE_WALLPAPER)
|
||||||
|
Helper.showMyLog("---序列化 intentLikeWallpaper=${intentLikeWallpaper} ")
|
||||||
|
intentLikeWallpaper?.let {
|
||||||
|
wallpaperId = it.id
|
||||||
|
wallpaperType = it.wallpapertype
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
textDescriptor.text = intentVideoWallpaper?.description ?: intentLikeWallpaper?.description
|
||||||
|
thumbnailStr = intent.getStringExtra(THUMBNAIL_STRING).toString()
|
||||||
|
|
||||||
|
cachePath = getCachePath(wallpaperId)
|
||||||
|
cacheFile = File(cachePath)
|
||||||
|
|
||||||
|
Helper.showMyLog("--thumbnailStr=${thumbnailStr} ")
|
||||||
|
Glide.with(this)
|
||||||
|
.asDrawable()
|
||||||
|
.load(thumbnailStr)
|
||||||
|
.placeholder(R.drawable.thumbnail_placeholder)
|
||||||
|
.centerCrop()
|
||||||
|
.listener(object : RequestListener<Drawable> {
|
||||||
|
override fun onLoadFailed(
|
||||||
|
e: GlideException?,
|
||||||
|
model: Any?,
|
||||||
|
target: Target<Drawable>,
|
||||||
|
isFirstResource: Boolean
|
||||||
|
): Boolean {
|
||||||
|
Helper.showMyLog("---onLoadFailed--${e?.message}")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceReady(
|
||||||
|
resource: Drawable,
|
||||||
|
model: Any,
|
||||||
|
target: Target<Drawable>,
|
||||||
|
dataSource: DataSource,
|
||||||
|
isFirstResource: Boolean
|
||||||
|
): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.into(thumbnailImageView)
|
||||||
|
|
||||||
|
|
||||||
|
imageFavorite.setSelected(DataBaseManager.queryIsLike(wallpaperId))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun initPlayerView() {
|
||||||
|
exoPlayer = ExoPlayer.Builder(this)
|
||||||
|
.build()
|
||||||
|
exoPlayer?.run {
|
||||||
|
repeatMode = ExoPlayer.REPEAT_MODE_ONE
|
||||||
|
// addListener(object : Player.Listener {
|
||||||
|
// override fun onPlaybackStateChanged(playbackState: Int) {
|
||||||
|
// if (playbackState == Player.STATE_READY) {
|
||||||
|
//// showCircleLoading(true, loadingType_circle)
|
||||||
|
// Helper.showMyLog("-------onPlaybackStateChanged-----")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
playerView.setPlayer(exoPlayer)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setVideoWallpaper() {
|
||||||
|
WallpaperPathManager.video_wallpaper_path = cachePath
|
||||||
|
Helper.showMyLog("----------setVideo_path---cachePath=$cachePath")
|
||||||
|
val wallpaperManager = WallpaperManager.getInstance(this)
|
||||||
|
try {
|
||||||
|
wallpaperManager.clear()
|
||||||
|
Helper.showMyLog("----------clear=")
|
||||||
|
} catch (e: java.lang.Exception) {
|
||||||
|
Helper.showMyLog("---------e=" + e.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val componentName =
|
||||||
|
ComponentName(this@DisplayVideoActivity, VideoWallpaperService::class.java)
|
||||||
|
val intent = Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER)
|
||||||
|
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, componentName)
|
||||||
|
startActivity(intent)
|
||||||
|
} catch (e: java.lang.Exception) {
|
||||||
|
Helper.showMyLog("---------e=" + e.message)
|
||||||
|
}
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
private fun playVideo(file: File) {
|
||||||
|
try {
|
||||||
|
val uri = Uri.fromFile(file)
|
||||||
|
// val uriFromFilePath: Uri = Com.getUriFromFilePath(this, filePath)
|
||||||
|
// val mediaItem = MediaItem.fromUri(uriFromFilePath)
|
||||||
|
// val mediaSource: ProgressiveMediaSource = createMediaSource(mediaItem)
|
||||||
|
val mediaItem = MediaItem.fromUri(uri)
|
||||||
|
exoPlayer?.setMediaItem(mediaItem)
|
||||||
|
exoPlayer?.addListener(object : Player.Listener {
|
||||||
|
override fun onPlayerError(error: PlaybackException) {
|
||||||
|
super.onPlayerError(error)
|
||||||
|
Helper.showMyLog("-------------onPlayerError error=${error.message}")
|
||||||
|
// deleteFile(cacheFile)
|
||||||
|
showCircleLoading(true, loadingType_retry, playErrorStr)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRenderedFirstFrame() {
|
||||||
|
super.onRenderedFirstFrame()
|
||||||
|
//播放视频第一帧
|
||||||
|
showCircleLoading(false)
|
||||||
|
thumbnailImageView.visibility = View.GONE
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
exoPlayer?.prepare()
|
||||||
|
exoPlayer?.play()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Helper.showMyLog("playVideo ${e.message}")
|
||||||
|
// deleteFile(cacheFile)
|
||||||
|
showCircleLoading(true, loadingType_retry, playErrorStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getNetWorkVideo(cachePath: String) {
|
||||||
|
showCircleLoading(true, loadingType_circle)
|
||||||
|
val imageStr = intentVideoWallpaper?.image ?: intentLikeWallpaper?.image
|
||||||
|
imageStr?.let {
|
||||||
|
if (wallpaperType == 2L) {
|
||||||
|
//shift
|
||||||
|
disposable = RetrofitManager
|
||||||
|
.getShiftMp4(
|
||||||
|
wallpaperId,
|
||||||
|
it,
|
||||||
|
cachePath,
|
||||||
|
{ mByte: Long, total: Long, complete: Boolean ->
|
||||||
|
runOnUiThread {
|
||||||
|
updateDownloadProgress(mByte, total, complete)
|
||||||
|
}
|
||||||
|
|
||||||
|
}) { ok: Boolean, path: String ->
|
||||||
|
runOnUiThread {
|
||||||
|
requestResult(ok, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
disposable = RetrofitManager.getMp4(
|
||||||
|
wallpaperId,
|
||||||
|
it,
|
||||||
|
cachePath,
|
||||||
|
{ mByte: Long, total: Long, complete: Boolean ->
|
||||||
|
runOnUiThread {
|
||||||
|
updateDownloadProgress(mByte, total, complete)
|
||||||
|
}
|
||||||
|
}) { ok: Boolean, path: String ->
|
||||||
|
runOnUiThread {
|
||||||
|
requestResult(ok, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun requestResult(isOK: Boolean, path: String) {
|
||||||
|
Helper.showMyLog("------------requestResult-------path= ${path}")
|
||||||
|
val file = File(path)
|
||||||
|
if (file.exists() && isOK) {
|
||||||
|
playVideo(file)
|
||||||
|
} else {
|
||||||
|
showCircleLoading(true, loadingType_retry)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showCircleLoading(
|
||||||
|
show: Boolean,
|
||||||
|
loadingType: Int? = 0,
|
||||||
|
retryString: String? = networkErrorStr
|
||||||
|
) {
|
||||||
|
if (show) {
|
||||||
|
loadingLayout.visibility = View.VISIBLE
|
||||||
|
when (loadingType) {
|
||||||
|
loadingType_circle -> {
|
||||||
|
progressBar.visibility = View.VISIBLE
|
||||||
|
retryLinearLayout.visibility = View.GONE
|
||||||
|
downloadingProgressLayout.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingType_download -> {
|
||||||
|
progressBar.visibility = View.GONE
|
||||||
|
retryLinearLayout.visibility = View.GONE
|
||||||
|
downloadingProgressLayout.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingType_retry -> {
|
||||||
|
progressBar.visibility = View.GONE
|
||||||
|
retryLinearLayout.visibility = View.VISIBLE
|
||||||
|
downloadingProgressLayout.visibility = View.GONE
|
||||||
|
retryTextView.text = retryString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
loadingLayout.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateDownloadProgress(mByte: Long, total: Long, complete: Boolean) {
|
||||||
|
Helper.showMyLog("------------updateDownloadProgress---- ${mByte}")
|
||||||
|
if (total <= 0) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
val current = ((100 * mByte) / total).toInt()
|
||||||
|
if (downloadProgressbar.progress != current) {
|
||||||
|
runOnUiThread(object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
if (downloadingProgressLayout.visibility !== View.VISIBLE) {
|
||||||
|
showCircleLoading(true, loadingType_download)
|
||||||
|
Helper.showMyLog("------------showLoading------11-----")
|
||||||
|
} else {
|
||||||
|
Helper.showMyLog("------------showLoading------22-----")
|
||||||
|
}
|
||||||
|
downloadProgressbar.progress = current
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有下载的视频保存位置
|
||||||
|
*/
|
||||||
|
private fun getCachePath(id: Long): String {
|
||||||
|
|
||||||
|
return "${App.mApp.cacheDir}/$id.mp4"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteFile(file: File): Boolean {
|
||||||
|
return file.exists() && file.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUriFromFilePath(context: Context, filePath: String): Uri? {
|
||||||
|
val file = File(filePath)
|
||||||
|
|
||||||
|
// 使用 FileProvider 获取 URI
|
||||||
|
return FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
exoPlayer?.release()
|
||||||
|
// if (countDownTimer != null) {
|
||||||
|
// countDownTimer.cancel()
|
||||||
|
// countDownTimer = null
|
||||||
|
// }
|
||||||
|
disposable?.isDisposed?.let {
|
||||||
|
if (!it) {
|
||||||
|
Helper.showMyLog("----------- disposable?.dispose()---")
|
||||||
|
disposable?.dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,112 @@
|
|||||||
|
package com.video.mobile.wallpaper.preview
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import android.service.wallpaper.WallpaperService
|
||||||
|
import android.view.SurfaceHolder
|
||||||
|
import androidx.annotation.OptIn
|
||||||
|
import androidx.media3.common.C
|
||||||
|
import androidx.media3.common.MediaItem
|
||||||
|
import androidx.media3.common.PlaybackException
|
||||||
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
|
import com.video.mobile.wallpaper.Helper
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class VideoWallpaperService : WallpaperService() {
|
||||||
|
override fun onCreateEngine(): Engine? = VideoWallpaperEngine()
|
||||||
|
|
||||||
|
inner class VideoWallpaperEngine : Engine() {
|
||||||
|
private var exoPlayer: ExoPlayer? = null
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
private fun initExoPlay() {
|
||||||
|
exoPlayer = ExoPlayer.Builder(this@VideoWallpaperService).build()
|
||||||
|
exoPlayer?.repeatMode = ExoPlayer.REPEAT_MODE_ONE
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(surfaceHolder: SurfaceHolder?) {
|
||||||
|
super.onCreate(surfaceHolder)
|
||||||
|
Helper.showMyLog("-----Engine-----onCreate")
|
||||||
|
initExoPlay()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
override fun onSurfaceCreated(holder: SurfaceHolder?) {
|
||||||
|
super.onSurfaceCreated(holder)
|
||||||
|
val surface = holder?.surface
|
||||||
|
if (surface != null) {
|
||||||
|
exoPlayer?.setVideoSurface(surface)
|
||||||
|
exoPlayer?.videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onVisibilityChanged(visible: Boolean) {
|
||||||
|
super.onVisibilityChanged(visible)
|
||||||
|
Helper.showMyLog("-------Engine---onVisibilityChanged visible=$visible")
|
||||||
|
if (visible) {
|
||||||
|
update()
|
||||||
|
exoPlayer?.play()
|
||||||
|
} else {
|
||||||
|
exoPlayer?.pause()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun onSurfaceDestroyed(holder: SurfaceHolder?) {
|
||||||
|
super.onSurfaceDestroyed(holder)
|
||||||
|
Helper.showMyLog("------Engine----onSurfaceDestroyed---")
|
||||||
|
exoPlayer?.release()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
Helper.showMyLog("-------Engine---onDestroy---")
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSurfaceChanged(
|
||||||
|
holder: SurfaceHolder?,
|
||||||
|
format: Int,
|
||||||
|
width: Int,
|
||||||
|
height: Int
|
||||||
|
) {
|
||||||
|
super.onSurfaceChanged(holder, format, width, height)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun update() {
|
||||||
|
val file = File(WallpaperPathManager.video_wallpaper_path)
|
||||||
|
if (file.isFile && file.exists()) {
|
||||||
|
val uri = Uri.fromFile(file)
|
||||||
|
val mediaItem = MediaItem.fromUri(uri)
|
||||||
|
exoPlayer?.run {
|
||||||
|
setMediaItem(mediaItem)
|
||||||
|
addListener(object : Player.Listener {
|
||||||
|
override fun onPlayerError(error: PlaybackException) {
|
||||||
|
super.onPlayerError(error)
|
||||||
|
Helper.showMyLog("-----------update--onPlayerError")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRenderedFirstFrame() {
|
||||||
|
super.onRenderedFirstFrame()
|
||||||
|
//播放视频第一帧
|
||||||
|
Helper.showMyLog("-----------update--播放视频第一帧")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
prepare()
|
||||||
|
playWhenReady = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
package com.video.mobile.wallpaper.preview
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import com.video.mobile.wallpaper.App
|
||||||
|
import androidx.core.content.edit
|
||||||
|
|
||||||
|
|
||||||
|
object WallpaperPathManager {
|
||||||
|
|
||||||
|
val KEY_CURRENT_WAPPPAPER_PATH = "video_wallpaper_path"
|
||||||
|
val DB_INIT_DATAT = "init_db_data"
|
||||||
|
|
||||||
|
private var shared: SharedPreferences? = null
|
||||||
|
|
||||||
|
var video_wallpaper_path: String
|
||||||
|
get() = queryString(
|
||||||
|
KEY_CURRENT_WAPPPAPER_PATH,
|
||||||
|
""
|
||||||
|
)
|
||||||
|
set(value) {
|
||||||
|
saveString(KEY_CURRENT_WAPPPAPER_PATH, value)
|
||||||
|
}
|
||||||
|
var dbinit: String
|
||||||
|
get() = queryString(
|
||||||
|
DB_INIT_DATAT,
|
||||||
|
"0"
|
||||||
|
)
|
||||||
|
set(value) {
|
||||||
|
saveString(DB_INIT_DATAT, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getShared(): SharedPreferences {
|
||||||
|
if (shared == null) {
|
||||||
|
shared = App.mApp.getSharedPreferences("", Context.MODE_PRIVATE)
|
||||||
|
}
|
||||||
|
return shared!!
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveString(key: String, value: String) {
|
||||||
|
getShared().edit {
|
||||||
|
putString(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun queryString(key: String, defaultValue: String): String {
|
||||||
|
return getShared()
|
||||||
|
.getString(key, defaultValue).orEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
package com.video.mobile.wallpaper.utils
|
||||||
|
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.recyclerview.widget.RecyclerView.ItemDecoration
|
||||||
|
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||||
|
import com.video.mobile.wallpaper.App
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
|
||||||
|
class RecyclerViewSpace(v: Int, h: Int, ex: Int) : ItemDecoration() {
|
||||||
|
private val v: Int = dpToPx(v.toFloat()).roundToInt()
|
||||||
|
private val h: Int = dpToPx(h.toFloat()).roundToInt()
|
||||||
|
private val ex: Int = dpToPx(ex.toFloat()).roundToInt()
|
||||||
|
|
||||||
|
override fun getItemOffsets(
|
||||||
|
outRect: Rect,
|
||||||
|
view: View,
|
||||||
|
parent: RecyclerView,
|
||||||
|
state: RecyclerView.State
|
||||||
|
) {
|
||||||
|
super.getItemOffsets(outRect, view, parent, state)
|
||||||
|
var spanCount = 1
|
||||||
|
var spanSize = 1
|
||||||
|
var spanIndex = 0
|
||||||
|
|
||||||
|
val childAdapterPosition = parent.getChildAdapterPosition(view)
|
||||||
|
val layoutManager = parent.layoutManager
|
||||||
|
if (layoutManager is StaggeredGridLayoutManager) {
|
||||||
|
val layoutParams = view.layoutParams as StaggeredGridLayoutManager.LayoutParams
|
||||||
|
spanCount = layoutManager.spanCount
|
||||||
|
if (layoutParams.isFullSpan) {
|
||||||
|
spanSize = spanCount
|
||||||
|
}
|
||||||
|
spanIndex = layoutParams.spanIndex
|
||||||
|
} else if (layoutManager is GridLayoutManager) {
|
||||||
|
val gridLayoutManager = layoutManager
|
||||||
|
val layoutParams = view.layoutParams as GridLayoutManager.LayoutParams
|
||||||
|
spanCount = gridLayoutManager.spanCount
|
||||||
|
spanSize = gridLayoutManager.spanSizeLookup.getSpanSize(childAdapterPosition)
|
||||||
|
spanIndex = layoutParams.spanIndex
|
||||||
|
} else if (layoutManager is LinearLayoutManager) {
|
||||||
|
outRect.left = v
|
||||||
|
outRect.right = v
|
||||||
|
outRect.bottom = h
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spanSize == spanCount) {
|
||||||
|
outRect.left = v + ex
|
||||||
|
outRect.right = v + ex
|
||||||
|
outRect.bottom = h
|
||||||
|
} else {
|
||||||
|
val itemAllSpacing = (v * (spanCount + 1) + ex * 2) / spanCount
|
||||||
|
val left = v * (spanIndex + 1) - itemAllSpacing * spanIndex + ex
|
||||||
|
val right = itemAllSpacing - left
|
||||||
|
outRect.left = left
|
||||||
|
outRect.right = right
|
||||||
|
outRect.bottom = h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun dpToPx(dpValue: Float): Float {
|
||||||
|
val density: Float = App.mApp.resources.displayMetrics.density
|
||||||
|
return density * dpValue + 0.5f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
app/src/main/res/drawable/common_back_button.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="64dp"
|
||||||
|
android:height="64dp"
|
||||||
|
android:viewportWidth="1024"
|
||||||
|
android:viewportHeight="1024">
|
||||||
|
<path
|
||||||
|
android:pathData="M395.2,513.6l323.1,-312.4c19.1,-18.4 19.1,-48.3 0,-66.7 -19.1,-18.4 -49.9,-18.4 -69,0L291.8,480.3c-19.1,18.4 -19.1,48.3 0,66.7l357.6,345.7c9.5,9.2 22,13.8 34.5,13.8 12.5,0 25,-4.6 34.5,-13.8 19.1,-18.4 19.1,-48.2 0,-66.7L395.2,513.6z"
|
||||||
|
android:fillColor="@color/black"/>
|
||||||
|
</vector>
|
||||||
6
app/src/main/res/drawable/common_back_button_bg.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid android:color="@color/main_sub_color"/>
|
||||||
|
|
||||||
|
</shape>
|
||||||
7
app/src/main/res/drawable/common_set_wallpaper_bg.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/main_sub_color" />
|
||||||
|
<corners android:radius="9dp" />
|
||||||
|
|
||||||
|
</shape>
|
||||||
6
app/src/main/res/drawable/display_selector_favorite.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@drawable/icon_favorite_selected" android:state_selected="true" />
|
||||||
|
<item android:drawable="@drawable/icon_favorite_unselected" android:state_selected="false" />
|
||||||
|
|
||||||
|
</selector>
|
||||||
39
app/src/main/res/drawable/empty_favorite.xml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="72.7dp"
|
||||||
|
android:height="64dp"
|
||||||
|
android:viewportWidth="1163"
|
||||||
|
android:viewportHeight="1024">
|
||||||
|
<path
|
||||||
|
android:pathData="M1103.8,383.2h-15a15,15 0,0 0,0 30h15v15a15,15 0,0 0,30 0v-15h15a15,15 0,0 0,0 -30h-15v-15a15,15 0,0 0,-30 0v15z"
|
||||||
|
android:fillColor="#F4F4F4"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M0,151.7a25.3,25.3 0,1 0,50.6 0,25.3 25.3,0 0,0 -50.6,0z"
|
||||||
|
android:fillColor="#F4F4F4"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M970,763.9L839.8,455.1H310.6L180.4,763.9H177V1024h796.4V763.9z"
|
||||||
|
android:fillColor="#F8F8F8"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M973.4,1024H177V763.9h3.4L310.6,455.1h529.1L970,763.9h2.5l0.9,7.3V1024h-0zM191.9,1009.4h766.6l-0.4,-235.3 -128.3,-304.3H320.6L191.9,774.9v234.5z"
|
||||||
|
android:fillColor="#CCCCCC"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M309.8,657.4L189.6,1005.9l15.5,5.5 120.2,-348.5L309.8,657.4zM828,657.4L948.1,1005.9 932.7,1011.4 812.5,662.9 828,657.4z"
|
||||||
|
android:fillColor="#CCCCCC"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M492.3,758.5H177v265.5h796.4V758.5H658.2a83,83 0,1 1,-165.9 0z"
|
||||||
|
android:fillColor="#FFFFFF"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M973.4,1024H177V758.5h315l0.6,6.9c3.5,42.7 39.8,76.1 82.7,76.1 42.9,0 79.2,-33.4 82.7,-76.1l0.6,-6.9H973.4v265.5h-0zM191.9,1009.1h766.6V773.4H671.9c-7.2,47 -48.5,83 -96.7,83 -48.3,0 -89.5,-35.9 -96.8,-83H191.9V1009.1z"
|
||||||
|
android:fillColor="#CCCCCC"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M303.4,455.1h531v227.6H303.4z"
|
||||||
|
android:fillColor="#F4F4F4"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M834.4,682.7L303.4,682.7L303.4,455.1h531v227.6zM318.3,668L819.5,668L819.5,469.7L318.3,469.7v198.3z"
|
||||||
|
android:fillColor="#CCCCCC"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M506.3,593.1c11,-5.9 21.9,-12.1 32.7,-18.4 4.3,-2.7 5.8,-8.6 3.4,-13.3 -2.4,-4.7 -7.8,-6.5 -12.2,-4.1 -10.3,6.1 -21.1,12.1 -32.2,18.1a9.9,9.9 0,0 0,-5 8.3,10.2 10.2,0 0,0 4.1,8.8 8.6,8.6 0,0 0,9.1 0.6zM570.3,555.1a764,764 0,0 0,32.3 -19.9,9 9,0 0,0 2.6,-12.8 9.6,9.6 0,0 0,-13.1 -2.5,754.3 754.3,0 0,1 -31.5,19.4 9.1,9.1 0,0 0,-3 12.5,9.6 9.6,0 0,0 12.7,3.3zM635.2,516.8a519,519 0,0 0,31.5 -21.8c4.1,-3.1 4.5,-8.4 0.8,-11.9 -3.7,-3.5 -10,-3.7 -14.1,-0.7a500.2,500.2 0,0 1,-30.3 20.9c-4.1,2.9 -4.8,8 -1.5,11.5 3.2,3.6 9.3,4.4 13.7,1.8zM684.7,477.2c7.9,-10.1 15.2,-20.8 22,-32 2.4,-4.5 1.4,-10.4 -2.3,-13.5 -3.7,-3.1 -8.7,-2.2 -11.5,1.9 -6.3,10.5 -13.2,20.5 -20.6,30a11.3,11.3 0,0 0,0.5 14.1c3.5,3.7 8.8,3.5 11.9,-0.6zM734.8,399.8c-1.9,4.2 -6.3,6 -9.9,3.9 -3.7,-2.1 -5.3,-7.2 -3.6,-11.6 4.3,-10.5 7.6,-21 9.9,-31.7 1.1,-4.6 5.2,-7.3 9.1,-6.2 3.9,1.2 6.4,5.9 5.5,10.6 -2.6,12 -6.3,23.8 -10.9,35zM745.9,332.3a80.2,80.2 0,0 0,-11.3 -37.8c-2.4,-4 -7.2,-5 -10.7,-2.2 -3.5,2.8 -4.3,8.3 -1.9,12.2 5,8.3 8,17.9 8.6,28.8 0.4,4.7 4,8.2 8.1,7.9 4.1,-0.3 7.3,-4.3 7.2,-9zM703,263.3a123.8,123.8 0,0 0,-35.6 -10.3,9.1 9.1,0 0,0 -8.1,2.8 7.2,7.2 0,0 0,-1.3 7.8c1.1,2.6 3.7,4.5 6.8,4.9 10.5,1.4 20.7,4.3 30.2,8.7 2.7,1.4 6.1,1.4 8.8,-0.1a7.6,7.6 0,0 0,4.1 -7.1,7.8 7.8,0 0,0 -4.9,-6.6zM621.6,253c-15.3,3.1 -28.3,9.8 -37.3,19.8a11.6,11.6 0,0 0,-2.5 10c0.7,3.6 3.1,6.5 6.1,7.6 3.1,1.1 6.4,0.1 8.7,-2.4 6.2,-6.8 16,-11.9 28.1,-14.4 4.9,-1 8.1,-6.4 7.3,-12.1 -0.9,-5.7 -5.5,-9.5 -10.4,-8.5zM581.9,315.4c3.3,11.3 10.4,23.1 21.3,35.5a9.3,9.3 0,0 0,13.1 0.8,9.4 9.4,0 0,0 0.8,-13.2c-9.2,-10.4 -14.9,-20 -17.4,-28.3a9.3,9.3 0,1 0,-15.6 -3.8,9.4 9.4,0 0,0 -2.2,9.1zM623.1,372.6a118.4,118.4 0,0 0,35.4 18.9c3.1,1 6.4,0.1 8.8,-2.5a11.3,11.3 0,0 0,2.5 -9.9c-0.8,-3.6 -3.2,-6.4 -6.3,-7.4a101.3,101.3 0,0 1,-30.2 -16.2c-4.1,-2.8 -9.5,-1.5 -12.2,3.1 -2.7,4.6 -1.7,10.8 2.1,14.1zM704.2,391.9a8.3,8.3 0,0 1,-7.5 -4.3,10.1 10.1,0 0,1 -0.4,-9.3 8.5,8.5 0,0 1,7.2 -5c10.6,-0.6 21.1,-2.7 31.3,-6.1a7.9,7.9 0,0 1,8.4 2c2.3,2.3 3.2,5.8 2.5,9.1a9,9 0,0 1,-6 6.8c-11.5,4 -23.4,6.3 -35.5,6.9zM785.3,378c11.4,-6 22.4,-12.8 32.9,-20.2a9.1,9.1 0,0 0,1.8 -12.6,9.5 9.5,0 0,0 -12.8,-2.4 276.6,276.6 0,0 1,-30.8 18.9,9.2 9.2,0 0,0 -5.2,7.9 9.2,9.2 0,0 0,4.5 8.3c2.9,1.7 6.6,1.8 9.6,0.1zM838.7,326.9a498.7,498.7 0,0 0,30.8 -22.6c3.8,-3.2 3.7,-8.2 -0.4,-11.3a12.7,12.7 0,0 0,-14.5 0c-9.5,7.5 -19.4,14.8 -29.6,21.7 -4.1,3 -4.4,7.9 -0.7,11.2 3.7,3.3 10.1,3.7 14.4,1zM887.1,287.6c7.5,-10.3 14.7,-20.9 21.6,-31.7 2.6,-4.4 1.8,-10.5 -1.9,-13.7 -3.7,-3.2 -8.9,-2.5 -11.8,1.7 -6.7,10.5 -13.7,20.7 -21,30.7 -2.8,4.2 -2.3,10.3 1.2,13.8 3.5,3.5 8.7,3.1 11.8,-0.8zM939.8,223.1a748.9,748.9 0,0 0,19.7 -31.9,9.5 9.5,0 0,0 0.1,-9.4 9.1,9.1 0,0 0,-7.8 -4.8,9.1 9.1,0 0,0 -8,4.6 740,740 0,0 1,-19.3 31.2,9.5 9.5,0 0,0 -0.9,9.5 9.1,9.1 0,0 0,7.8 5.3,9.1 9.1,0 0,0 8.2,-4.5zM976,159.6c3.2,-6.7 6.3,-13.5 9.4,-20.3 1.7,-4.4 0.1,-9.6 -3.8,-11.8 -3.9,-2.2 -8.6,-0.6 -10.7,3.6a795.9,795.9 0,0 1,-9.1 19.9c-2.1,4.4 -0.6,10 3.3,12.4 3.9,2.4 8.8,0.7 11,-3.7z"
|
||||||
|
android:fillColor="#CCCCCC"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M651.1,88.5C626.7,88.5 606.8,68.6 606.8,44.2S626.7,0 651.1,0 695.3,19.8 695.3,44.2 675.5,88.5 651.1,88.5zM651.1,16.3A28,28 0,0 0,623.1 44.2c0,15.4 12.5,28 28,28A28,28 0,0 0,679.1 44.2,28 28,0 0,0 651.1,16.3z"
|
||||||
|
android:fillColor="#D8D8D8"/>
|
||||||
|
</vector>
|
||||||
170
app/src/main/res/drawable/ic_launcher_background.xml
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path
|
||||||
|
android:fillColor="#3DDC84"
|
||||||
|
android:pathData="M0,0h108v108h-108z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M9,0L9,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,0L19,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,0L29,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,0L39,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,0L49,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,0L59,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,0L69,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,0L79,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M89,0L89,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M99,0L99,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,9L108,9"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,19L108,19"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,29L108,29"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,39L108,39"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,49L108,49"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,59L108,59"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,69L108,69"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,79L108,79"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,89L108,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,99L108,99"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,29L89,29"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,39L89,39"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,49L89,49"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,59L89,59"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,69L89,69"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,79L89,79"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,19L29,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,19L39,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,19L49,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,19L59,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,19L69,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,19L79,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
</vector>
|
||||||
30
app/src/main/res/drawable/ic_launcher_foreground.xml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient
|
||||||
|
android:endX="85.84757"
|
||||||
|
android:endY="92.4963"
|
||||||
|
android:startX="42.9492"
|
||||||
|
android:startY="49.59793"
|
||||||
|
android:type="linear">
|
||||||
|
<item
|
||||||
|
android:color="#44000000"
|
||||||
|
android:offset="0.0" />
|
||||||
|
<item
|
||||||
|
android:color="#00000000"
|
||||||
|
android:offset="1.0" />
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:strokeColor="#00000000" />
|
||||||
|
</vector>
|
||||||
9
app/src/main/res/drawable/icon_favorite_selected.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="64dp"
|
||||||
|
android:height="64dp"
|
||||||
|
android:viewportWidth="1024"
|
||||||
|
android:viewportHeight="1024">
|
||||||
|
<path
|
||||||
|
android:pathData="M910.9,364.8l-1.3,-10.1a237,237 0,0 0,-6.2 -28,201.4 201.4,0 0,0 -42.6,-80 46.1,46.1 0,0 0,-3.8 -4.5,212 212,0 0,0 -160,-71.7c-75.7,0 -146.7,29.8 -185.1,74.1 -38.4,-44.3 -109.6,-74.1 -185.1,-74.1a212,212 0,0 0,-160 71.7,46.1 46.1,0 0,0 -3.8,4.5 201.4,201.4 0,0 0,-42.6 80,237 237,0 0,0 -6.2,28l-1.3,10.1A186.4,186.4 0,0 0,112 385.9a205.3,205.3 0,0 0,1.1 21.3c16,194.1 368,423.2 382.9,433l16,10.4 16,-10.4c15,-9.6 367,-238.7 382.9,-433a205.3,205.3 0,0 0,1.1 -21.3,186.4 186.4,0 0,0 -1.1,-21.1z"
|
||||||
|
android:fillColor="@color/favorite_red"/>
|
||||||
|
</vector>
|
||||||
9
app/src/main/res/drawable/icon_favorite_unselected.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="64dp"
|
||||||
|
android:height="64dp"
|
||||||
|
android:viewportWidth="1024"
|
||||||
|
android:viewportHeight="1024">
|
||||||
|
<path
|
||||||
|
android:pathData="M908.8,214.4c-9.6,-12.8 -19.2,-22.4 -28.8,-32 -112,-115.2 -230.4,-105.6 -342.4,-16 -9.6,6.4 -19.2,16 -28.8,25.6 -9.6,-9.6 -19.2,-16 -28.8,-25.6 -112,-86.4 -230.4,-99.2 -342.4,16 -9.6,9.6 -19.2,19.2 -25.6,32 -134.4,195.2 -60.8,387.2 137.6,560 44.8,38.4 89.6,73.6 137.6,102.4 16,9.6 32,19.2 44.8,28.8 9.6,6.4 12.8,9.6 19.2,9.6 3.2,3.2 6.4,3.2 12.8,6.4 3.2,3.2 9.6,3.2 16,6.4 25.6,6.4 64,3.2 89.6,-12.8 3.2,0 9.6,-3.2 16,-9.6 12.8,-6.4 28.8,-16 44.8,-28.8 48,-28.8 92.8,-64 137.6,-102.4 201.6,-176 275.2,-368 140.8,-560zM736,732.8c-41.6,35.2 -86.4,70.4 -131.2,99.2 -16,9.6 -28.8,19.2 -44.8,25.6 -6.4,3.2 -12.8,6.4 -16,9.6 -6.4,3.2 -16,6.4 -25.6,9.6h-28.8s-3.2,0 -3.2,-3.2c-3.2,0 -6.4,-3.2 -9.6,-3.2 -3.2,-3.2 -9.6,-6.4 -16,-9.6 -12.8,-6.4 -28.8,-16 -44.8,-25.6 -44.8,-28.8 -89.6,-60.8 -131.2,-99.2C105.6,576 41.6,412.8 153.6,246.4c6.4,-9.6 16,-16 22.4,-25.6 89.6,-96 182.4,-86.4 275.2,-12.8 9.6,6.4 16,12.8 22.4,19.2l28.8,32 6.4,6.4 16,-16c12.8,-12.8 25.6,-25.6 41.6,-38.4C659.2,137.6 752,128 841.6,224c6.4,9.6 16,16 22.4,25.6 118.4,156.8 54.4,323.2 -128,483.2z"
|
||||||
|
android:fillColor="@color/white"/>
|
||||||
|
</vector>
|
||||||
27
app/src/main/res/drawable/main_gradient_border.xml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<!-- 外层:渐变填充 -->
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<gradient
|
||||||
|
android:startColor="#FF5722"
|
||||||
|
android:endColor="#03A9F4"
|
||||||
|
android:angle="0" />
|
||||||
|
<corners android:radius="16dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<!-- 内层:中间透明(留出边框) -->
|
||||||
|
<item
|
||||||
|
android:left="4dp"
|
||||||
|
android:top="4dp"
|
||||||
|
android:right="4dp"
|
||||||
|
android:bottom="4dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="@android:color/transparent" />
|
||||||
|
<corners android:radius="12dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</layer-list>
|
||||||
9
app/src/main/res/drawable/main_tab_selected.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners android:radius="8dp" />
|
||||||
|
<gradient
|
||||||
|
android:endColor="@color/main_FF7FED"
|
||||||
|
android:startColor="@color/main_536DFF" />
|
||||||
|
|
||||||
|
</shape>
|
||||||
6
app/src/main/res/drawable/main_tab_selector.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_selected="true" android:drawable="@drawable/main_tab_selected"/>
|
||||||
|
<item android:drawable="@drawable/main_tab_unselect"/>
|
||||||
|
|
||||||
|
</selector>
|
||||||
7
app/src/main/res/drawable/main_tab_unselect.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners android:radius="8dp" />
|
||||||
|
<solid android:color="@color/main_sub_color" />
|
||||||
|
|
||||||
|
</shape>
|
||||||
21
app/src/main/res/drawable/splash_progress_drawable.xml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:id="@android:id/background">
|
||||||
|
<shape>
|
||||||
|
<corners android:radius="5dp" />
|
||||||
|
<solid android:color="@color/main_sub_color" /> <!-- 背景颜色 -->
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item android:id="@android:id/progress">
|
||||||
|
<clip>
|
||||||
|
<shape>
|
||||||
|
<corners android:radius="20dp" />
|
||||||
|
<gradient
|
||||||
|
android:angle="0"
|
||||||
|
android:endColor="@color/main_FF7FED"
|
||||||
|
android:startColor="@color/main_536DFF" />
|
||||||
|
</shape>
|
||||||
|
</clip>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
25
app/src/main/res/drawable/thumbnail_placeholder.xml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="256dp"
|
||||||
|
android:height="256dp"
|
||||||
|
android:viewportWidth="1024"
|
||||||
|
android:viewportHeight="1024">
|
||||||
|
<path
|
||||||
|
android:pathData="M972.8,0a51.2,51.2 0,0 1,51.2 51.2v921.6a51.2,51.2 0,0 1,-51.2 51.2H51.2a51.2,51.2 0,0 1,-51.2 -51.2V51.2a51.2,51.2 0,0 1,51.2 -51.2h921.6z"
|
||||||
|
android:fillColor="#BEBEBE"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M755.2,448L1024,716.8v256a51.2,51.2 0,0 1,-51.2 51.2H51.2a51.2,51.2 0,0 1,-51.2 -51.2v-113.2l294.4,-294.4 171.8,171.8L755.2,448z"
|
||||||
|
android:strokeAlpha="0.694"
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:fillAlpha="0.694"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M332.8,332.8m-102.4,0a102.4,102.4 0,1 0,204.8 0,102.4 102.4,0 1,0 -204.8,0Z"
|
||||||
|
android:strokeAlpha="0.694"
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:fillAlpha="0.694"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M972.8,0a51.2,51.2 0,0 1,51.2 51.2v921.6a51.2,51.2 0,0 1,-51.2 51.2L51.2,1024a51.2,51.2 0,0 1,-51.2 -51.2L0,51.2a51.2,51.2 0,0 1,51.2 -51.2h921.6zM870.4,153.6L153.6,153.6v716.8h716.8L870.4,153.6z"
|
||||||
|
android:fillColor="#FFFFFF"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M972.8,0a51.2,51.2 0,0 1,51.2 51.2v921.6a51.2,51.2 0,0 1,-51.2 51.2L51.2,1024a51.2,51.2 0,0 1,-51.2 -51.2L0,51.2a51.2,51.2 0,0 1,51.2 -51.2h921.6zM972.8,25.6L51.2,25.6a25.6,25.6 0,0 0,-25.4 22.6L25.6,51.2v921.6a25.6,25.6 0,0 0,22.6 25.4L51.2,998.4h921.6a25.6,25.6 0,0 0,25.4 -22.6L998.4,972.8L998.4,51.2a25.6,25.6 0,0 0,-22.6 -25.4L972.8,25.6z"
|
||||||
|
android:fillColor="#D9D9D9"/>
|
||||||
|
</vector>
|
||||||
190
app/src/main/res/layout/activity_display_video.xml
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/main"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".preview.DisplayVideoActivity">
|
||||||
|
|
||||||
|
|
||||||
|
<androidx.media3.ui.PlayerView
|
||||||
|
android:id="@+id/player_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:background="@color/white"
|
||||||
|
app:resize_mode="zoom"
|
||||||
|
app:show_buffering="never"
|
||||||
|
app:show_shuffle_button="false"
|
||||||
|
app:show_subtitle_button="false"
|
||||||
|
app:show_vr_button="false"
|
||||||
|
app:use_controller="false" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/image_thumbnail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/loading_bg_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/white_BFFFFFFF"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:visibility="visible">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/download_progress_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:lineSpacingExtra="4dp"
|
||||||
|
android:text="@string/wait_patiently"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/horizontal_progressbar"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:layout_width="270dp"
|
||||||
|
android:layout_height="4dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:max="100"
|
||||||
|
android:progress="100"
|
||||||
|
android:progressDrawable="@drawable/splash_progress_drawable" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/normal_progress"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:indeterminateTint="@color/main_536DFF"
|
||||||
|
android:visibility="visible" />
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/retry_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_load_fail"
|
||||||
|
android:layout_width="320dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:lineSpacingExtra="4dp"
|
||||||
|
android:text="@string/download_fail_network"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_retry_button"
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:background="@drawable/main_gradient_border"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/retry"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_video_describe"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:padding="9dp"
|
||||||
|
android:text="Eternal hues dance in the void's embrace 🎗️"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="@drawable/common_set_wallpaper_bg"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/layout_btn"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_btn"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:layout_marginBottom="25dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_btn_set"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/common_set_wallpaper_bg"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingStart="11dp"
|
||||||
|
android:paddingTop="9dp"
|
||||||
|
android:paddingEnd="11dp"
|
||||||
|
android:paddingBottom="9dp"
|
||||||
|
android:text="@string/set_wallpaper"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/framelayout_favorite"
|
||||||
|
android:layout_width="45dp"
|
||||||
|
android:layout_height="45dp"
|
||||||
|
android:layout_marginStart="9dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:background="@drawable/common_back_button_bg">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/im_favorite"
|
||||||
|
android:layout_width="26dp"
|
||||||
|
android:layout_height="26dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:src="@drawable/display_selector_favorite" />
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/back_btn"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="15dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:background="@drawable/common_back_button_bg"
|
||||||
|
android:padding="8dp"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="22dp"
|
||||||
|
android:layout_height="22dp"
|
||||||
|
android:src="@drawable/common_back_button" />
|
||||||
|
</FrameLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
65
app/src/main/res/layout/activity_favorite.xml
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/main"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".favorite.FavoriteActivity">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/image_back"
|
||||||
|
android:layout_width="42dp"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:src="@drawable/common_back_button"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/favorite"
|
||||||
|
android:textSize="17sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/image_back"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/image_back" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/favorite_recyclerview"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/image_back" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_empty"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="115dp"
|
||||||
|
android:layout_height="115dp"
|
||||||
|
android:src="@drawable/empty_favorite" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:text="@string/empty_text"
|
||||||
|
android:textColor="@color/gray"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
86
app/src/main/res/layout/activity_main.xml
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/main"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".main.MainActivity">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_view_name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="45dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/app_name"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="45dp"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/text_view_name"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:id="@+id/favorite_btn"
|
||||||
|
android:src="@drawable/icon_favorite_selected"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_1_explore"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="45dp"
|
||||||
|
android:layout_marginStart="15dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:background="@drawable/main_tab_selector"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/tab1_explore"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="15sp"
|
||||||
|
app:layout_constraintHorizontal_weight="1"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/text_2_shift"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/text_view_name" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_2_shift"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="45dp"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:background="@drawable/main_tab_selector"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/tab2_shift"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="15sp"
|
||||||
|
app:layout_constraintHorizontal_weight="1"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/text_1_explore"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/text_3_trending"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/text_1_explore" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_3_trending"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="45dp"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:background="@drawable/main_tab_selector"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/tab3_trending"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="15sp"
|
||||||
|
app:layout_constraintHorizontal_weight="1"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/text_2_shift"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/text_1_explore" />
|
||||||
|
|
||||||
|
|
||||||
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:id="@+id/viewpager2"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/text_1_explore" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
58
app/src/main/res/layout/activity_splash.xml
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/main"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".SplashActivity">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/image_logo"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="200dp"
|
||||||
|
android:src="@mipmap/logo"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
android:text="@string/app_name"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="17sp"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/image_logo" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_bar"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="18dp"
|
||||||
|
android:layout_marginStart="26dp"
|
||||||
|
android:layout_marginEnd="26dp"
|
||||||
|
android:layout_marginBottom="55dp"
|
||||||
|
android:max="100"
|
||||||
|
android:progress="1"
|
||||||
|
android:progressDrawable="@drawable/splash_progress_drawable"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textview_progress"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="1%"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="13sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/progress_bar"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/progress_bar" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
16
app/src/main/res/layout/favorite_adapter.xml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
|
||||||
|
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||||
|
android:id="@+id/thumbnail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="200dp"
|
||||||
|
android:src="@mipmap/logo"
|
||||||
|
app:roundPercent="0.1" />
|
||||||
|
</LinearLayout>
|
||||||
13
app/src/main/res/layout/fragment_main.xml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".main.MainFragment">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:id="@+id/recycler_view" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
20
app/src/main/res/layout/main_adapter.xml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:id="@+id/view_placeholder"/>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||||
|
android:id="@+id/thumbnail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="200dp"
|
||||||
|
android:src="@mipmap/logo"
|
||||||
|
app:roundPercent="0.1" />
|
||||||
|
</LinearLayout>
|
||||||
6
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_background" />
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
</adaptive-icon>
|
||||||
6
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_background" />
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
</adaptive-icon>
|
||||||
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 982 B |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/logo.png
Normal file
|
After Width: | Height: | Size: 92 KiB |
7
app/src/main/res/values-night/themes.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="Base.Theme.DynamicCartoonWallpaper" parent="Theme.Material3.DayNight.NoActionBar">
|
||||||
|
<!-- Customize your dark theme here. -->
|
||||||
|
<!-- <item name="colorPrimary">@color/my_dark_primary</item> -->
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
13
app/src/main/res/values/colors.xml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="black">#FF000000</color>
|
||||||
|
<color name="white">#FFFFFFFF</color>
|
||||||
|
<color name="main_sub_color">#70D7D6D6</color>
|
||||||
|
<color name="main_D4E7FF">#D4E7FF</color>
|
||||||
|
<color name="main_FFEFFC">#FFEFFC</color>
|
||||||
|
<color name="main_536DFF">#536DFF</color>
|
||||||
|
<color name="main_FF7FED">#FF7FED</color>
|
||||||
|
<color name="white_BFFFFFFF">#BFFFFFFF</color>
|
||||||
|
<color name="favorite_red">#CA1919</color>
|
||||||
|
<color name="gray">#C8C6C6</color>
|
||||||
|
</resources>
|
||||||
17
app/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="app_name">Dynamic Cartoon Wallpaper</string>
|
||||||
|
<string name="splash_progress_text">%d%%</string>
|
||||||
|
<string name="tab1_explore">Explore</string>
|
||||||
|
<string name="tab2_shift">Shift</string>
|
||||||
|
<string name="tab3_trending">Trending</string>
|
||||||
|
<string name="download_fail_network">Loading failed, please check the network and try again</string>
|
||||||
|
<string name="download_fail_unknown">Some unknown errors occurred during playing, please try again later</string>
|
||||||
|
<string name="retry">Retry</string>
|
||||||
|
<string name="wait_patiently">Downloading video, please wait patiently</string>
|
||||||
|
<string name="set_wallpaper">Set Wallpaper</string>
|
||||||
|
<string name="favorite">Favorite</string>
|
||||||
|
<string name="empty_text">Go collect your favorite wallpapers</string>
|
||||||
|
<string name="remove_favorite_ok">Successfully canceled the collection</string>
|
||||||
|
<string name="remove_favorite_fail">Failed to cancel collection</string>
|
||||||
|
<string name="cache_file_no_lost">The resource is lost, please re-enter this page</string>
|
||||||
|
</resources>
|
||||||
16
app/src/main/res/values/themes.xml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="Base.Theme.DynamicCartoonWallpaper" parent="Theme.Material3.DayNight.NoActionBar">
|
||||||
|
<!-- Customize your light theme here. -->
|
||||||
|
<!-- <item name="colorPrimary">@color/my_light_primary</item> -->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Theme.DynamicCartoonWallpaper" parent="Base.Theme.DynamicCartoonWallpaper" />
|
||||||
|
|
||||||
|
<!-- <style name="Theme.MyApp.Splash" parent="Theme.SplashScreen">-->
|
||||||
|
<!-- <item name="windowSplashScreenBackground">@color/white</item>-->
|
||||||
|
<!-- <item name="windowSplashScreenAnimatedIcon">@mipmap/logo</item>-->
|
||||||
|
<!-- <item name="postSplashScreenTheme">@style/Theme.DynamicCartoonWallpaper</item>-->
|
||||||
|
<!-- </style>-->
|
||||||
|
|
||||||
|
</resources>
|
||||||
13
app/src/main/res/xml/backup_rules.xml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
Sample backup rules file; uncomment and customize as necessary.
|
||||||
|
See https://developer.android.com/guide/topics/data/autobackup
|
||||||
|
for details.
|
||||||
|
Note: This file is ignored for devices older than API 31
|
||||||
|
See https://developer.android.com/about/versions/12/backup-restore
|
||||||
|
-->
|
||||||
|
<full-backup-content>
|
||||||
|
<!--
|
||||||
|
<include domain="sharedpref" path="."/>
|
||||||
|
<exclude domain="sharedpref" path="device.xml"/>
|
||||||
|
-->
|
||||||
|
</full-backup-content>
|
||||||
19
app/src/main/res/xml/data_extraction_rules.xml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
Sample data extraction rules file; uncomment and customize as necessary.
|
||||||
|
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
|
||||||
|
for details.
|
||||||
|
-->
|
||||||
|
<data-extraction-rules>
|
||||||
|
<cloud-backup>
|
||||||
|
<!-- TODO: Use <include> and <exclude> to control what is backed up.
|
||||||
|
<include .../>
|
||||||
|
<exclude .../>
|
||||||
|
-->
|
||||||
|
</cloud-backup>
|
||||||
|
<!--
|
||||||
|
<device-transfer>
|
||||||
|
<include .../>
|
||||||
|
<exclude .../>
|
||||||
|
</device-transfer>
|
||||||
|
-->
|
||||||
|
</data-extraction-rules>
|
||||||
8
app/src/main/res/xml/file_paths.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- 允许访问应用的内部存储文件 -->
|
||||||
|
<files-path name="internal_files" path="." />
|
||||||
|
<cache-path name="inner_app_cache" path="." />
|
||||||
|
<!-- 允许访问应用的外部存储文件(如果有的话) -->
|
||||||
|
<external-path name="external_files" path="." />
|
||||||
|
</paths>
|
||||||
5
app/src/main/res/xml/video_wallpaper.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<wallpaper xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:description="@string/app_name"
|
||||||
|
android:thumbnail="@mipmap/logo">
|
||||||
|
</wallpaper>
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package com.video.mobile.wallpaper
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
import org.junit.Assert.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
|
*
|
||||||
|
* See [testing documentation](http://d.android.com/tools/testing).
|
||||||
|
*/
|
||||||
|
class ExampleUnitTest {
|
||||||
|
@Test
|
||||||
|
fun addition_isCorrect() {
|
||||||
|
assertEquals(4, 2 + 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
10
build.gradle.kts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
plugins {
|
||||||
|
alias(libs.plugins.android.application) apply false
|
||||||
|
alias(libs.plugins.kotlin.android) apply false
|
||||||
|
}
|
||||||
|
buildscript {
|
||||||
|
dependencies {
|
||||||
|
classpath("io.objectbox:objectbox-gradle-plugin:4.0.3")
|
||||||
|
}
|
||||||
|
}
|
||||||
23
gradle.properties
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Project-wide Gradle settings.
|
||||||
|
# IDE (e.g. Android Studio) users:
|
||||||
|
# Gradle settings configured through the IDE *will override*
|
||||||
|
# any settings specified in this file.
|
||||||
|
# For more details on how to configure your build environment visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
|
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
||||||
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
|
# This option should only be used with decoupled projects. For more details, visit
|
||||||
|
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
|
||||||
|
# org.gradle.parallel=true
|
||||||
|
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||||
|
# Android operating system, and which are packaged with your app's APK
|
||||||
|
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||||
|
android.useAndroidX=true
|
||||||
|
# Kotlin code style for this project: "official" or "obsolete":
|
||||||
|
kotlin.code.style=official
|
||||||
|
# Enables namespacing of each library's R class so that its R class includes only the
|
||||||
|
# resources declared in the library itself and none from the library's dependencies,
|
||||||
|
# thereby reducing the size of the R class for that library
|
||||||
|
android.nonTransitiveRClass=true
|
||||||
26
gradle/libs.versions.toml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
[versions]
|
||||||
|
agp = "8.10.1"
|
||||||
|
kotlin = "2.0.21"
|
||||||
|
coreKtx = "1.16.0"
|
||||||
|
junit = "4.13.2"
|
||||||
|
junitVersion = "1.3.0"
|
||||||
|
espressoCore = "3.7.0"
|
||||||
|
appcompat = "1.7.1"
|
||||||
|
material = "1.12.0"
|
||||||
|
activity = "1.10.1"
|
||||||
|
constraintlayout = "2.2.1"
|
||||||
|
|
||||||
|
[libraries]
|
||||||
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
|
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||||
|
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||||
|
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||||
|
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
||||||
|
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||||
|
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
|
||||||
|
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
|
||||||
|
|
||||||
|
[plugins]
|
||||||
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
|
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||||
|
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#Wed Aug 13 18:04:51 CST 2025
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
185
gradlew
vendored
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2015 the original author or authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=`expr $i + 1`
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
0) set -- ;;
|
||||||
|
1) set -- "$args0" ;;
|
||||||
|
2) set -- "$args0" "$args1" ;;
|
||||||
|
3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save () {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=`save "$@"`
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
89
gradlew.bat
vendored
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
6
keystore.properties
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
app_name=Dynamic Cartoon Wallpaper
|
||||||
|
package_name=com.video.mobile.wallpaper
|
||||||
|
keystoreFile=app/DynamicCartoonWallpaper.jks
|
||||||
|
key_alias=DynamicCartoonWallpaperkey0
|
||||||
|
key_store_password=DynamicCartoonWallpaper
|
||||||
|
key_password=DynamicCartoonWallpaper
|
||||||
24
settings.gradle.kts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
google {
|
||||||
|
content {
|
||||||
|
includeGroupByRegex("com\\.android.*")
|
||||||
|
includeGroupByRegex("com\\.google.*")
|
||||||
|
includeGroupByRegex("androidx.*")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mavenCentral()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dependencyResolutionManagement {
|
||||||
|
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "Dynamic Cartoon Wallpaper"
|
||||||
|
include(":app")
|
||||||
|
|
||||||