V1.0.0(1) 无Ad版本

This commit is contained in:
litingting 2024-04-16 18:19:58 +08:00
commit 2b9c7cf257
89 changed files with 5336 additions and 0 deletions

17
.gitignore vendored Normal file
View File

@ -0,0 +1,17 @@
*.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
.idea/
app/release/

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

BIN
app/LiveWallpaper.jks Normal file

Binary file not shown.

3
app/SignInfo Normal file
View File

@ -0,0 +1,3 @@
签名文件:LiveWallpaper.jks
别名:LiveWallpaperkey0
密码:LiveWallpaper

90
app/build.gradle.kts Normal file
View File

@ -0,0 +1,90 @@
import java.util.Date
import java.text.SimpleDateFormat
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}
val timestamp = SimpleDateFormat("MM_dd_HH_mm").format(Date())
android {
namespace = "com.live.wallpaper.style.hd"
compileSdk = 34
defaultConfig {
applicationId = "com.live.wallpaper.style.hd"
minSdk = 23
targetSdk = 34
versionCode = 1
versionName = "1.0.0"
setProperty("archivesBaseName", "Live Wallpaper_V" + versionName + "(${versionCode})_$timestamp")
testInstrumentationRunner = "androidx.hd.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
}
buildTypes {
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
compose = true
viewBinding = true
buildConfig = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.4.3"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}
dependencies {
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.activity:activity-compose:1.8.2")
implementation(libs.core.ktx)
implementation(libs.appcompat)
implementation(libs.material)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.test.ext.junit)
androidTestImplementation(libs.espresso.core)
// MultiDexApplication
implementation(libs.androidx.multidex)
//Glide
implementation(libs.glide)
// viewModel
implementation(libs.lifecycle.viewmodel.ktx)
//viewModel初始化用
implementation(libs.activity.ktx)
implementation(libs.fragment.ktx)
// RxBinding
implementation(libs.jakewharton.rxbinding4)
// smart refresh layout
implementation(libs.smart.refresh.kernel)
implementation(libs.smart.refresh.material.header)
implementation(libs.smart.refresh.classics.footer)
implementation(libs.okhttp3.okhttp)
implementation(libs.commons.codec)
// progress bar
implementation(libs.com.akexorcist.progress.bar)
}

33
app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,33 @@
# 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
-keep class com.live.wallpaper.style.hd.bean.WallpaperImage { *; }
-keep class com.live.wallpaper.style.hd.bean.WallpaperImageListBean { *; }
-dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.bouncycastle.jsse.BCSSLSocket
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
-dontwarn org.conscrypt.Conscrypt$Version
-dontwarn org.conscrypt.Conscrypt
-dontwarn org.conscrypt.ConscryptHostnameVerifier
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
-dontwarn org.openjsse.net.ssl.OpenJSSE

View File

@ -0,0 +1,24 @@
package com.live.wallpaper.style.hd
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 hd, 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 hd.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.live.wallpaper.style.hd", appContext.packageName)
}
}

View File

@ -0,0 +1,47 @@
<?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" />
<application
android:name=".LiveWallpaper"
android:allowBackup="true"
android:usesCleartextTraffic="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/live_logo"
android:label="@string/app_name"
android:roundIcon="@mipmap/live_logo"
android:supportsRtl="true"
android:theme="@style/Theme.LiveWallpaper"
tools:targetApi="31">
<activity
android:name=".actandfrag.FirstActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.LiveWallpaper">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".myliveservice.LiveService"
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/wallpaper" />
</service>
<activity android:name=".actandfrag.MainActivity"/>
<activity android:name=".actandfrag.PreVideoActivity"/>
</application>
</manifest>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
package com.live.wallpaper.style.hd
import androidx.multidex.MultiDexApplication
import com.live.wallpaper.style.hd.mytools.WallpaperDataUtil
class LiveWallpaper : MultiDexApplication() {
companion object {
lateinit var app: LiveWallpaper
const val URL_TAG = "url_tag"
const val KEY_EXTRA_LIST = "key_extra_list"
const val URL_Video = "url_video"
const val KEY_EXTRA__POS = "key_extra_pos"
}
override fun onCreate() {
super.onCreate()
app = this
WallpaperDataUtil.assestGet()
}
}

View File

@ -0,0 +1,111 @@
package com.live.wallpaper.style.hd.actandfrag
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.fragment.app.DialogFragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.live.wallpaper.style.hd.databinding.FragmentContactBinding
import com.live.wallpaper.style.hd.recycleradapter.AdapterStar
class ContactFragment() : DialogFragment() {
private lateinit var binding: FragmentContactBinding
private lateinit var mAdapter: AdapterStar
companion object {
val EXTRA_KEY = "task"
val ADD_TASK_TYPE_KEY = "add_task_type_key"
@JvmStatic
fun newInstance(param1: Int, param2: Int) =
ContactFragment().apply {
arguments = Bundle().apply {
putInt(EXTRA_KEY, param1)
putInt(ADD_TASK_TYPE_KEY, param2)
}
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentContactBinding.inflate(layoutInflater)
return binding.root
}
override fun onStart() {
super.onStart()
dialog?.run {
setCanceledOnTouchOutside(false)
setCancelable(false)
window?.run {
attributes = attributes.apply {
gravity = Gravity.CENTER
width = WindowManager.LayoutParams.WRAP_CONTENT
height = WindowManager.LayoutParams.WRAP_CONTENT
}
}
val decorView = window!!.decorView
decorView.setPadding(0, 0, 0, 0)
decorView.background = ColorDrawable(Color.TRANSPARENT)
}
init()
}
private fun goRate() {
val intent = Intent("android.intent.action.VIEW")
val stringBuilder = "https://play.google.com/store/apps/details?id=${requireContext().packageName}"
intent.data = Uri.parse(stringBuilder)
startActivity(intent)
}
private fun init() {
binding.run {
mAdapter = AdapterStar(requireContext()) {
tvRateIt.run {
isSelected = true
isClickable = true
}
}
recyclerStart.apply {
adapter = mAdapter
layoutManager = LinearLayoutManager(requireContext()).apply {
orientation = LinearLayoutManager.HORIZONTAL
}
}
tvRateIt.run {
isSelected = false
isClickable = false
}
tvCancel.setOnClickListener { dismiss() }
tvRateIt.setOnClickListener {
mAdapter.getRate()?.let {
if (it >= 3) {
goRate()
dismiss()
} else {
dismiss()
}
}
}
}
}
}

View File

@ -0,0 +1,37 @@
package com.live.wallpaper.style.hd.actandfrag
import android.content.Intent
import android.view.View
import com.live.wallpaper.style.hd.databinding.ActFirstBinding
import com.live.wallpaper.style.hd.mytools.Common.countDown
class FirstActivity : ParentActivity() {
private lateinit var binding: ActFirstBinding
private var countTime = 2
override fun getContentView(): View {
binding = ActFirstBinding.inflate(layoutInflater)
return binding.root
}
override fun initViews() {
super.initViews()
startCountDown()
}
private fun startCountDown() {
countDown(countTime, start = {
}, next = {
}) {
intoMain()
}
}
private fun intoMain() {
if (!isFinishing) {
startActivity(Intent(this, MainActivity::class.java))
finish()
}
}
}

View File

@ -0,0 +1,110 @@
package com.live.wallpaper.style.hd.actandfrag
import android.content.Intent
import android.view.View
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import com.live.wallpaper.style.hd.LiveWallpaper
import com.live.wallpaper.style.hd.bean.WallpaperImage
import com.live.wallpaper.style.hd.bean.WallpaperImageListBean
import com.live.wallpaper.style.hd.databinding.FragmentWallpaperBinding
import com.live.wallpaper.style.hd.recycleradapter.AdapterWall
import com.live.wallpaper.style.hd.mytools.SpaceDecoration
import com.live.wallpaper.style.hd.mytools.Common.onMain
import com.live.wallpaper.style.hd.viewm.WallpaperViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class InfoFragment : ParentFragment() {
private lateinit var binding: FragmentWallpaperBinding
private val mViewModel: WallpaperViewModel by viewModels()
private var mAdapter: AdapterWall? = null
private var mList: MutableList<WallpaperImage> = mutableListOf()
private var mCurPos: Int = -1
companion object {
private const val ARG_TAG = "arg_tag"
fun newInstance(): InfoFragment {
val fragment = InfoFragment()
return fragment
}
}
override fun getContentView(): View {
binding = FragmentWallpaperBinding.inflate(layoutInflater)
return binding.root
}
override fun initViews() {
super.initViews()
mAdapter = AdapterWall(requireActivity(), mList)
mAdapter?.setOnItemClickListener(object :
AdapterWall.OnItemClickListener {
override fun onItemClick(pos: Int) {
toPreview(pos)
}
})
binding.rv.layoutManager = GridLayoutManager(requireActivity(), 2)
binding.rv.addItemDecoration(
SpaceDecoration(4, 16)
)
binding.rv.adapter = mAdapter!!
binding.refreshLayout.setOnRefreshListener {
mCurPos = -1
if (mViewModel.isLoading.get()) {
return@setOnRefreshListener
}
lifecycleScope.launch(Dispatchers.IO) {
mViewModel.updateWallpaper()
}
}
binding.refreshLayout.setOnLoadMoreListener {
mCurPos = -1
if (mViewModel.isLoading.get()) {
return@setOnLoadMoreListener
}
mViewModel.loadWallpaper()
}
mViewModel.getData().observe(this) { list ->
mList.clear()
mList.addAll(list)
onMain {
binding.refreshLayout.finishRefresh()
binding.refreshLayout.finishLoadMore()
mAdapter?.notifyDataSetChanged()
}
}
if (!reCreated) {
lifecycleScope.launch(Dispatchers.IO) {
mViewModel.updateWallpaper()
}
}
}
private fun toPreview(pos: Int) {
mCurPos = pos
if (activity != null) {
val intent = Intent(requireActivity(), PreVideoActivity::class.java)
val listBean = WallpaperImageListBean()
listBean.list = mList
intent.putExtra(LiveWallpaper.KEY_EXTRA_LIST, listBean)
intent.putExtra(LiveWallpaper.KEY_EXTRA__POS, pos)
startActivity(intent)
}
}
}

View File

@ -0,0 +1,81 @@
package com.live.wallpaper.style.hd.actandfrag
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.viewpager.widget.ViewPager
import com.live.wallpaper.style.hd.databinding.ActivityMainBinding
import com.live.wallpaper.style.hd.mytools.Common.throttleClicks
class MainActivity : ParentActivity() {
private lateinit var binding: ActivityMainBinding
private val mFragments: MutableList<Fragment> = ArrayList()
override fun getContentView(): View {
binding = ActivityMainBinding.inflate(layoutInflater)
return binding.root
}
override fun initViews() {
super.initViews()
updateTab(0)
setViewPager()
binding.llHome.throttleClicks {
binding.viewPager.currentItem = 0
}
binding.llSettings.throttleClicks {
binding.viewPager.currentItem = 1
}
}
private fun updateTab(index: Int) {
when (index) {
0 -> {
binding.ivHome.isSelected = true
binding.ivSettings.isSelected = false
}
1 -> {
binding.ivHome.isSelected = false
binding.ivSettings.isSelected = true
}
}
}
private fun setViewPager() {
mFragments.add(InfoFragment.newInstance())
mFragments.add(SetFragment())
binding.viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int
) {
}
override fun onPageSelected(position: Int) {
updateTab(position)
}
override fun onPageScrollStateChanged(state: Int) {
}
})
binding.viewPager.adapter = object : FragmentStatePagerAdapter(supportFragmentManager) {
override fun getCount(): Int {
return mFragments.size
}
override fun getItem(position: Int): Fragment {
return mFragments[position]
}
}
}
}

View File

@ -0,0 +1,59 @@
package com.live.wallpaper.style.hd.actandfrag
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import androidx.annotation.ColorInt
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
import com.live.wallpaper.style.hd.R
abstract class ParentActivity: AppCompatActivity() {
var reCreated = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStatusBarUpperAPI21(resources.getColor(R.color.white))
setContentView(getContentView())
//设置壁纸后Activity会被销毁重建但viewModel不会此处判断是否是设置壁纸重建activity执行的onCreate(),此时不展示广告
// if (mConfigurationViewModel.originalConfiguration == null) {
// mConfigurationViewModel.originalConfiguration = resources.configuration
// } else {
// val diff = resources.configuration.diff(mConfigurationViewModel.originalConfiguration)
// reCreated = (diff.toLong() and 0x80000000) != 0L
// mConfigurationViewModel.originalConfiguration = resources.configuration
// }
initViews()
}
abstract fun getContentView(): View
open fun initViews() {}
private fun setStatusBarUpperAPI21(@ColorInt color: Int) {
val window = window
//取消设置透明状态栏,使 ContentView 内容不再覆盖状态栏
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
//需要设置这个 flag 才能调用 setStatusBarColor 来设置状态栏颜色
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
//设置状态栏颜色
//由于setStatusBarColor()这个API最低版本支持21, 本人的是15,所以如果要设置颜色,自行到style中通过配置文件设置
window.statusBarColor = color
val mContentView = findViewById<View>(Window.ID_ANDROID_CONTENT) as ViewGroup
val mChildView = mContentView.getChildAt(0)
if (mChildView != null) {
//注意不是设置 ContentView 的 FitsSystemWindows, 而是设置 ContentView 的第一个子 View . 预留出系统 View 的空间.
mChildView.fitsSystemWindows = true
}
val wc = WindowCompat.getInsetsController(window, window.decorView)
wc.isAppearanceLightStatusBars = true
}
}

View File

@ -0,0 +1,39 @@
package com.live.wallpaper.style.hd.actandfrag
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
abstract class ParentFragment: Fragment() {
var reCreated = false
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return getContentView()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//设置壁纸后Activity会被销毁重建但viewModel不会此处判断是否是设置壁纸重建activity执行的onCreate(),此时不展示广告
// if (mConfigurationViewModel.originalConfiguration == null) {
// mConfigurationViewModel.originalConfiguration = resources.configuration
// } else {
// val diff = resources.configuration.diff(mConfigurationViewModel.originalConfiguration)
// reCreated = (diff.toLong() and 0x80000000) != 0L
// mConfigurationViewModel.originalConfiguration = resources.configuration
// }
initViews()
}
abstract fun getContentView(): View
open fun initViews(){
}
}

View File

@ -0,0 +1,286 @@
package com.live.wallpaper.style.hd.actandfrag
import android.app.WallpaperManager
import android.content.ComponentName
import android.content.Intent
import android.media.MediaPlayer
import android.net.Uri
import android.os.Build
import android.view.SurfaceHolder
import android.view.View
import androidx.core.view.isVisible
import androidx.viewpager2.widget.ViewPager2
import com.live.wallpaper.style.hd.LiveWallpaper
import com.live.wallpaper.style.hd.R
import com.live.wallpaper.style.hd.bean.WallpaperImage
import com.live.wallpaper.style.hd.bean.WallpaperImageListBean
import com.live.wallpaper.style.hd.customerDialog.DownDialog
import com.live.wallpaper.style.hd.databinding.ActPreLiveBinding
import com.live.wallpaper.style.hd.myliveservice.LiveService
import com.live.wallpaper.style.hd.mytools.Common.getMyStr
import com.live.wallpaper.style.hd.mytools.Common.hide
import com.live.wallpaper.style.hd.mytools.Common.onMain
import com.live.wallpaper.style.hd.mytools.Common.show
import com.live.wallpaper.style.hd.mytools.Common.throttleClicks
import com.live.wallpaper.style.hd.mytools.Sp
import com.live.wallpaper.style.hd.mytools.download.DownloadUtil
import com.live.wallpaper.style.hd.recycleradapter.AdapterLive
class PreVideoActivity : ParentActivity(){
private lateinit var binding: ActPreLiveBinding
private var mList: MutableList<WallpaperImage> = mutableListOf()
private var mImage: WallpaperImage? = null
private var mImagePagerAdapter: AdapterLive? = null
private var mCurPos: Int = 0
private var mMediaPlayer: MediaPlayer? = null
private var mDownDialog: DownDialog? = null
private var mAction = 0
override fun getContentView(): View {
binding = ActPreLiveBinding.inflate(layoutInflater)
return binding.root
}
override fun initViews() {
super.initViews()
var listBean: WallpaperImageListBean? = null
if (intent.hasExtra(LiveWallpaper.KEY_EXTRA_LIST)) {
listBean = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getSerializableExtra(LiveWallpaper.KEY_EXTRA_LIST, WallpaperImageListBean::class.java)
} else {
intent.getSerializableExtra(LiveWallpaper.KEY_EXTRA_LIST) as WallpaperImageListBean?
}
}
if (listBean == null) {
finish()
return
}
mList.clear()
mList.addAll(listBean.list)
if (mList.size == 0) {
finish()
return
}
mCurPos = intent.getIntExtra(LiveWallpaper.KEY_EXTRA__POS, 0)
mImage = mList[mCurPos]
mImagePagerAdapter = AdapterLive(this, mList)
mImagePagerAdapter?.setOnItemClickListener(object :
AdapterLive.OnItemClickListener {
override fun onItemClick(pos: Int) {
mAction = 2
if (isExist()) {
playVideo()
} else {
showDownloadDialog()
}
}
})
binding.viewPager.adapter = mImagePagerAdapter!!
binding.viewPager.setCurrentItem(mCurPos, false)
binding.viewPager.registerOnPageChangeCallback(object :
ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
mCurPos = position
mImage = mList[mCurPos]
}
})
binding.ivBack.throttleClicks {
onBackPressed()
}
binding.tvSet.throttleClicks {
if (isExist()) {
setLiveWallpaper()
} else {
showDownloadDialog()
}
}
binding.ivClose.throttleClicks {
stopHideVideo()
}
}
override fun onResume() {
super.onResume()
if (binding.flPlay.isVisible) {
try {
mMediaPlayer?.start()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
override fun onPause() {
super.onPause()
if (binding.flPlay.isVisible) {
try {
stopHideVideo()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
override fun onDestroy() {
super.onDestroy()
mDownDialog?.dismiss()
mMediaPlayer?.stop()
mMediaPlayer?.release()
mMediaPlayer = null
}
override fun onBackPressed() {
super.onBackPressed()
if (binding.flPlay.isVisible) {
stopHideVideo()
return
}
finish()
}
private fun playVideo() {
val uri = getVideoUrl() ?: return
try {
if (mMediaPlayer == null) {
mMediaPlayer = MediaPlayer()
binding.surfaceVideo.holder.addCallback(object : SurfaceHolder.Callback {
override fun surfaceCreated(holder: SurfaceHolder) {
try {
mMediaPlayer?.reset()
mMediaPlayer?.setDataSource(this@PreVideoActivity, getVideoUrl()!!)
mMediaPlayer?.setDisplay(holder)
mMediaPlayer?.isLooping = true
mMediaPlayer?.setVolume(0f, 0f)
mMediaPlayer?.setOnPreparedListener {
try {
it.start()
} catch (e: Exception) {
e.printStackTrace()
}
}
mMediaPlayer?.prepareAsync()
// mMediaPlayer?.start()
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun surfaceChanged(
holder: SurfaceHolder,
format: Int,
width: Int,
height: Int
) {
}
override fun surfaceDestroyed(holder: SurfaceHolder) {}
})
} else {
mMediaPlayer?.reset()
mMediaPlayer?.setDataSource(this@PreVideoActivity, uri)
mMediaPlayer?.isLooping = true
mMediaPlayer?.setVolume(0f, 0f)
mMediaPlayer?.prepare()
}
binding.flPlay.show()
} catch (_: Exception) {
}
}
private fun stopHideVideo() {
try {
mMediaPlayer?.stop()
} catch (e: Exception) {
e.printStackTrace()
}
binding.flPlay.hide()
}
private fun getVideoUrl(): Uri? {
val file = DownloadUtil.getFile(mImage!!.preview, mImage!!.getTag())
val uri = if (file.isFile && file.exists()) {
Uri.fromFile(file)
} else {
null
}
return uri
}
private fun setLiveWallpaper() {
mImage?.let { video ->
Sp.video_url = video.preview
Sp.video_url_tag = video.getTag()
val manager = WallpaperManager.getInstance(this@PreVideoActivity)
val cn = ComponentName(this@PreVideoActivity, LiveService::class.java)
val info = manager.wallpaperInfo
if (info == null || info.component != cn) {
try {
val intent = Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER)
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, cn)
startActivity(intent)
finish()
} catch (e: Exception) {
e.printStackTrace()
}
} else {
try {
val intent = Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER)
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, cn)
startActivity(intent)
finish()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
private fun isExist(): Boolean {
return DownloadUtil.isExist(mImage!!.preview, mImage!!.getTag())
}
private fun showDownloadDialog() {
mDownDialog = DownDialog(
this,
mutableListOf(mImage!!.preview),
mImage!!.getTag(),
R.string.loading_video.getMyStr()
) {
onDownloadSuccess = {
if (mAction == 0) {
setLiveWallpaper()
} else {
playVideo()
}
mImagePagerAdapter?.notifyItemChanged(mCurPos)
}
onDownloadFailed = {
}
}
if (!isFinishing) {
onMain {
mDownDialog?.show()
}
}
}
}

View File

@ -0,0 +1,33 @@
package com.live.wallpaper.style.hd.actandfrag
import android.content.pm.PackageManager
import android.view.View
import com.live.wallpaper.style.hd.LiveWallpaper
import com.live.wallpaper.style.hd.databinding.FragmentSettingsBinding
class SetFragment: ParentFragment() {
private lateinit var binding: FragmentSettingsBinding
override fun getContentView(): View {
binding = FragmentSettingsBinding.inflate(layoutInflater)
return binding.root
}
override fun initViews() {
super.initViews()
binding.tvVersion.text = getAppVersionName()
binding.tvRateUs.setOnClickListener {
ContactFragment.newInstance(0, 0).show(childFragmentManager,"")
}
}
fun getAppVersionName(): String {
return try {
val pm: PackageManager = LiveWallpaper.app.packageManager
val pi = pm.getPackageInfo(LiveWallpaper.app.packageName, 0)
if (pi == null) "" else pi.versionName
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
""
}
}
}

View File

@ -0,0 +1,5 @@
package com.live.wallpaper.style.hd.bean
class InfoFile(var url: String, var filePath: String? = null, var fileName: String? = null) {
}

View File

@ -0,0 +1,22 @@
package com.live.wallpaper.style.hd.bean
import java.io.Serializable
class WallpaperImage : Serializable {
var id: Long = 0
var wallpaperId: Long = 0
var title: String = ""
var thumbnail: String = ""
var category: Int = 0
var preview: String = ""
fun getTag(): String {
return "$wallpaperId"
}
}

View File

@ -0,0 +1,7 @@
package com.live.wallpaper.style.hd.bean
import java.io.Serializable
class WallpaperImageListBean: Serializable {
var list: MutableList<WallpaperImage> = mutableListOf()
}

View File

@ -0,0 +1,111 @@
package com.live.wallpaper.style.hd.customerDialog
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
import com.live.wallpaper.style.hd.R
import com.live.wallpaper.style.hd.databinding.ViewDownloadBinding
import com.live.wallpaper.style.hd.mytools.Common
import com.live.wallpaper.style.hd.mytools.Common.throttleClicks
import com.live.wallpaper.style.hd.mytools.asynchronous.asynchronousMan
import com.live.wallpaper.style.hd.mytools.download.NetListener
import com.live.wallpaper.style.hd.mytools.download.NetManager
import java.util.concurrent.atomic.AtomicInteger
class DownDialog (
private val ctx: Context,
private val urls: MutableList<String>,
private val tag: String,
private val title: String = "",
init: DownDialog.() -> Unit
) : Dialog(ctx, R.style.AppDialog) {
private lateinit var binding: ViewDownloadBinding
var onDownloadSuccess: (() -> Unit)? = null
var onDownloadFailed: (() -> Unit)? = null
private var mCount: AtomicInteger = AtomicInteger(0)
init {
init()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ViewDownloadBinding.inflate(LayoutInflater.from(ctx))
setContentView(binding.root)
val p = window!!.attributes
p.width = (Common.getScreenWidth(ctx) * 0.8).toInt() //设置dialog的宽度为当前手机屏幕的宽度*0.8
window!!.attributes = p
initViews()
}
private fun initViews() {
setCancelable(false)
setCanceledOnTouchOutside(false)
initView()
startDownload()
}
private fun initView() {
if (!TextUtils.isEmpty(title)) {
binding.tvTitle.text = title
}
binding.ivClose.throttleClicks {
dismiss()
}
}
private fun startDownload() {
binding.pbb.progress = 0f
for (url in urls) {
NetManager.instance.add(url, tag, object : NetListener {
override fun onFinished(url: String) {
if (urls.size > 1 && isShowing) {
val cur = if (mCount.get() >= urls.size - 1) {
100
} else {
(100 / urls.size) * mCount.get() + (100 / urls.size)
}
binding.pbb.progress = cur.toFloat()
binding.tvPercent.text = "$cur%"
}
mCount.incrementAndGet()
if (mCount.get() >= urls.size) {
if (isShowing) {
asynchronousMan.scheduleTaskOnUiThread(400) {
dismiss()
onDownloadSuccess?.invoke()
}
}
}
}
override fun onProgress(url: String, progress: Float) {
if (urls.size == 1 && isShowing) {
binding.pbb.progress = progress * 100
binding.tvPercent.text = "${(progress * 100).toInt()}%"
}
}
override fun onPause(url: String) {
}
override fun onCancel(url: String) {
if (isShowing) {
dismiss()
onDownloadFailed?.invoke()
}
}
})
}
asynchronousMan.scheduleTaskOnUiThread(200) {
NetManager.instance.download(urls)
}
}
}

View File

@ -0,0 +1,145 @@
package com.live.wallpaper.style.hd.myliveservice
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.media.MediaPlayer
import android.net.Uri
import android.service.wallpaper.WallpaperService
import android.util.Log
import android.view.SurfaceHolder
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.live.wallpaper.style.hd.LiveWallpaper
import com.live.wallpaper.style.hd.mytools.download.DownloadUtil
import com.live.wallpaper.style.hd.mytools.Sp
class LiveService : WallpaperService() {
companion object {
const val ACTION_SET_WALLPAPER = "LiveService"
}
private lateinit var mBroadcastManager: LocalBroadcastManager
override fun onCreate() {
super.onCreate()
Log.d("tep", "LiveService: onCreate")
mBroadcastManager = LocalBroadcastManager.getInstance(this)
}
override fun onDestroy() {
super.onDestroy()
Log.d("tep", "LiveService: onCreate")
}
override fun onCreateEngine(): Engine {
return VideoWallpaperEngine()
}
inner class VideoWallpaperEngine : WallpaperService.Engine() {
private var mMediaPlayer: MediaPlayer? = null
//LiveWallpaperService正在运行时更新替换视频
private var mReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.d("tep", "VideoWallpaperEngine: onReceive")
updateVideo()
}
}
override fun onCreate(surfaceHolder: SurfaceHolder?) {
super.onCreate(surfaceHolder)
Log.d("tep", "VideoWallpaperEngine: onCreate")
val filter = IntentFilter(ACTION_SET_WALLPAPER)
mBroadcastManager.registerReceiver(mReceiver, filter)
}
override fun onSurfaceCreated(holder: SurfaceHolder?) {
super.onSurfaceCreated(holder)
Log.d("tep", "VideoWallpaperEngine: onSurfaceCreated")
val uri = getVideoUrl()
if (uri == null) {
Log.d("tep", "onSurfaceCreated video uri is null")
return
}
mMediaPlayer = MediaPlayer.create(LiveWallpaper.app, uri)
mMediaPlayer?.setSurface(holder!!.surface)
mMediaPlayer?.isLooping = true
mMediaPlayer?.setVolume(0f, 0f)
mMediaPlayer?.start()
}
override fun onVisibilityChanged(visible: Boolean) {
super.onVisibilityChanged(visible)
Log.d(
"tep",
"VideoWallpaperEngine: onVisibilityChanged visible: $visible"
)
if (visible) {
mMediaPlayer?.start()
} else {
mMediaPlayer?.pause()
}
}
override fun onSurfaceDestroyed(holder: SurfaceHolder?) {
super.onSurfaceDestroyed(holder)
Log.d("tep", "VideoWallpaperEngine: onSurfaceDestroyed")
}
override fun onDestroy() {
super.onDestroy()
Log.d("tep", "VideoWallpaperEngine: onDestroy")
mMediaPlayer?.let {
if (it.isPlaying) {
it.stop()
}
}
mMediaPlayer?.release()
mBroadcastManager.unregisterReceiver(mReceiver)
}
override fun onSurfaceChanged(
holder: SurfaceHolder?,
format: Int,
width: Int,
height: Int
) {
super.onSurfaceChanged(holder, format, width, height)
Log.d("tep", "VideoWallpaperEngine: onSurfaceChanged")
}
private fun getVideoUrl(): Uri? {
val file = DownloadUtil.getFile(Sp.video_url, Sp.video_url_tag)
val uri = if (file.isFile && file.exists()) {
Uri.fromFile(file)
} else {
null
}
Log.d("tep", "video uri: $uri")
return uri
}
private fun updateVideo() {
Log.d("tep", "updateVideo...")
val uri = getVideoUrl()
if (uri == null) {
Log.d("tep", "updateVideo video uri is null")
return
}
//setDataSource()要结合reset()和prepare()一起用才会生效且不报错
mMediaPlayer?.reset()
// mMediaPlayer?.setSurface(surfaceHolder.surface)
mMediaPlayer?.setDataSource(this@LiveService, uri)
mMediaPlayer?.isLooping = true
mMediaPlayer?.setVolume(0f, 0f)
mMediaPlayer?.prepare()
}
}
}

View File

@ -0,0 +1,83 @@
package com.live.wallpaper.style.hd.mytools
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.jakewharton.rxbinding4.view.clicks
import com.live.wallpaper.style.hd.LiveWallpaper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import java.util.concurrent.TimeUnit
object Common {
fun onMain(operation: () -> Unit) = Handler(Looper.getMainLooper()).post(operation)
fun Int.getMyStr(): String = getCustString(this)
fun Int.dp2PxInt(): Int = dp2Px(this)
fun getCustString(resId: Int): String {
return LiveWallpaper.app.getString(resId)
}
fun dp2Px(dp: Int): Int {
val scale: Float = LiveWallpaper.app.resources.displayMetrics.density
return (dp * scale + 0.5f).toInt()
}
fun getScreenHeight(context: Context): Int {
return context.resources.displayMetrics.heightPixels
}
fun getScreenWidth(context: Context): Int {
return context.resources.displayMetrics.widthPixels
}
fun View.throttleClicks(time: Long = 1000, block: (View) -> Unit) {
this.clicks().throttleFirst(time, TimeUnit.MILLISECONDS).subscribe { block(this) }
}
fun View.show() {
this.visibility = View.VISIBLE
}
fun View.hide() {
this.visibility = View.GONE
}
fun AppCompatActivity.countDown(
time: Int = 15,
start: (scop: CoroutineScope) -> Unit,
next: (time: String) -> Unit,
end: () -> Unit
) {
lifecycleScope.launch {
flow {
(time downTo 0).forEach {
delay(1000)
emit(it)
}
}.onStart {
start(this@launch)
}.onCompletion {
end()
}.catch {
}.collect {
next(it.toString())
}
}
}
}

View File

@ -0,0 +1,48 @@
package com.live.wallpaper.style.hd.mytools
import android.content.Context
import android.content.SharedPreferences
import com.live.wallpaper.style.hd.LiveWallpaper
object Sp {
var video_url: String
get() = queryString(
LiveWallpaper.URL_Video,
""
)
set(value) {
saveString(LiveWallpaper.URL_Video, value)
}
var video_url_tag: String
get() = queryString(
LiveWallpaper.URL_TAG,
""
)
set(value) {
saveString(LiveWallpaper.URL_TAG, value)
}
private const val defaultFile = "chat_mate"
private fun read(ctx: Context, file: String? = defaultFile): SharedPreferences {
return ctx.getSharedPreferences(file, Context.MODE_PRIVATE)
}
private fun write(ctx: Context, file: String? = defaultFile): SharedPreferences.Editor {
return ctx.getSharedPreferences(file, Context.MODE_PRIVATE).edit()
}
fun saveString(key: String, value: String) {
write(LiveWallpaper.app)
.putString(key, value).apply()
}
fun queryString(key: String, defaultValue: String): String {
return read(LiveWallpaper.app)
.getString(key, defaultValue).orEmpty()
}
}

View File

@ -0,0 +1,70 @@
package com.live.wallpaper.style.hd.mytools
import android.graphics.Rect
import android.view.View
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.live.wallpaper.style.hd.mytools.Common.dp2PxInt
class SpaceDecoration : RecyclerView.ItemDecoration {
private var verticalSpacing = 0
private var horizontalSpacing = 0
private var extraSpacing = 0
var needVerticalSpacingInSingleLine = true
var needHorizontalSpacingInSingleLine = true
constructor(spacing: Int) {
initSpacing(spacing, spacing, 0)
}
constructor(spacing: Int, extraSpacing: Int) {
initSpacing(spacing, spacing, extraSpacing)
}
constructor(verticalSpacing: Int, horizontalSpacing: Int, extraSpacing: Int) {
initSpacing(verticalSpacing, horizontalSpacing, extraSpacing)
}
private fun initSpacing(verticalSpacing: Int, horizontalSpacing: Int, extraSpacing: Int) {
this.horizontalSpacing = horizontalSpacing.dp2PxInt()
this.verticalSpacing = verticalSpacing.dp2PxInt()
this.extraSpacing = extraSpacing.dp2PxInt()
}
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
val position = parent.getChildAdapterPosition(view)
var spanCount = 1
var spanSize = 1
var spanIndex = 0
parent.layoutManager?.run {
if(this is GridLayoutManager){
spanCount = this.spanCount
spanSize = this.spanSizeLookup.getSpanSize(position)
spanIndex = (view.layoutParams as GridLayoutManager.LayoutParams).spanIndex
}
}
if (spanSize == spanCount) {
outRect.left =
if (needVerticalSpacingInSingleLine) verticalSpacing + extraSpacing else 0
outRect.right =
if (needVerticalSpacingInSingleLine) verticalSpacing + extraSpacing else 0
outRect.bottom = if (needHorizontalSpacingInSingleLine) horizontalSpacing else 0
} else {
val itemAllSpacing = (verticalSpacing * (spanCount + 1) + extraSpacing * 2) / spanCount
val left = verticalSpacing * (spanIndex + 1) - itemAllSpacing * spanIndex + extraSpacing
val right = itemAllSpacing - left
outRect.left = left
outRect.right = right
outRect.bottom = horizontalSpacing
}
}
}

View File

@ -0,0 +1,72 @@
package com.live.wallpaper.style.hd.mytools
import com.live.wallpaper.style.hd.LiveWallpaper
import com.live.wallpaper.style.hd.bean.WallpaperImage
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.json.JSONArray
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.Reader
import java.io.StringWriter
import java.nio.charset.StandardCharsets
object WallpaperDataUtil {
var liveList = mutableListOf<WallpaperImage>()
fun assestGet() {
GlobalScope.launch(Dispatchers.IO) {
val jsonLive = getdataString("live.json")
if (jsonLive.isNotEmpty()) {
val list = covertBean(jsonLive)
if (list.isNotEmpty()) {
liveList.addAll(list)
}
}
}
}
private fun getdataString(name: String): String {
var json = ""
try {
val inputStream = LiveWallpaper.app.assets.open(name)
val writer = StringWriter()
val buffer = CharArray(inputStream.available())
val reader: Reader =
BufferedReader(InputStreamReader(inputStream, StandardCharsets.UTF_8))
var n: Int
while (reader.read(buffer).also { n = it } != -1) {
writer.write(buffer, 0, n)
}
json = writer.toString()
} catch (e: Exception) {
e.printStackTrace()
}
return json
}
private fun covertBean(json: String): MutableList<WallpaperImage> {
val list = mutableListOf<WallpaperImage>()
val jsonArray = JSONArray(json)
for (i in 0 until jsonArray.length()) {
try {
val obj = jsonArray.getJSONObject(i)
val bean = WallpaperImage()
bean.wallpaperId = obj.getLong("id")
bean.title = obj.getString("title")
bean.thumbnail = obj.getString("thumbnail")
bean.preview = obj.getString("preview")
bean.category = obj.getInt("category")
list.add(bean)
} catch (_: Exception) {
continue
}
}
return list
}
}

View File

@ -0,0 +1,46 @@
package com.live.wallpaper.style.hd.mytools.asynchronous;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class AsynQueue extends Thread{
private BlockingQueue<Object> mQueue;
public AsynQueue() {
mQueue = new LinkedBlockingQueue<Object>();
}
public AsynQueue(String name) {
this();
setName(name);
}
public void stopTaskQueue() {
// use 'Poison Pill Shutdown' to stop the task queue
// add a non-Runnable object, which will be recognized as the command
// by the thread to break the infinite loop
mQueue.add(new Object());
}
public void scheduleTask(Runnable task) {
mQueue.add(task);
}
@Override
public void run() {
while (true) {
try {
Object obj = mQueue.take();
if (obj instanceof Runnable) {
((Runnable) obj).run();
obj = null;
} else {
break;
}
} catch (InterruptedException e) {
}
}
}
}

View File

@ -0,0 +1,47 @@
package com.live.wallpaper.style.hd.mytools.asynchronous;
import android.os.Handler;
import android.os.Looper;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class MyPool {
private static final Long IDLE_THREAD_KEEP_ALIVE_TIME = 60L;
private ExecutorService mThreadPoolExecutor;
private Handler mMainHandler;
private AsynQueue mActionQueue;
private ScheduledThreadPoolExecutor mScheduledThreadPoolExecutor;
public MyPool(int activeThreadCount, int maxThreadCount, int maxScheTaskThread) {
mThreadPoolExecutor = new ThreadPoolExecutor(activeThreadCount, maxThreadCount,
IDLE_THREAD_KEEP_ALIVE_TIME, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>());
if (maxScheTaskThread > 0) {
mScheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(maxScheTaskThread);
}
mMainHandler = new Handler(Looper.getMainLooper());
mActionQueue = new AsynQueue(asynchronousMan.class.getName());
mActionQueue.start();
}
public void scheduleTaskOnUiThread(long delay, Runnable task) {
if (task == null) {
return;
}
mMainHandler.postDelayed(task, delay);
}
}

View File

@ -0,0 +1,27 @@
package com.live.wallpaper.style.hd.mytools.asynchronous;
public class asynchronousMan {
private static MyPool sMyPool;
private static MyPool getThreadPoolExecutorWrapper() {
if (sMyPool == null) {
synchronized (asynchronousMan.class) {
if (sMyPool == null) {
sMyPool = new MyPool(12, 12, 10);
// if (BuildConfig.DEBUG)
// LogUtil.d(LogFilterDef.APP_INIT, LogHelper.getFileLineMethod(1));
}
}
}
return sMyPool;
}
public static void scheduleTaskOnUiThread(long delay, Runnable task) {
getThreadPoolExecutorWrapper().scheduleTaskOnUiThread(delay, task);
}
}

View File

@ -0,0 +1,26 @@
package com.live.wallpaper.style.hd.mytools.download
import android.text.TextUtils
import java.io.File
object DownloadUtil {
fun getFileName(url: String, tag: String?): String {
return if (TextUtils.isEmpty(tag)) {
url.substring(url.lastIndexOf("/") + 1)
} else {
tag + url.substring(url.lastIndexOf("/") + 1)
}
}
fun getFilePath(url: String, tag: String?): String {
return FileTools.getDownloadDirectory() + File.separator + getFileName(url, tag)
}
fun getFile(url: String, tag: String?): File {
return File(getFilePath(url, tag))
}
fun isExist(url: String, tag: String?): Boolean {
return File(getFilePath(url, tag)).exists()
}
}

View File

@ -0,0 +1,205 @@
package com.live.wallpaper.style.hd.mytools.download
import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.util.Log
import com.live.wallpaper.style.hd.LiveWallpaper
import java.io.File
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
object FileTools {
private const val DIR_FILE_NAME = "tep"
private const val DIR_DOWNLOAD = "download"
private fun getDefaultDirectory(): String {
var dirName = ""
if (LiveWallpaper.app.getExternalFilesDir(DIR_FILE_NAME) != null) {//外部存储可用
if (Build.VERSION.SDK_INT >= 29) {
dirName = LiveWallpaper.app.getExternalFilesDir(DIR_FILE_NAME)!!.path
} else if (Build.VERSION.SDK_INT < 29) {
dirName = LiveWallpaper.app.getExternalFilesDir(DIR_FILE_NAME)!!.absolutePath
}
} else {//外部存储不可用
dirName = LiveWallpaper.app.filesDir.absolutePath
}
return dirName
}
fun getDownloadDirectory(): String {
return getDefaultDirectory() + File.separator + DIR_DOWNLOAD
}
/**
* @param path 文件绝对路径
*/
fun isExists(path: String): Boolean {
return File(path).exists()
}
/**
* 获取下载文件的名称 + 后缀名
*/
fun getFileNameAndSuffix(path: String): String {
return path.substring(path.lastIndexOf("/") + 1)
}
fun getFileName(path: String): String? {
val start = path.lastIndexOf("/")
val end = path.lastIndexOf(".")
return if (start != -1 && end != -1) {
path.substring(start + 1, end)
} else {
null
}
}
/**
* 1.URI content://com.android.providers.media.documents/document/image%3A235700
* 因为在 Android 4.4 及以上的机型使用了 DocumentUri 来代表获取到文件的 URI
* 要对于 DocumentUri 进行适配
* 2.URI content://media/extenral/images/media/17766 而我们需要得到对应的文件路径。
* 参考:https://blog.csdn.net/rjc_lihui/article/details/127020909
*/
fun getFilePathByUri(context: Context, uri: Uri): String? {
var path: String? = null
// 以 file:// 开头的
if (ContentResolver.SCHEME_FILE == uri.scheme) {
path = uri.path
return path
}
// 以 content:// 开头的,比如 content://media/extenral/images/media/17766
if (ContentResolver.SCHEME_CONTENT == uri.scheme && Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
val cursor = context.contentResolver.query(
uri,
arrayOf(MediaStore.Images.Media.DATA),
null,
null,
null
)
if (cursor != null) {
if (cursor.moveToFirst()) {
val columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
if (columnIndex > -1) {
path = cursor.getString(columnIndex)
}
}
cursor.close()
}
return path
}
// 4.4及之后的 是以 content:// 开头的,比如 content://com.android.providers.media.documents/document/image%3A235700
if (ContentResolver.SCHEME_CONTENT == uri.scheme && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (DocumentsContract.isDocumentUri(context, uri)) {
if (isExternalStorageDocument(uri)) {
// ExternalStorageProvider
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()
val type = split[0]
if ("primary".equals(type, ignoreCase = true)) {
path = Environment.getExternalStorageDirectory().toString() + "/" + split[1]
return path
}
} else if (isDownloadsDocument(uri)) {
// DownloadsProvider
val id = DocumentsContract.getDocumentId(uri)
val contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"),
java.lang.Long.valueOf(id)
)
path = getDataColumn(context, contentUri, null, null)
return path
} else if (isMediaDocument(uri)) {
// MediaProvider
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()
val type = split[0]
var contentUri: Uri? = null
if ("image" == type) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
} else if ("video" == type) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
} else if ("audio" == type) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}
val selection = "_id=?"
val selectionArgs = arrayOf(split[1])
path = getDataColumn(context, contentUri, selection, selectionArgs)
return path
}
}
}
return null
}
private fun getDataColumn(
context: Context,
uri: Uri?,
selection: String?,
selectionArgs: Array<String>?
): String? {
var cursor: Cursor? = null
val column = "_data"
val projection = arrayOf(column)
try {
cursor =
context.contentResolver.query(uri!!, projection, selection, selectionArgs, null)
if (cursor != null && cursor.moveToFirst()) {
val column_index = cursor.getColumnIndexOrThrow(column)
return cursor.getString(column_index)
}
} finally {
cursor?.close()
}
return null
}
private fun isExternalStorageDocument(uri: Uri): Boolean {
return "com.android.externalstorage.documents" == uri.authority
}
private fun isDownloadsDocument(uri: Uri): Boolean {
return "com.android.providers.downloads.documents" == uri.authority
}
private fun isMediaDocument(uri: Uri): Boolean {
return "com.android.providers.media.documents" == uri.authority
}
fun getFileName(contentResolver: ContentResolver, uri: Uri): String? {
val projection = arrayOf(MediaStore.MediaColumns.DISPLAY_NAME)
contentResolver.query(uri, projection, null, null, null)?.use {
if (it.moveToFirst()) {
return it.getString(0)
}
}
return null
}
fun getFileInputStream(fileUri: Uri): InputStream? =
try {
LiveWallpaper.app.contentResolver.openInputStream(fileUri)
} catch (e: IOException) {
val errorInfo = "Error opening external file at $fileUri: $e"
Log.d("tep", errorInfo)
null
}
fun getFileOutStream(fileName: String): OutputStream? =
try {
LiveWallpaper.app.openFileOutput(fileName, Context.MODE_PRIVATE)
} catch (e: IOException) {
val errorInfo = "Error opening internal file: $fileName: $e"
Log.d("tep", errorInfo)
null
}
}

View File

@ -0,0 +1,72 @@
package com.live.wallpaper.style.hd.mytools.download
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.IOException
import java.util.concurrent.TimeUnit
class HttpNet {
private var mOkHttpClient: OkHttpClient? = null
companion object {
val mInstance: HttpNet by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
HttpNet()
}
}
private val CONNECT_TIMEOUT: Long = 60 //超时时间,秒
private val READ_TIMEOUT: Long = 60 //读取时间,秒
private val WRITE_TIMEOUT: Long = 60 //写入时间,秒
init {
val builder: OkHttpClient.Builder = OkHttpClient.Builder()
.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
mOkHttpClient = builder.build()
}
/**
* @param url 下载链接
* @param startIndex 下载起始位置
* @param endIndex 结束为止
* @param callback 回调
* @throws IOException
*/
@Throws(IOException::class)
fun downloadFileByRange(url: String, startIndex: Long, endIndex: Long, callback: Callback) {
// 创建一个Request
// 设置分段下载的头信息。 Range:做分段数据请求,断点续传指示下载的区间。格式: Range bytes=0-1024或者bytes:0-1024
val request: Request = Request.Builder().header("RANGE", "bytes=$startIndex-$endIndex")
.url(url)
.build()
doAsync(request, callback)
}
@Throws(IOException::class)
fun getContentLength(url: String, callback: Callback) {
// 创建一个Request
val request: Request = Request.Builder()
.url(url)
.build()
doAsync(request, callback)
}
/**
* 异步请求
*/
@Throws(IOException::class)
private fun doAsync(request: Request, callback: Callback) {
//创建请求会话
val call = mOkHttpClient!!.newCall(request)
//同步执行会话请求
call.enqueue(callback)
}
}

View File

@ -0,0 +1,358 @@
package com.live.wallpaper.style.hd.mytools.download
import android.os.Handler
import android.os.Message
import android.util.Log
import com.live.wallpaper.style.hd.BuildConfig
import com.live.wallpaper.style.hd.bean.InfoFile
import okhttp3.Call
import okhttp3.Response
import java.io.Closeable
import java.io.File
import java.io.IOException
import java.io.RandomAccessFile
import java.util.concurrent.atomic.AtomicInteger
class MyTask(point: InfoFile, l: NetListener?) : Handler() {
private val TAG = "MyTask"
private val THREAD_COUNT = 3 //线程数
private var mPoint: InfoFile
private var mFileLength: Long = 0
@Volatile
private var isDownloading = false
private val childCancelCount = AtomicInteger(0) //子线程取消数量
private val childPauseCount = AtomicInteger(0) //子线程暂停数量
private val childFinishCount = AtomicInteger(0) //子线程完成数量
private var mHttpNet: HttpNet
private var mProgress: LongArray
private var mCacheFiles: Array<File?>
private var mTmpFile: File? = null//临时占位文件
@Volatile
private var pause = false //是否暂停
@Volatile
private var cancel = false //是否取消下载
private val MSG_PROGRESS = 1 //进度
private val MSG_FINISH = 2 //完成下载
private val MSG_PAUSE = 3 //暂停
private val MSG_CANCEL = 4 //暂停
private var mListener: NetListener? = null //下载回调监听
init {
mPoint = point
mListener = l
mProgress = LongArray(THREAD_COUNT)
mCacheFiles = arrayOfNulls(THREAD_COUNT)
mHttpNet = HttpNet.mInstance
}
/**
* 任务回调消息
*
* @param msg
*/
override fun handleMessage(msg: Message) {
if (null == mListener) {
return
}
when (msg.what) {
MSG_PROGRESS -> {
var progress: Long = 0
var i = 0
val length = mProgress.size
while (i < length) {
progress += mProgress[i]
i++
}
val p = progress * 1.0f / mFileLength
// if (BuildConfig.DEBUG) {
// Log.d(TAG, "${mPoint.getUrl()} is downloading: $p")
// }
mListener!!.onProgress(mPoint.url, p)
}
MSG_PAUSE -> {
if (confirmStatus(childPauseCount)) return
resetStutus()
if (BuildConfig.DEBUG) {
Log.d(TAG, "${mPoint.url} is pause")
}
mListener!!.onPause(mPoint.url)
}
MSG_FINISH -> {
if (confirmStatus(childFinishCount)) return
//下载完毕后,重命名目标文件名
val renameResult = mTmpFile!!.renameTo(
File(
mPoint.filePath,
mPoint.fileName
)
)
resetStutus()
if (BuildConfig.DEBUG) {
Log.d(
TAG,
"重命名结果:$renameResult"
)
Log.d(
TAG,
"file is downloaded, path: ${mTmpFile!!.absolutePath}"
)
}
mListener!!.onFinished(mPoint.url)
}
MSG_CANCEL -> {
if (confirmStatus(childCancelCount)) return
resetStutus()
mProgress = LongArray(THREAD_COUNT)
if (BuildConfig.DEBUG) {
Log.d(TAG, "${mPoint.url} is cancel")
}
mListener!!.onCancel(mPoint.url)
}
}
}
@Synchronized
fun start() {
try {
if (isDownloading) return
isDownloading = true
if (BuildConfig.DEBUG) {
Log.d(
TAG,
"start: ${mPoint.url}"
)
}
mHttpNet.getContentLength(mPoint.url, object : okhttp3.Callback {
override fun onResponse(call: Call, response: Response) {
if (BuildConfig.DEBUG) {
Log.d(
TAG,
"start: ${mPoint.url} response.code: ${response.code}"
)
}
if (response.code != 200) {
close(response.body)
resetStutus()
return
}
// 获取资源大小
mFileLength = response.body!!.contentLength()
if (mFileLength < 0) {
return
}
close(response.body)
// 在本地创建一个与资源同样大小的文件来占位
mTmpFile = File(mPoint.filePath, mPoint.fileName.toString() + ".tmp")
if (!mTmpFile!!.parentFile.exists()) {
mTmpFile!!.parentFile.mkdirs()
}
val tmpAccessFile = RandomAccessFile(mTmpFile, "rw")
tmpAccessFile.setLength(mFileLength)
/*将下载任务分配给每个线程*/
val blockSize = mFileLength / THREAD_COUNT // 计算每个线程理论上下载的数量.
/*为每个线程配置并分配任务*/
for (threadId in 0 until THREAD_COUNT) {
val startIndex = threadId * blockSize // 线程开始下载的位置
var endIndex = (threadId + 1) * blockSize - 1 // 线程结束下载的位置
if (threadId == THREAD_COUNT - 1) { // 如果是最后一个线程,将剩下的文件全部交给这个线程完成
endIndex = mFileLength - 1
}
download(startIndex, endIndex, threadId) // 开启线程下载
}
}
override fun onFailure(call: Call, e: IOException) {
if (BuildConfig.DEBUG) {
Log.e(TAG, e.toString())
}
resetStutus()
}
})
} catch (e: Exception) {
if (BuildConfig.DEBUG) {
Log.e(TAG, e.toString())
}
resetStutus()
}
}
@Throws(IOException::class)
private fun download(startIndex: Long, endIndex: Long, threadId: Int) {
if (BuildConfig.DEBUG) {
Log.d(
TAG,
"download: ${mPoint.url}"
)
}
var newStartIndex = startIndex
// 分段请求网络连接,分段将文件保存到本地.
// 加载下载位置缓存文件
val cacheFile: File =
File(mPoint.filePath, "thread" + threadId + "_" + mPoint.fileName + ".cache")
mCacheFiles[threadId] = cacheFile
val cacheAccessFile = RandomAccessFile(cacheFile, "rwd")
if (cacheFile.exists()) { // 如果文件存在
val startIndexStr = cacheAccessFile.readLine()
try {
newStartIndex = startIndexStr.toInt().toLong() //重新设置下载起点
} catch (e: Exception) {
if (BuildConfig.DEBUG) {
Log.e(TAG, e.toString())
}
e.printStackTrace()
}
}
val finalStartIndex = newStartIndex
if (BuildConfig.DEBUG) {
Log.d(
TAG,
"finalStartIndex: $finalStartIndex"
)
Log.d(
TAG,
"endIndex: $endIndex"
)
}
mHttpNet.downloadFileByRange(
mPoint.url,
finalStartIndex,
endIndex,
object : okhttp3.Callback {
override fun onResponse(call: Call, response: Response) {
if (BuildConfig.DEBUG) {
Log.d(
TAG,
"download: ${mPoint.url} response.code: ${response.code}"
)
}
if (response.code != 206) { // 206请求部分资源成功码
resetStutus()
return
}
val stream = response.body!!.byteStream() // 获取流
val tmpAccessFile = RandomAccessFile(mTmpFile, "rw") // 获取前面已创建的文件.
tmpAccessFile.seek(finalStartIndex) // 文件写入的开始位置.
/* 将网络流中的文件写入本地*/
val buffer = ByteArray(1024 shl 2)
var length = -1
var total = 0 // 记录本次下载文件的大小
var progress: Long = 0
while (stream.read(buffer).also { length = it } > 0) {
if (cancel) {
//关闭资源
close(cacheAccessFile, stream, response.body)
cleanFile(cacheFile)
sendEmptyMessage(MSG_CANCEL)
return
}
if (pause) {
//关闭资源
close(cacheAccessFile, stream, response.body)
//发送暂停消息
sendEmptyMessage(MSG_PAUSE)
return
}
tmpAccessFile.write(buffer, 0, length)
total += length
progress = finalStartIndex + total
//将当前现在到的位置保存到文件中
cacheAccessFile.seek(0)
cacheAccessFile.write((progress.toString() + "").toByteArray(charset("UTF-8")))
//发送进度消息
mProgress[threadId] = progress - startIndex
sendEmptyMessage(MSG_PROGRESS)
}
//关闭资源
close(cacheAccessFile, stream, response.body)
// 删除临时文件
cleanFile(cacheFile)
//发送完成消息
sendEmptyMessage(MSG_FINISH)
}
override fun onFailure(call: Call, e: IOException) {
isDownloading = false
}
})
}
/**
* 关闭资源
*
* @param closeables
*/
private fun close(vararg closeables: Closeable?) {
val length = closeables.size
try {
for (i in 0 until length) {
val closeable = closeables[i]
if (null != closeable) closeables[i]!!.close()
}
} catch (e: IOException) {
if (BuildConfig.DEBUG) {
Log.e(TAG, e.toString())
}
e.printStackTrace()
} finally {
for (i in 0 until length) {
// closeables[i] = null
}
}
}
/**
* 删除临时文件
*/
private fun cleanFile(vararg files: File?) {
var i = 0
val length = files.size
while (i < length) {
if (null != files[i]) files[i]!!.delete()
i++
}
}
/**
* 重置下载状态
*/
private fun resetStutus() {
pause = false
cancel = false
isDownloading = false
}
/**
* 确认下载状态
*
* @param count
* @return
*/
private fun confirmStatus(count: AtomicInteger): Boolean {
return count.incrementAndGet() % THREAD_COUNT != 0
}
}

View File

@ -0,0 +1,11 @@
package com.live.wallpaper.style.hd.mytools.download
interface NetListener {
fun onFinished(url: String)
fun onProgress(url: String, progress: Float)
fun onPause(url: String)
fun onCancel(url: String)
}

View File

@ -0,0 +1,70 @@
package com.live.wallpaper.style.hd.mytools.download
import android.text.TextUtils
import com.live.wallpaper.style.hd.bean.InfoFile
class NetManager {
private var DEFAULT_FILE_DIR: String? = null //默认下载目录
private var mMyTasks: MutableMap<String, MyTask> =
mutableMapOf() //文件下载任务索引String为url,用来唯一区别并操作下载的文件
companion object {
val instance: NetManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
NetManager()
}
}
/**
* 添加下载任务
* tag是用来区别下载文件的文件名相同的情况
*/
fun add(url: String, tag: String, l: NetListener?) {
add(url, null, null, tag, l)
}
/**
* 添加下载任务
* tag是用来区别下载文件的文件名相同的情况
*/
fun add(url: String, filePath: String?, fileName: String?, tag: String?, l: NetListener?) {
var filePath = filePath
var fileName = fileName
if (TextUtils.isEmpty(filePath)) { //没有指定下载目录,使用默认目录
filePath = FileTools.getDownloadDirectory()
}
if (TextUtils.isEmpty(fileName)) {
fileName = DownloadUtil.getFileName(url, tag)
}
mMyTasks[url] = MyTask(InfoFile(url, filePath, fileName), l)
}
/**
* 下载文件 要放在主线程中运行 否则 Can't create handler inside thread Thread[pool-13-thread-2,5,main] that has not called Looper.prepare()
*/
fun download(urls: MutableList<String>) {
//单任务开启下载或多任务开启下载
urls.forEach { url ->
if (mMyTasks.containsKey(url)) {
mMyTasks[url]!!.start()
}
}
}
/**
* 下载文件
*/
fun download(vararg urls: String?) {
//单任务开启下载或多任务开启下载
var i = 0
val length = urls.size
while (i < length) {
val url = urls[i]
if (mMyTasks.containsKey(url)) {
mMyTasks[url]!!.start()
}
i++
}
}
}

View File

@ -0,0 +1,106 @@
package com.live.wallpaper.style.hd.recycleradapter
import android.content.Context
import android.graphics.drawable.Drawable
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.live.wallpaper.style.hd.bean.WallpaperImage
import com.live.wallpaper.style.hd.databinding.ItemPreviewLiveBinding
import com.live.wallpaper.style.hd.mytools.download.DownloadUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.live.wallpaper.style.hd.mytools.Common.hide
import com.live.wallpaper.style.hd.mytools.Common.show
class AdapterLive (private val ctx: Context, private val list: MutableList<WallpaperImage>) :
RecyclerView.Adapter<AdapterLive.VH>() {
private var mListener: OnItemClickListener? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
return VH(ItemPreviewLiveBinding.inflate(LayoutInflater.from(ctx), parent, false))
}
override fun onBindViewHolder(holder: VH, position: Int) {
if (list.isEmpty()) {
return
}
if (position >= list.size) {
return
}
val bean = list[position]
holder.mItemBinding?.ivPlaceholder?.show()
val url = if (DownloadUtil.isExist(bean.preview, bean.getTag())) {
DownloadUtil.getFilePath(bean.preview, bean.getTag())
} else {
bean.thumbnail
}
// val url = bean.thumbnail
holder.mItemBinding?.ivWallpaper?.let {
Glide.with(ctx)
.load(url)
.transition(DrawableTransitionOptions.withCrossFade())
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
holder.mItemBinding?.ivPlaceholder?.show()
Log.d("-----------","----------fail--$url")
return false
}
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
holder.mItemBinding?.ivPlaceholder?.hide()
return false
}
})
.into(it)
}
holder.mItemBinding?.ivPlay?.let {
it.setOnClickListener { mListener?.onItemClick(holder.adapterPosition) }
}
}
override fun getItemCount(): Int {
return list.size
}
fun setOnItemClickListener(listener: OnItemClickListener) {
mListener = listener
}
interface OnItemClickListener {
fun onItemClick(pos: Int)
}
class VH(itemView: View) : RecyclerView.ViewHolder(itemView) {
var mItemBinding: ItemPreviewLiveBinding? = null
constructor(binding: ItemPreviewLiveBinding) : this(binding.root) {
this.mItemBinding = binding
}
fun getRoot(): View? {
return mItemBinding?.root
}
}
}

View File

@ -0,0 +1,54 @@
package com.live.wallpaper.style.hd.recycleradapter
import android.annotation.SuppressLint
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.live.wallpaper.style.hd.databinding.ItemRateStartBinding
class AdapterStar(private val context: Context, private var clickAction: (Int) -> Unit) :
RecyclerView.Adapter<AdapterStar.MyViewHolder>() {
private var clickPos: Int? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder = MyViewHolder(
ItemRateStartBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
)
override fun getItemCount(): Int = 5
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(position)
}
@SuppressLint("NotifyDataSetChanged")
inner class MyViewHolder(private val binding: ItemRateStartBinding) :
RecyclerView.ViewHolder(binding.root) {
init {
// binding.root.setOnClickListener {
// val position = bindingAdapterPosition
// if (position != RecyclerView.NO_POSITION) {
// clickAction.invoke(position)
// }
//
// }
}
fun bind(position: Int) {
clickPos?.let {
binding.imStart.isSelected = position <= it
}
binding.consStart.setOnClickListener {
clickAction.invoke(position)
clickPos = position
notifyDataSetChanged()
}
}
}
fun getRate(): Int? = clickPos
}

View File

@ -0,0 +1,108 @@
package com.live.wallpaper.style.hd.recycleradapter
import android.content.Context
import android.graphics.drawable.Drawable
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
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.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.live.wallpaper.style.hd.bean.WallpaperImage
import com.live.wallpaper.style.hd.databinding.ItemWallpaperBinding
import com.live.wallpaper.style.hd.mytools.Common
import com.live.wallpaper.style.hd.mytools.Common.dp2PxInt
import com.live.wallpaper.style.hd.mytools.Common.hide
import com.live.wallpaper.style.hd.mytools.Common.show
class AdapterWall (private val ctx: Context, private val list: MutableList<WallpaperImage>) :
RecyclerView.Adapter<AdapterWall.VH>() {
private var mListener: OnItemClickListener? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
return VH(ItemWallpaperBinding.inflate(LayoutInflater.from(ctx), parent, false))
}
override fun onBindViewHolder(holder: VH, position: Int) {
if (list.isEmpty()) {
return
}
if (position >= list.size) {
return
}
val bean = list[position]
holder.mItemBinding?.ivPlaceholder?.show()
holder.mItemBinding?.ivWallpaper?.let {
Glide.with(ctx)
.load(bean.thumbnail)
.transition(DrawableTransitionOptions.withCrossFade())
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
Log.d("-----------","----------fail--${bean.thumbnail}")
holder.mItemBinding?.ivPlaceholder?.show()
return false
}
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
Log.d("-----------","----------fail--${bean.thumbnail}")
holder.mItemBinding?.ivPlaceholder?.hide()
return false
}
})
.into(it)
}
holder.getRoot()?.let {
it.setOnClickListener { mListener?.onItemClick(holder.adapterPosition) }
val params = it.layoutParams
val itemWidth = (Common.getScreenWidth(ctx) - 48.dp2PxInt()) / 2f
params.width = itemWidth.toInt()
val itemHeight =
((itemWidth * Common.getScreenHeight(ctx) / Common.getScreenWidth(ctx) * 1f)).toInt()
params.height = itemHeight
it.layoutParams = params
}
}
override fun getItemCount(): Int {
return list.size
}
fun setOnItemClickListener(listener: OnItemClickListener) {
mListener = listener
}
interface OnItemClickListener {
fun onItemClick(pos: Int)
}
class VH(itemView: View) : RecyclerView.ViewHolder(itemView) {
var mItemBinding: ItemWallpaperBinding? = null
constructor(binding: ItemWallpaperBinding) : this(binding.root) {
this.mItemBinding = binding
}
fun getRoot(): View? {
return mItemBinding?.root
}
}
}

View File

@ -0,0 +1,88 @@
package com.live.wallpaper.style.hd.viewm
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.live.wallpaper.style.hd.bean.WallpaperImage
import com.live.wallpaper.style.hd.mytools.WallpaperDataUtil
import java.util.concurrent.atomic.AtomicBoolean
class WallpaperViewModel : ViewModel() {
private var mCurListLiveData: MutableLiveData<MutableList<WallpaperImage>> = MutableLiveData()
private var mCurList: MutableList<WallpaperImage> = mutableListOf()
private var mPoolList: MutableList<WallpaperImage> = mutableListOf()
var isLoading = AtomicBoolean(false)
fun getData(): MutableLiveData<MutableList<WallpaperImage>> {
return mCurListLiveData
}
fun updateWallpaper() {
if (isLoading.get()) {
return
}
try {
isLoading.set(true)
mCurList.clear()
mPoolList.clear()
mPoolList.addAll(getDataLIst())
val list = mPoolList.randomList(40)
mCurList.addAll(list)
mPoolList.removeAll(list)
} catch (e: Exception) {
e.printStackTrace()
} finally {
mCurListLiveData.postValue(mCurList)
isLoading.set(false)
}
}
fun getDataLIst(): MutableList<WallpaperImage> {
return WallpaperDataUtil.liveList
}
fun loadWallpaper() {
if (isLoading.get()) {
return
}
try {
isLoading.set(true)
val list = mPoolList.randomList(20)
mCurList.addAll(list)
mPoolList.removeAll(list)
} catch (e: Exception) {
e.printStackTrace()
} finally {
mCurListLiveData.postValue(mCurList)
isLoading.set(false)
}
}
fun <T> List<T>.randomList(needListSize: Int): List<T> {
return if (this.isNotEmpty()) {
if (needListSize > 0) {
val counts = if (needListSize > this.size) this.size else needListSize
val randomSet = mutableSetOf<T>()
for (index in this.indices) {
if (randomSet.size == counts) {
break
}
val randomIndex = (this.indices).random()
randomSet.add(this[randomIndex])
}
randomSet.toList()
} else {
this
}
} else {
emptyList<T>()
}
}
override fun onCleared() {
super.onCleared()
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/black" android:state_selected="false"/>
<item android:color="@color/color_cb39a7" android:state_selected="true"/>
</selector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M4.5,21C4.083,21 3.729,20.85 3.437,20.549C3.145,20.248 2.999,19.883 3,19.455V17.498L7,13.841V21H4.5ZM8,21V16.88H16V21H8ZM17,21V12.554L12.725,8.639L15.75,5.884L20.5,10.236C20.667,10.391 20.792,10.567 20.875,10.764C20.958,10.962 21,11.172 21,11.395V19.455C21,19.884 20.854,20.249 20.562,20.55C20.27,20.851 19.916,21.001 19.5,21H17ZM3,16.107V11.395C3,11.172 3.042,10.957 3.125,10.751C3.208,10.545 3.333,10.373 3.5,10.236L11,3.386C11.133,3.249 11.288,3.15 11.463,3.091C11.638,3.031 11.817,3.001 12,3C12.183,3 12.362,3.03 12.537,3.091C12.712,3.151 12.866,3.25 13,3.386L15,5.215L3,16.107Z"
android:fillColor="#cdb2c2"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M4.5,21C4.083,21 3.729,20.85 3.437,20.549C3.145,20.248 2.999,19.883 3,19.455V17.498L7,13.841V21H4.5ZM8,21V16.88H16V21H8ZM17,21V12.554L12.725,8.639L15.75,5.884L20.5,10.236C20.667,10.391 20.792,10.567 20.875,10.764C20.958,10.962 21,11.172 21,11.395V19.455C21,19.884 20.854,20.249 20.562,20.55C20.27,20.851 19.916,21.001 19.5,21H17ZM3,16.107V11.395C3,11.172 3.042,10.957 3.125,10.751C3.208,10.545 3.333,10.373 3.5,10.236L11,3.386C11.133,3.249 11.288,3.15 11.463,3.091C11.638,3.031 11.817,3.001 12,3C12.183,3 12.362,3.03 12.537,3.091C12.712,3.151 12.866,3.25 13,3.386L15,5.215L3,16.107Z"
android:fillColor="#FFcb39a7"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="200dp"
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="#272636"/>
</vector>

View File

@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="120dp"
android:height="120dp"
android:viewportWidth="120"
android:viewportHeight="120">
<path
android:pathData="M60,0C26.86,0 0,26.86 0,60C0,93.14 26.86,120 60,120C93.14,120 120,93.14 120,60C120,26.86 93.14,0 60,0Z"
android:strokeAlpha="0.32497442"
android:strokeWidth="1"
android:fillColor="#020202"
android:fillType="evenOdd"
android:strokeColor="#00000000"
android:fillAlpha="0.32497442"/>
<path
android:pathData="M51.63,87.19C50.12,88.18 48.18,88.27 46.59,87.41C44.99,86.56 44,84.9 44,83.1L44,36.9C44,35.1 44.99,33.44 46.59,32.59C48.18,31.73 50.12,31.82 51.63,32.81L87.79,55.91C89.17,56.82 90,58.36 90,60C90,61.65 89.17,63.19 87.79,64.09L51.63,87.19Z"
android:strokeWidth="1"
android:fillColor="#FFFFFF"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>

View File

@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,12m-12,0a12,12 0,1 1,24 0a12,12 0,1 1,-24 0"
android:strokeAlpha="0.15923418"
android:strokeWidth="1"
android:fillColor="#1C211F"
android:fillType="evenOdd"
android:strokeColor="#00000000"
android:fillAlpha="0.15923418"/>
<path
android:pathData="M17,8.4l-1.4,-1.4l-3.6,3.6l-3.6,-3.6l-1.4,1.4l3.6,3.6l-3.6,3.6l1.4,1.4l3.6,-3.6l3.6,3.6l1.4,-1.4l-3.6,-3.6z"
android:strokeWidth="1"
android:fillColor="#FFFFFF"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>

View File

@ -0,0 +1,5 @@
<?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/home_true"/>
<item android:state_selected="false" android:drawable="@drawable/home_false"/>
</selector>

View File

@ -0,0 +1,5 @@
<?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/settings_true"/>
<item android:state_selected="false" android:drawable="@drawable/settings_false"/>
</selector>

View 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/star_selected" android:state_selected="true"/>
<item android:drawable="@drawable/star_normal" android:state_selected="false"/>
</selector>

View File

@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<group>
<clip-path
android:pathData="M0,0h24v24h-24z"/>
<path
android:pathData="M5.284,12.303V11.759L14.411,3.444C14.495,3.57 14.552,3.717 14.572,3.877L14.747,5.286C14.793,5.652 15.042,5.952 15.358,6.143L15.37,6.15L15.403,6.17C15.702,6.355 16.072,6.404 16.396,6.267L17.723,5.706C18.188,5.51 18.727,5.691 18.979,6.128L20.561,8.875C20.812,9.311 20.7,9.866 20.3,10.17L18.937,11.208C18.787,11.322 18.716,11.508 18.716,11.697V12.182L9.565,20.518C9.494,20.401 9.446,20.267 9.428,20.123L9.253,18.714C9.208,18.348 8.958,18.048 8.642,17.858L8.63,17.85L8.597,17.83C8.298,17.645 7.928,17.596 7.604,17.733L6.277,18.294C5.812,18.49 5.273,18.309 5.022,17.872L3.439,15.125C3.188,14.689 3.3,14.134 3.7,13.83L5.063,12.792C5.213,12.678 5.284,12.492 5.284,12.303ZM10.521,21H13.579C14.084,21 14.509,20.624 14.572,20.123L14.749,18.695C14.794,18.339 15.029,18.041 15.339,17.861L15.358,17.85L15.399,17.826C15.702,17.645 16.072,17.597 16.396,17.735L17.699,18.29C18.165,18.488 18.705,18.308 18.958,17.869L20.539,15.125C20.79,14.689 20.678,14.134 20.278,13.83L19.251,13.048L10.521,21ZM10.421,3H13.414L4.704,10.934L3.7,10.17C3.3,9.866 3.188,9.311 3.439,8.875L5.022,6.128C5.273,5.691 5.812,5.51 6.277,5.706L7.605,6.267C7.929,6.404 8.297,6.355 8.599,6.175L8.642,6.15L8.661,6.139C8.971,5.959 9.206,5.661 9.251,5.305L9.428,3.877C9.491,3.376 9.916,3 10.421,3ZM12.045,15.15C12.91,15.15 13.649,14.842 14.261,14.227C14.873,13.613 15.179,12.87 15.179,12C15.179,11.13 14.873,10.387 14.261,9.773C13.649,9.158 12.91,8.85 12.045,8.85C11.164,8.85 10.422,9.158 9.817,9.773C9.212,10.387 8.91,11.13 8.91,12C8.91,12.87 9.213,13.613 9.817,14.227C10.421,14.842 11.164,15.15 12.045,15.15Z"
android:fillColor="#cdb2c2"
android:fillType="evenOdd"/>
</group>
</vector>

View File

@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<group>
<clip-path
android:pathData="M0,0h24v24h-24z"/>
<path
android:pathData="M5.284,12.303V11.759L14.411,3.444C14.495,3.57 14.552,3.717 14.572,3.877L14.747,5.286C14.792,5.652 15.042,5.952 15.358,6.143L15.37,6.15L15.403,6.17C15.702,6.355 16.072,6.404 16.396,6.267L17.723,5.706C18.188,5.51 18.726,5.691 18.979,6.128L20.561,8.875C20.812,9.311 20.7,9.866 20.3,10.17L18.937,11.208C18.787,11.322 18.716,11.508 18.716,11.697V12.182L9.565,20.518C9.494,20.401 9.446,20.267 9.428,20.123L9.253,18.714C9.207,18.348 8.958,18.048 8.642,17.858L8.63,17.85L8.597,17.83C8.298,17.645 7.928,17.596 7.604,17.733L6.277,18.294C5.812,18.49 5.273,18.309 5.021,17.872L3.439,15.125C3.188,14.689 3.3,14.134 3.7,13.83L5.063,12.792C5.213,12.678 5.284,12.492 5.284,12.303ZM10.521,21H13.579C14.084,21 14.509,20.624 14.572,20.123L14.749,18.695C14.794,18.339 15.029,18.041 15.339,17.861L15.358,17.85L15.399,17.826C15.702,17.645 16.072,17.597 16.396,17.735L17.699,18.29C18.165,18.488 18.705,18.308 18.958,17.869L20.538,15.125C20.79,14.689 20.678,14.134 20.278,13.83L19.251,13.048L10.521,21ZM10.421,3H13.414L4.704,10.934L3.7,10.17C3.3,9.866 3.188,9.311 3.439,8.875L5.021,6.128C5.273,5.691 5.812,5.51 6.277,5.706L7.605,6.267C7.929,6.404 8.297,6.355 8.599,6.175L8.642,6.15L8.661,6.139C8.971,5.959 9.206,5.661 9.251,5.305L9.428,3.877C9.491,3.376 9.916,3 10.421,3ZM12.045,15.15C12.91,15.15 13.649,14.842 14.261,14.227C14.873,13.613 15.179,12.87 15.179,12C15.179,11.13 14.873,10.387 14.261,9.773C13.649,9.158 12.91,8.85 12.045,8.85C11.164,8.85 10.422,9.158 9.817,9.773C9.212,10.387 8.91,11.13 8.91,12C8.91,12.87 9.213,13.613 9.817,14.227C10.421,14.842 11.164,15.15 12.045,15.15Z"
android:fillColor="#FFcb39a7"
android:fillType="evenOdd"/>
</group>
</vector>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/color_cb39a7" />
<corners android:radius="8dp" />
</shape>
</item>
</selector>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/theme_gray" />
<corners android:radius="8dp" />
</shape>
</item>
</selector>

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M9.153,5.408C10.42,3.136 11.053,2 12,2C12.947,2 13.58,3.136 14.847,5.408L15.175,5.996C15.535,6.642 15.715,6.965 15.995,7.178C16.275,7.391 16.625,7.47 17.325,7.628L17.961,7.772C20.421,8.329 21.65,8.607 21.943,9.548C22.235,10.488 21.397,11.469 19.72,13.43L19.286,13.937C18.81,14.494 18.571,14.773 18.464,15.117C18.357,15.462 18.393,15.834 18.465,16.577L18.531,17.254C18.784,19.871 18.911,21.179 18.145,21.76C17.379,22.342 16.227,21.811 13.925,20.751L13.328,20.477C12.674,20.175 12.347,20.025 12,20.025C11.653,20.025 11.326,20.175 10.671,20.477L10.076,20.751C7.773,21.811 6.621,22.341 5.856,21.761C5.089,21.179 5.216,19.871 5.469,17.254L5.535,16.578C5.607,15.834 5.643,15.462 5.535,15.118C5.429,14.773 5.19,14.494 4.714,13.938L4.28,13.43C2.603,11.47 1.765,10.489 2.057,9.548C2.35,8.607 3.58,8.328 6.04,7.772L6.676,7.628C7.375,7.47 7.724,7.391 8.005,7.178C8.285,6.965 8.465,6.642 8.825,5.996L9.153,5.408Z"
android:strokeAlpha="0.3"
android:fillColor="#ffffff"
android:fillAlpha="0.3"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M9.153,5.408C10.42,3.136 11.053,2 12,2C12.947,2 13.58,3.136 14.847,5.408L15.175,5.996C15.535,6.642 15.715,6.965 15.995,7.178C16.275,7.391 16.625,7.47 17.325,7.628L17.961,7.772C20.421,8.329 21.65,8.607 21.943,9.548C22.235,10.488 21.397,11.469 19.72,13.43L19.286,13.937C18.81,14.494 18.571,14.773 18.464,15.117C18.357,15.462 18.393,15.834 18.465,16.577L18.531,17.254C18.784,19.871 18.911,21.179 18.145,21.76C17.379,22.342 16.227,21.811 13.925,20.751L13.328,20.477C12.674,20.175 12.347,20.025 12,20.025C11.653,20.025 11.326,20.175 10.671,20.477L10.076,20.751C7.773,21.811 6.621,22.341 5.856,21.761C5.089,21.179 5.216,19.871 5.469,17.254L5.535,16.578C5.607,15.834 5.643,15.462 5.535,15.118C5.429,14.773 5.19,14.494 4.714,13.938L4.28,13.43C2.603,11.47 1.765,10.489 2.057,9.548C2.35,8.607 3.58,8.328 6.04,7.772L6.676,7.628C7.375,7.47 7.724,7.391 8.005,7.178C8.285,6.965 8.465,6.642 8.825,5.996L9.153,5.408Z"
android:fillColor="#FFcb39a7"/>
</vector>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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="match_parent"
android:background="@mipmap/first_img">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="92dp"
android:layout_height="92dp"
app:srcCompat="@mipmap/live_logo" />
<TextView
android:layout_width="260dp"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:layout_marginBottom="60dp"
android:gravity="center"
android:lineSpacingMultiplier="0.6"
android:text="@string/app_name"
android:textColor="@color/black"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout>
<ProgressBar
android:id="@+id/pbb"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="110dp"
android:indeterminateTint="@color/color_fffa64"
android:visibility="visible" />
</FrameLayout>

View File

@ -0,0 +1,70 @@
<?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">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginBottom="36dp"
android:visibility="visible">
<TextView
android:id="@+id/tvSet"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_centerInParent="true"
android:background="@drawable/shape_set_wallpaper_bg"
android:gravity="center"
android:minWidth="200dp"
android:paddingHorizontal="28dp"
android:text="@string/set_wallpaper"
android:textColor="@color/white"
android:textSize="16sp" />
</RelativeLayout>
<ImageView
android:id="@+id/ivBack"
android:layout_width="46dp"
android:layout_height="46dp"
android:layout_gravity="start"
android:layout_marginTop="10dp"
android:padding="8dp"
android:src="@drawable/ic_back" />
<FrameLayout
android:id="@+id/flPlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:visibility="gone">
<SurfaceView
android:id="@+id/surfaceVideo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible" />
<ImageView
android:id="@+id/ivClose"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="end"
android:layout_marginEnd="10dp"
android:layout_marginTop="14dp"
android:src="@drawable/img_x"
android:visibility="visible" />
</FrameLayout>
</FrameLayout>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewPager"
android:paddingTop="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="52dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="52dp"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/llHome"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/ivHome"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/selector_home_tab" />
</LinearLayout>
<LinearLayout
android:id="@+id/llSettings"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/ivSettings"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/selector_set_tab" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,77 @@
<?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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:background="@drawable/shape_theme_gray_8">
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginTop="24dp"
app:layout_constraintRight_toRightOf="parent"
android:text="@string/rate_us"
android:textColor="@color/black"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center"
android:paddingStart="24dp"
android:paddingEnd="24dp"
android:text="@string/rate_us_content"
android:textColor="@color/black"
android:textSize="12sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvTitle" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_start"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_content"
android:layout_marginTop="24dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_cancel"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginTop="24dp"
android:gravity="center"
android:text="@string/cancel"
android:textColor="@color/color_999999"
android:textSize="12sp"
android:textStyle="bold"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/tv_rate_it"
app:layout_constraintTop_toBottomOf="@id/recycler_start" />
<TextView
android:id="@+id/tv_rate_it"
android:layout_width="0dp"
android:layout_height="40dp"
android:gravity="center"
android:text="@string/rate_it"
android:textColor="@color/selector_rate_it"
android:textSize="12sp"
android:textStyle="bold"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/tv_cancel"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_cancel" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_gravity="top"
android:gravity="center"
android:text="@string/settings"
android:textColor="@color/text_title"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:id="@+id/tvRateUs"
android:layout_marginStart="16dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="16dp"
android:background="@drawable/shape_theme_gray_8"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:text="@string/rate_us"
android:textColor="@color/text_title"
android:textSize="16sp"
android:textStyle="bold" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
android:background="@drawable/shape_theme_gray_8"
android:paddingVertical="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginStart="16dp"
android:text="@string/version"
android:textColor="@color/text_title"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvVersion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="16dp"
android:alpha="0.4"
android:text="@string/version"
android:textColor="@color/text_title"
android:textSize="16sp" />
</RelativeLayout>
</LinearLayout>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">
<com.scwang.smart.refresh.layout.SmartRefreshLayout
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.scwang.smart.refresh.header.MaterialHeader
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="2dp" />
<com.scwang.smart.refresh.footer.ClassicsFooter
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
</FrameLayout>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="MissingDefaultResource">
<ImageView
android:id="@+id/ivWallpaper"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:scaleType="centerCrop" />
<ImageView
android:id="@+id/ivPlay"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_gravity="center"
android:padding="30dp"
android:src="@drawable/ic_play" />
<ImageView
android:id="@+id/ivPlaceholder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginHorizontal="24dp"
android:src="@mipmap/live_logo" />
</FrameLayout>

View File

@ -0,0 +1,17 @@
<?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"
android:layout_width="wrap_content"
android:id="@+id/cons_start"
android:layout_height="wrap_content"
android:padding="10dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imStart"
android:src="@drawable/selector_start"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 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:layout_width="match_parent"
android:layout_height="174dp"
app:cardCornerRadius="4dp"
android:background="@color/color_cb39a7"
tools:ignore="MissingDefaultResource">
<ImageView
android:id="@+id/ivPlaceholder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginHorizontal="24dp"
android:src="@mipmap/live_logo" />
<ImageView
android:id="@+id/ivWallpaper"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:scaleType="centerCrop" />
</androidx.cardview.widget.CardView>

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape_theme_gray_8"
android:orientation="vertical"
android:paddingStart="22dp"
android:paddingEnd="22dp"
android:paddingBottom="22dp">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:gravity="center"
android:text="@string/loading_video"
android:textColor="@color/text_title"
android:textSize="16sp"
android:textStyle="bold" />
<com.akexorcist.roundcornerprogressbar.RoundCornerProgressBar
android:id="@+id/pbb"
android:layout_width="match_parent"
android:layout_height="8dp"
android:layout_below="@id/tvPercent"
android:layout_gravity="center"
android:layout_marginHorizontal="32dp"
android:layout_marginTop="16dp"
app:rcBackgroundColor="@color/white"
app:rcProgressColor="@color/color_cb39a7" />
<TextView
android:id="@+id/tvPercent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tvTitle"
android:layout_marginTop="16dp"
android:alpha="0.54"
android:gravity="center"
android:textColor="@color/text_title"
android:textSize="16sp"
tools:text="54%" />
<ImageView
android:id="@+id/ivClose"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginEnd="6dp"
android:padding="6dp"
android:src="@drawable/img_x" />
</RelativeLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="color_cb39a7">#FFcb39a7</color>
<color name="color_fffa64">#FFfffa64</color>
<color name="theme_gray">#FFEEEEEE</color>
<color name="text_title">#FF000000</color>
<color name="color_999999">#999999</color>
</resources>

View File

@ -0,0 +1,11 @@
<resources>
<string name="app_name">LiveWallpaper</string>
<string name="settings">Settings</string>
<string name="set_wallpaper">Set Wallpaper</string>
<string name="rate_us_content">We hope this app is useful for you, if it does, would youplease give us a 5 sar and a mice revtew on Google Play, it really helps!</string>
<string name="cancel">CANCEL</string>
<string name="rate_it">RATE IT</string>
<string name="loading_video">Loading video...</string>
<string name="version">Version</string>
<string name="rate_us">Rate us</string>
</resources>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppDialog" parent="@android:style/Theme.Dialog">
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
</resources>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.LiveWallpaper" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="android:statusBarColor">@color/color_cb39a7</item>
</style>
</resources>

View 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 that 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>

View 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>

View File

@ -0,0 +1,6 @@
<?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/ic_launcher">
</wallpaper>

View File

@ -0,0 +1,17 @@
package com.live.wallpaper.style.hd
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit hd, 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)
}
}

BIN
app/testlivewallpaper.jks Normal file

Binary file not shown.

5
build.gradle.kts Normal file
View File

@ -0,0 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.1.3" apply false
id("org.jetbrains.kotlin.android") version "1.8.10" apply false
}

24
gradle.properties Normal file
View File

@ -0,0 +1,24 @@
# 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. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec: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
android.enableJetifier=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

60
gradle/libs.versions.toml Normal file
View File

@ -0,0 +1,60 @@
[versions]
agp = "7.3.0"
appLovin-quality-service-gradleplugin = "4.13.2"
google-material = "1.11.0"
kotlin = "1.8.21"
core-ktx = "1.9.0"
junit = "4.13.2"
androidx-test-ext-junit = "1.1.5"
espresso-core = "3.5.1"
appcompat = "1.6.1"
material = "1.11.0"
multidex = "2.0.1"
glide = "4.15.1"
lifecycle = "2.6.1"
activity-ktx = "1.7.2"
fragment-ktx = "1.6.1"
rxbinding = "4.0.0"
smart-refresh-layout = "2.0.6"
flyco-tabLayout = "3.0.0"
commons-codec = "1.15"
okhttp3-okhttp = "4.10.0"
progress-bar = "2.1.2"
google-services = "4.3.15"
firebase-crashlytics = "2.9.9"
[libraries]
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" }
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" }
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
androidx-multidex = { module = "androidx.multidex:multidex", version.ref = "multidex" }
glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" }
lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycle" }
activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activity-ktx" }
fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragment-ktx" }
jakewharton-rxbinding4 = { module = "com.jakewharton.rxbinding4:rxbinding", version.ref = "rxbinding" }
material-1_11_0 = { module = "com.google.android.material:material", version.ref = "google-material" }
smart-refresh-kernel = { module = "io.github.scwang90:refresh-layout-kernel", version.ref = "smart-refresh-layout" }
smart-refresh-material-header = { module = "io.github.scwang90:refresh-header-material", version.ref = "smart-refresh-layout" }
smart-refresh-classics-footer = { module = "io.github.scwang90:refresh-footer-classics", version.ref = "smart-refresh-layout" }
flyco-tabLayout = { module = "io.github.h07000223:flycoTabLayout", version.ref = "flyco-tabLayout" }
commons-codec = { module = "commons-codec:commons-codec", version.ref = "commons-codec" }
okhttp3-okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp3-okhttp" }
com-akexorcist-progress-bar = { group = "com.akexorcist", name = "round-corner-progress-bar", version.ref = "progress-bar" }
[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
googleServices = { id = "com.google.gms.google-services", version.ref = "google-services" }
firebaseCrashlytics = { id = "com.google.firebase.crashlytics", version.ref = "firebase-crashlytics" }
[bundles]

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Fri Mar 15 15:37:22 CST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

185
gradlew vendored Normal file
View 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
View 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

19
settings.gradle.kts Normal file
View File

@ -0,0 +1,19 @@
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { setUrl("https://jitpack.io") }
}
}
rootProject.name = "LiveWallpaper"
include(":app")