Commit 679da567 authored by wanglei's avatar wanglei

..

parent 940128af
...@@ -156,5 +156,9 @@ dependencies { ...@@ -156,5 +156,9 @@ dependencies {
implementation(libs.lottie) implementation(libs.lottie)
implementation(libs.expandablerecyclerview) implementation(libs.expandablerecyclerview)
implementation(libs.okhttp)
implementation(libs.logging.interceptor)
} }
package com.base.scanqrclear.luma
import android.util.Base64
import com.base.scanqrclear.GlobalConfig.KEY_AES
import java.nio.charset.Charset
import java.security.SecureRandom
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec
object AESHelps {
private val AES_CIPHER_TRANSFORMATION = "AES/GCM/NoPadding" // 明确指定加密算法
// 使用单例模式初始化Cipher,避免每次加密解密都重新创建
private val cipher: Cipher by lazy {
Cipher.getInstance(AES_CIPHER_TRANSFORMATION)
}
// 使用单例模式初始化SecretKeySpec,避免每次加密解密都重新创建
private val secretKey: SecretKeySpec by lazy {
SecretKeySpec(KEY_AES.toByteArray(Charset.defaultCharset()), "AES")
}
fun encrypt(content: String): String {
try {
// 初始化向量IV,确保每次加密都是随机的
val iv = generateIv()
// 初始化GCM参数规范
val gcmParameterSpec = GCMParameterSpec(128, iv)
// 初始化Cipher为加密模式
cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmParameterSpec)
// 加密内容
val encryptedBytes = cipher.doFinal(content.toByteArray(Charset.defaultCharset()))
// 将IV和加密数据合并,并进行Base64编码
val message = iv + encryptedBytes
return Base64.encodeToString(message, Base64.NO_WRAP)
} catch (_: Exception) {
return content
}
}
fun decrypt(content: String): String {
try {
// 将Base64编码的字符串解码为字节数组
val contentBytes = Base64.decode(content, Base64.NO_WRAP)
// 提取IV
val iv = contentBytes.copyOfRange(0, 12)
// 提取加密数据
val encryptedBytes = contentBytes.copyOfRange(12, contentBytes.size)
// 初始化GCM参数规范
val gcmParameterSpec = GCMParameterSpec(128, iv)
// 初始化Cipher为解密模式
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmParameterSpec)
// 解密内容
val decryptedBytes = cipher.doFinal(encryptedBytes)
// 将解密后的字节数组转换为字符串
return String(decryptedBytes, Charset.defaultCharset())
} catch (_: Exception) {
return content
}
}
// 生成随机的初始化向量IV
private fun generateIv(): ByteArray {
val iv = ByteArray(12)
SecureRandom().nextBytes(iv)
return iv
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.util.Base64
import com.base.scanqrclear.BuildConfig
import com.base.scanqrclear.GlobalConfig.PACKAGE_NAME
import com.base.scanqrclear.GlobalConfig.URL_API
import com.base.scanqrclear.helper.EventUtils
import com.base.scanqrclear.luma.AdmobHelps.KEY_GOOGLE_ADVERTISER_ID
import com.base.scanqrclear.luma.AdmobHelps.KEY_REFERRER
import com.base.scanqrclear.luma.AdmobHelps.KEY_UUID
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import okhttp3.Call
import okhttp3.Callback
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor
import org.json.JSONObject
import java.io.IOException
object APIUtils {
private val configUrl by lazy {
val url = StringBuilder("${URL_API}/${PACKAGE_NAME.filter { it.isLowerCase() }.substring(4, 9)}spk")
url.append("?pkg=$PACKAGE_NAME")
val referrer = SpUtils.getInstance().getString(KEY_REFERRER)
url.append("&referrer=${Base64.encodeToString(referrer.toByteArray(), Base64.DEFAULT)}")
url.append("&vn=${BuildConfig.VERSION_NAME}")
url.append("&vc=${BuildConfig.VERSION_CODE}")
url.append("&device=${SpUtils.getInstance().getString(KEY_GOOGLE_ADVERTISER_ID)}")
url.append("&aid=${SpUtils.getInstance().getString(KEY_UUID)}")
url.append("&mode=4")
url.toString()
}
private val blacklistUrl by lazy {
val url = StringBuilder("${URL_API}/${PACKAGE_NAME.filter { it.isLowerCase() }.substring(4, 9)}cl")
url.append("?pkg=${PACKAGE_NAME}")
url.toString()
}
fun requestConfig(block: () -> Unit) {
val request = Request.Builder()
.url(configUrl)
.get()
.build()
val client = createOkHttpClient()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
EventUtils.event("api_config_error", value = e.toString())
}
override fun onResponse(call: Call, response: Response) {
response.body?.string()?.let {
val result = Regex("\"data\":\"(.*?)\"").find(it)
if (result != null && result.toString() != "null") {
result.groupValues[1].let {
try {
val str = AESHelps.decrypt(it)
val gson = Gson()
val type = object : TypeToken<Map<String, Int>>() {}.type
val configMap = gson.fromJson<Map<String, Int>>(str, type)
configMap.forEach { (t, u) ->
SpUtils.getInstance().put(t, u)
}
block.invoke()
val jsonObject = JSONObject()
jsonObject.put("ut", SpUtils.getInstance().getInt("ut"))
EventUtils.event("user_type", ext = jsonObject)
} catch (_: Exception) {
}
}
}
}
}
})
}
fun requestBlacklist() {
val data = JSONObject()
.put("bp", DeviceHelps.getConfigParams())
.toString()
val body = AESHelps.encrypt(data)
.toRequestBody("application/json;charset=utf-8".toMediaTypeOrNull())
val request = Request.Builder()
.url(blacklistUrl)
.post(body)
.build()
val client = createOkHttpClient()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
EventUtils.event("api_blacklist_error", value = e.toString())
}
override fun onResponse(call: Call, response: Response) {
response.body?.string()?.let {
val result = Regex("\"data\":\"(.*?)\"").find(it)
if (result != null && result.toString() != "null") {
result.groupValues[1].let {
val str = AESHelps.decrypt(it)
val blacklist = if (str == "true") 0 else 1
// GlobalConfig.blacklist = blacklist
}
}
}
}
})
}
private fun createOkHttpClient(): OkHttpClient {
val client = OkHttpClient.Builder().apply {
if (BuildConfig.DEBUG) {
addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
})
}
}.build()
return client
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.app.Activity
import android.content.Context
import android.content.Intent
import com.base.scanqrclear.luma.AdmobHelps.ID_CLEAN_JUNK
import com.base.scanqrclear.luma.AdmobHelps.ID_LARGE_FILE_CLEANER
import com.base.scanqrclear.luma.AdmobHelps.ID_PHOTO_COMPRESSION
import com.base.scanqrclear.luma.AdmobHelps.ID_SCREENSHOT_CLEAN
import com.base.scanqrclear.luma.AdmobHelps.ID_WHATSAPP
import com.base.scanqrclear.utils.ActivityLauncher
object ActivityJumpHelps {
private var isShowStoragePermission = false
fun start(
context: Context,
launcher: ActivityLauncher,
nameId: Int
) {
when(nameId) {
// R.string.junk_scan -> requestPermission(context, launcher) { CleanJunkActivity.start(context) }
// R.string.battery_info -> BatteryInfoActivity.start(context)
// R.string.app_process -> AppProcessActivity.start(context)
// R.string.whatsapp_clean -> requestPermission(context, launcher) { WhatsappCleanActivity.start(context) }
// R.string.screenshot_clean -> requestPermission(context, launcher) { ScreenshotCleanActivity.start(context) }
// R.string.app_manager -> AppManagerActivity.start(context)
// R.string.large_files -> requestPermission(context, launcher) { LargeFileCleanActivity.start(context) }
// R.string.image_compressor -> requestPermission(context, launcher) { PhotoCompressionActivity.start(context) }
// R.string.similar_photos -> requestPermission(context, launcher) { SimilarPhotosActivity.start(context) }
}
}
fun startFunction(
context: Context,
launcher: ActivityLauncher,
notificationId: Int
) {
when (notificationId) {
// ID_CLEAN_JUNK -> requestPermission(context, launcher) { CleanJunkActivity.start(context) }
// ID_WHATSAPP -> requestPermission(context, launcher) { WhatsappCleanActivity.start(context) }
// ID_LARGE_FILE_CLEANER -> requestPermission(context, launcher) { LargeFileCleanActivity.start(context) }
// ID_PHOTO_COMPRESSION -> requestPermission(context, launcher) { PhotoCompressionActivity.start(context) }
// ID_SCREENSHOT_CLEAN -> requestPermission(context, launcher) { ScreenshotCleanActivity.start(context) }
}
}
fun toFunction(context: Activity, notificationId: Int) {
if (!PermissionHelps.checkFilesAccessPermission(context)
&& (notificationId == ID_CLEAN_JUNK
|| notificationId == ID_LARGE_FILE_CLEANER
|| notificationId == ID_PHOTO_COMPRESSION
|| notificationId == ID_WHATSAPP
|| notificationId == ID_SCREENSHOT_CLEAN)) {
// context.startActivity(Intent(context, MainActivity::class.java).apply { putExtra(KEY_NOTIFICATION_ID, notificationId) })
return
}
when (notificationId) {
// ID_CLEAN_JUNK -> CleanJunkActivity.start(context)
// ID_WHATSAPP -> WhatsappCleanActivity.start(context)
// ID_BATTERY_INFO -> BatteryInfoActivity.start(context)
// ID_LARGE_FILE_CLEANER -> LargeFileCleanActivity.start(context)
// ID_PHOTO_COMPRESSION -> PhotoCompressionActivity.start(context)
// ID_SCREENSHOT_CLEAN -> ScreenshotCleanActivity.start(context)
// ID_APP_INSTALL -> AppManagerActivity.start(context)
// ID_APP_UNINSTALL -> AppManagerActivity.start(context)
// ID_NOT_CLEANED -> CleanJunkActivity.start(context)
// ID_BATTERY_LEVEL -> BatteryInfoActivity.start(context)
// ID_APP_MANAGER -> AppManagerActivity.start(context)
// ID_HOME -> MainActivity.start(context)
}
}
fun requestPermission(
context: Context,
launcher: ActivityLauncher,
block: (() -> Unit?)? = null
) {
if (PermissionHelps.checkFilesAccessPermission(context)) {
block?.invoke()
} else {
if (isShowStoragePermission) return
isShowStoragePermission = true
DialogHelps.showStoragePermissionDialog(
context,
{
PermissionHelps.requestFilesAccessPermission(context, launcher, result = {
if (it) block?.invoke()
isShowStoragePermission = false
})
},
{
isShowStoragePermission = false
}
)
}
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.app.Activity
import java.util.Stack
object ActivityManagerHelps {
private val activityStack = Stack<Activity>()
/**
* 添加Activity到堆栈
*/
fun add(activity: Activity) {
activityStack.add(activity)
}
/**
* 移除Activity从堆栈
*/
fun remove(activity: Activity) {
activityStack.remove(activity)
}
/**
* 结束指定的Activity
*/
fun finish(activity: Activity?) {
if (activity != null) {
activityStack.remove(activity)
activity.finish()
}
}
/**
* 结束所有Activity
*/
fun finishAll() {
for (activity in activityStack) {
activity?.finish()
}
activityStack.clear()
}
fun finishAll(excludeCls: Class<*>?) {
val iterator = activityStack.iterator()
while (iterator.hasNext()) {
val item = iterator.next()
if (excludeCls != item.javaClass) {
item.finish()
iterator.remove()
}
}
}
/**
* 检查Activity是否存在于堆栈中
*/
fun isActivityInStack(cls: Class<*>?): Boolean {
var isExist = false
if (cls != null) {
for (activity in activityStack) {
if (cls == activity.javaClass) {
isExist = true
break
}
}
}
return isExist
}
val all: List<Activity>
get() = activityStack
val topActivity: Activity?
get() = if (activityStack.isEmpty()) {
null
} else {
activityStack.peek()
}
}
\ No newline at end of file
This diff is collapsed.
package com.base.scanqrclear.luma
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.app.Activity
import android.app.Dialog
import android.os.Bundle
import android.view.View
import android.view.animation.LinearInterpolator
import android.widget.Toast
import androidx.activity.addCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.lifecycle.lifecycleScope
import com.airbnb.lottie.LottieAnimationView
import com.base.scanqrclear.R
import com.base.scanqrclear.helper.EventUtils
import com.base.scanqrclear.luma.AdmobHelps.KEY_CLEANUP_SIZE
import com.base.scanqrclear.ui.main.MainActivity
import com.base.scanqrclear.utils.ActivityLauncher
import com.base.scanqrclear.utils.ExitType
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.random.Random
open class BaseActivity2 : AppCompatActivity() {
protected lateinit var launcher: ActivityLauncher
protected var loadingDialog: Dialog? = null
protected var isDisableBack = false
protected var isExit = false
private var isShowAdInterstitial = false
private var isPause = false
private var lottieType: LottieType? = null
private var complete: (() -> Unit?)? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
launcher = ActivityLauncher(this)
immersive()
//todo 返回
// addBackPressedCallback()
ActivityManagerHelps.add(this)
EventUtils.event("${javaClass.simpleName}_show")
}
override fun onResume() {
super.onResume()
isPause = false
// if (isShowAdInterstitial) {
// lifecycleScope.launch {
// delay(1000)
// startAdInterstitial()
// }
// }
}
override fun onPause() {
super.onPause()
isPause = true
}
override fun onDestroy() {
super.onDestroy()
ActivityManagerHelps.remove(this)
isExit = false
lottieType = null
complete = null
}
protected open fun immersive() {
StatusBarHelps.immersive(this, getColor(R.color.color_ffb764))
}
protected fun showAnimationAd(
lottieType: LottieType = LottieType.CLEAN,
isShowAnimation: Boolean = true,
complete: (() -> Unit?)? = null
) {
this.lottieType = lottieType
this.complete = complete
showAdInterstitial(AdmobHelps.isShowAdInter()) {
val animationView = findViewById<ConstraintLayout>(R.id.animation)
animationView.setOnClickListener { }
if (isShowAnimation) {
StatusBarHelps.immersive(this, getColor(R.color.color_ffb764))
showAnimation(animationView, lottieType, complete)
} else {
complete?.invoke()
}
}
// if (isShowAnimation) {
// StatusBarHelps.immersive(this, getColor(R.color.color_ffb764))
// val animationView = findViewById<ConstraintLayout>(R.id.animation)
// showAnimation(animationView, lottieType) { startAdInterstitial() }
// } else {
// startAdInterstitial()
// }
}
// protected fun startAdInterstitial() {
// if (this is SplashActivity || this is MainActivity) return
// isShowAdInterstitial = true
// if (!isPause) {
// val animationView = findViewById<ConstraintLayout>(R.id.animation)
// showAdInterstitial(animationView, complete)
// }
// }
protected fun showAdInterstitial(isShow: Boolean, complete: (() -> Unit?)? = null) {
if (this.isFinishing || this.isDestroyed || isShowAdInterstitial) return
isShowAdInterstitial = true
if (isShow) {
AdmobHelps.showInterstitialAd(
this,
dismissed = {
clearLoading()
immersive()
complete?.invoke()
},
completed = {
StatusBarHelps.immersive(this, getColor(R.color.black))
loadingDialog?.dismiss()
},
failed = {
clearLoading()
immersive()
complete?.invoke()
}
)
} else {
isShowAdInterstitial = false
complete?.invoke()
}
}
protected fun showAnimation(
view: View,
lottieType: LottieType,
complete: (() -> Unit?)? = null
) {
isDisableBack = true
view.visibility = View.VISIBLE
val progress = view.findViewById<androidx.appcompat.widget.AppCompatTextView>(R.id.tv_progress)
progress.text = "0%"
val lottie = view.findViewById<LottieAnimationView>(R.id.lottie_animation)
lottie.setAnimation(lottieType.data)
lottie.loop(isLoop(lottieType))
lottie.playAnimation()
if (!lottieType.images.isNullOrEmpty())
lottie.imageAssetsFolder = lottieType.images
if (!isLoop(lottieType)) {
lottie.addAnimatorUpdateListener { animation ->
val value = animation.animatedValue as Float * 100
progress.text = "${value.toInt()}%"
if (value.toInt() == 100) {
view.visibility = View.GONE
complete?.invoke()
isDisableBack = false
}
}
return
}
lifecycleScope.launch(Dispatchers.Main) {
val durationTime = Random.Default.nextLong(3000, 3500)
ValueAnimator.ofInt(0, 100).apply {
duration = durationTime
interpolator = LinearInterpolator()
addUpdateListener { animation ->
val value = animation.animatedValue as Int
progress.text = "${value}%"
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
view.visibility = View.GONE
complete?.invoke()
isDisableBack = false
lottie.cancelAnimation()
}
})
}.start()
}
}
private fun isLoop(lottieType: LottieType): Boolean {
return lottieType != LottieType.CLEAN
}
private fun clearLoading() {
loadingDialog?.dismiss()
loadingDialog = null
isShowAdInterstitial = false
}
protected fun cleanFiles(list: List<FileBean>) {
lifecycleScope.launch(Dispatchers.IO) {
val paths = list.filter { it.isSelected }.map { it.path }.toTypedArray()
paths.forEach { FileHelps.deleteFile(it) }
withContext(Dispatchers.Main) {
MediaHelps.updateMedia(applicationContext, paths)
}
}
}
protected fun toCleanResult(size: Long, titleName: String) {
val cleanupSize = SpUtils.getInstance().getLong(KEY_CLEANUP_SIZE)
SpUtils.getInstance().putLong(KEY_CLEANUP_SIZE, cleanupSize + size)
CleanResultActivity.start(this, size, titleName)
ActivityManagerHelps.finishAll(MainActivity::class.java)
}
protected fun backPressed() {
onBackPressedDispatcher.onBackPressed()
}
protected open fun handleBackPressed(activity: Activity) {
when (activity) {
is MainActivity -> logout()
// is AppManagerActivity -> exit(ExitType.APP_MANAGER)
// is BatteryInfoActivity -> exit(ExitType.BATTERY_INFO)
// is CleanJunkActivity -> exit(ExitType.CLEAN)
// is LargeFileCleanActivity -> exit(ExitType.LARGE_FILE)
// is ScreenshotCleanActivity -> exit(ExitType.SCREENSHOT)
// is SimilarPhotosActivity -> exit(ExitType.SIMILAR_PHOTOS)
// is WhatsappCleanActivity -> exit(ExitType.WHATSAPP)
// is PhotoCompressionActivity -> exit(ExitType.PHOTO_COMPRESSION)
// else -> finishOrToMain()
}
}
private fun logout() {
DialogHelps.showLogoutDialog(this, {
ActivityManagerHelps.finishAll()
// exitProcess(0)
}, {
ActivityJumpHelps.start(this, launcher, R.string.junk_scan)
})
}
protected fun showExitDialog(title: String, content: CharSequence) {
if (isExit) return
isExit = true
DialogHelps.showExitDialog(
this,
title,
content,
{ showAdInterstitial(AdmobHelps.isShowAdBackInter()) { finishOrToMain() } },
{ isExit = false }
)
}
private fun exit(exit: ExitType) {
showExitDialog(getString(exit.title), getString(exit.content))
}
private fun addBackPressedCallback(activity: Activity) {
onBackPressedDispatcher.addCallback {
if (isDisableBack) {
Toast.makeText(applicationContext, getString(R.string.wait_a_moment), Toast.LENGTH_SHORT).show()
} else {
if (isShowAdInterstitial) return@addCallback
handleBackPressed(activity)
}
}
}
protected fun finishOrToMain() {
// if (this !is MainActivity
// && !ActivityManagerHelps.isActivityInStack(MainActivity::class.java)
// ) {
// MainActivity.start(this)
// }
// finish()
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
abstract class BaseAdapter<T, VB : ViewBinding>(
private var items: List<T> = emptyList()
) : RecyclerView.Adapter<BaseViewHolder<VB>>() {
interface OnClickCallback<T> {
fun onClicked(view: View, position: Int, item: T)
}
var callback: OnClickCallback<T>? = null
fun submitList(data: List<T>) {
items = data
notifyDataSetChanged()
}
fun add(item: T) {
items = items.toMutableList().apply { add(item) }
notifyItemInserted(items.size - 1)
}
val list: MutableList<T> get() = items.toMutableList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<VB> {
return BaseViewHolder(getViewBinding(LayoutInflater.from(parent.context), parent))
}
override fun onBindViewHolder(holder: BaseViewHolder<VB>, position: Int) {
bind(holder, position, items[position])
}
override fun getItemCount(): Int = items.size
abstract fun getViewBinding(layoutInflater: LayoutInflater, parent: ViewGroup): VB
abstract fun bind(holder: BaseViewHolder<VB>, position: Int, item: T)
}
\ No newline at end of file
package com.base.scanqrclear.luma
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
class BaseViewHolder<VB : ViewBinding>(val binding: VB) : RecyclerView.ViewHolder(binding.root)
\ No newline at end of file
package com.base.scanqrclear.luma
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import com.base.scanqrclear.R
import com.base.scanqrclear.databinding.ActivityCleanResultBinding
class CleanResultActivity : BaseActivity2() {
companion object {
var total = 0L
var titleName = ""
fun start(context: Context, total: Long, titleName: String) {
Companion.total = total
Companion.titleName = titleName
val intent = Intent(context, CleanResultActivity::class.java)
context.startActivity(intent)
}
}
private val binding by lazy {
ActivityCleanResultBinding.inflate(layoutInflater)
}
private lateinit var adapter: CleanResultAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
initView()
}
//todo
// override fun handleBackPressed() {
// showAdInterstitial(AdmobHelps.isShowAdResultBackInter()) { finishOrToMain() }
// }
private fun initView() {
adapter = CleanResultAdapter(getData())
adapter.callback = object : BaseAdapter.OnClickCallback<FunctionBean> {
override fun onClicked(view: View, position: Int, item: FunctionBean) {
ActivityJumpHelps.start(this@CleanResultActivity, launcher, item.name)
finish()
}
}
binding.rvResult.adapter = adapter
binding.rvResult.layoutManager = LinearLayoutManager(this)
if (titleName.isNotEmpty()) binding.tvTitle.text = titleName
binding.tvCleanedUp.text = "${getString(R.string.cleaned_up)} ${Utils.getSize(total)}"
binding.flBack.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
}
private fun getData(): List<FunctionBean> {
val list = mutableListOf<FunctionBean>().apply {
add(FunctionBean(R.mipmap.icon_junk_scan1, R.string.junk_scan, R.string.result_clean_junk, text = R.string.clean_now))
add(FunctionBean(R.mipmap.icon_battery_1, R.string.battery_info, R.string.result_battery_info, text = R.string.view))
add(FunctionBean(R.mipmap.icon_app_process_1, R.string.app_process, R.string.result_app_processes, text = R.string.view))
add(FunctionBean(R.mipmap.icon_large_1, R.string.large_files, R.string.result_large_file, text = R.string.clean_now))
add(FunctionBean(R.mipmap.icon_image, R.string.image_compressor, R.string.result_photo_compression, text = R.string.compress))
add(FunctionBean(R.mipmap.icon_screenshot_1, R.string.screenshot_clean, R.string.result_screenshot_clean, text = R.string.clean_now))
add(FunctionBean(R.mipmap.icon_similar_1, R.string.similar_photos, R.string.result_similar_photos, text = R.string.clean_now))
add(FunctionBean(R.mipmap.icon_app_1, R.string.app_manager, R.string.result_app_manager, text = R.string.view))
add(FunctionBean(R.mipmap.icon_whatsapp_1, R.string.whatsapp_clean, R.string.result_whatsapp_clean, text = R.string.clean_now))
}
val filteredList = list.filter { getString(it.name) != titleName }
val randomIndices = filteredList.indices.shuffled().take(4).toList()
val data = randomIndices.map { filteredList[it] }
return data
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.animation.ObjectAnimator
import android.view.LayoutInflater
import android.view.ViewGroup
import com.base.scanqrclear.databinding.ItemCleanResultBinding
class CleanResultAdapter(
val data: List<FunctionBean>
) : BaseAdapter<FunctionBean, ItemCleanResultBinding>(data) {
override fun getViewBinding(
layoutInflater: LayoutInflater,
parent: ViewGroup
): ItemCleanResultBinding {
return ItemCleanResultBinding.inflate(layoutInflater, parent, false)
}
override fun bind(
holder: BaseViewHolder<ItemCleanResultBinding>,
position: Int,
item: FunctionBean
) {
holder.binding.ivImage.setImageResource(item.icon)
holder.binding.tvName.setText(item.name)
holder.binding.tvContent.setText(item.content)
holder.binding.tvCleanNow.setText(item.text)
holder.binding.tvCleanNow.setOnClickListener {
callback?.onClicked(it, position, item)
}
val translationX = holder.itemView.context.resources.displayMetrics.widthPixels.toFloat()
holder.itemView.translationX = -translationX
ObjectAnimator.ofFloat(holder.itemView, "translationX", -translationX, 0f).apply {
duration = 1000
startDelay = (position + 1) * 300L
start()
}
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.os.Build
import android.util.Log
import com.base.scanqrclear.BuildConfig
import com.base.scanqrclear.GlobalConfig.PACKAGE_NAME
import com.base.scanqrclear.MyApplication
import com.base.scanqrclear.luma.AdmobHelps.KEY_DEVICE_NAME
import com.base.scanqrclear.luma.AdmobHelps.KEY_GOOGLE_ADVERTISER_ID
import com.base.scanqrclear.luma.AdmobHelps.KEY_UUID
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import org.json.JSONObject
import java.util.Locale
import java.util.TimeZone
object DeviceHelps {
fun init() {
MainScope().launch(Dispatchers.IO) {
getGoogleAdvertiserId()
getDeviceName()
}
}
private fun getGoogleAdvertiserId() {
try {
val googleAdvertiserId = AdvertisingIdClient.getAdvertisingIdInfo(MyApplication.appContext).id ?: ""
if (googleAdvertiserId.isNotEmpty())
SpUtils.getInstance().putString(KEY_GOOGLE_ADVERTISER_ID, googleAdvertiserId)
} catch (e: Exception) {
Log.d("TAG", "getGoogleAdvertiserId error: ${e.localizedMessage}")
}
}
private fun getDeviceName() {
val manufacturer = Build.MANUFACTURER
val model = Build.MODEL
val flag = model.lowercase(Locale.getDefault()).startsWith(manufacturer.lowercase(Locale.getDefault()))
val deviceName = if (flag) {
if (model.isNullOrEmpty()) {
model
} else {
model.substring(0, 1)
.uppercase(Locale.getDefault()) + model.substring(1)
.lowercase(Locale.getDefault())
}
} else {
val ss = if (manufacturer.isNullOrEmpty()) {
manufacturer
} else {
manufacturer.substring(0, 1)
.uppercase(Locale.getDefault()) + manufacturer.substring(1)
.lowercase(Locale.getDefault())
}
"$ss $model"
}
SpUtils.getInstance().putString(KEY_DEVICE_NAME, deviceName)
}
// 获取配置参数
fun getConfigParams(): JSONObject {
val packageName = PACKAGE_NAME
val jsonObject = JSONObject()
jsonObject.put("${packageName}_3", SpUtils.getInstance().getString(KEY_DEVICE_NAME))//手机型号
jsonObject.put("${packageName}_4", Build.MANUFACTURER)//手机厂商
jsonObject.put("${packageName}_5", Build.VERSION.SDK_INT)//android系统版本号
jsonObject.put("${packageName}_8", BuildConfig.VERSION_NAME)//APP版本号,如:1.1.2
jsonObject.put("${packageName}_9", SpUtils.getInstance().getString(KEY_UUID))//Android id
jsonObject.put("${packageName}_10", SpUtils.getInstance().getString(KEY_GOOGLE_ADVERTISER_ID))//Google advertiser id
jsonObject.put("${packageName}_13", "android")//platform 默认android
jsonObject.put("${packageName}_14", BuildConfig.VERSION_CODE)//android版本,如:13
jsonObject.put("${packageName}_15", "google")
jsonObject.put("${packageName}_24", BuildConfig.BUILD_TYPE)//环境
val timeZone: TimeZone = TimeZone.getDefault()
jsonObject.put("${packageName}_34", timeZone.id) // 手机本地时区,值如下格式:America/New_York
return jsonObject
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.animation.ObjectAnimator
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.animation.LinearInterpolator
import com.base.scanqrclear.R
import com.base.scanqrclear.databinding.DialogDeleteBinding
import com.base.scanqrclear.databinding.DialogExitBinding
import com.base.scanqrclear.databinding.DialogLoadingBinding
import com.base.scanqrclear.databinding.DialogLogoutBinding
import com.base.scanqrclear.databinding.DialogNotificationBinding
import com.base.scanqrclear.databinding.DialogPermissionBinding
import com.base.scanqrclear.databinding.DialogScoreBinding
import com.base.scanqrclear.luma.AdmobHelps.KEY_SCORE
import com.base.scanqrclear.utils.ExitType
import com.google.android.material.bottomsheet.BottomSheetDialog
object DialogHelps {
fun showStoragePermissionDialog(context: Context, open: () -> Unit, dismiss: () -> Unit) {
val binding = DialogPermissionBinding.inflate(LayoutInflater.from(context))
val dialog = BottomSheetDialog(context, R.style.BottomSheetDialog).apply {
setContentView(binding.root)
show()
}
dialog.setOnDismissListener { dismiss.invoke() }
binding.tvOpenSettings.setOnClickListener {
it.isEnabled = false
open.invoke()
it.postDelayed({ dialog.dismiss() }, 500)
}
}
fun showNotificationDialog(context: Context, turnOn: () -> Unit, dismiss: () -> Unit) {
val binding = DialogNotificationBinding.inflate(LayoutInflater.from(context))
val dialog = BottomSheetDialog(context, R.style.BottomSheetDialog).apply {
setCancelable(false)
setCanceledOnTouchOutside(false)
setContentView(binding.root)
show()
}
binding.ivClose.setOnClickListener {
dismiss.invoke()
dialog.dismiss()
}
binding.tvTurnOn.setOnClickListener {
it.isEnabled = false
turnOn.invoke()
it.postDelayed({ dialog.dismiss() }, 500)
}
}
fun showScoreDialog(context: Context, view: View? = null): Dialog {
view?.isEnabled = false
val binding = DialogScoreBinding.inflate(LayoutInflater.from(context))
val dialog = Dialog(context, R.style.CustomDialogStyle).apply {
setCancelable(false)
setCanceledOnTouchOutside(false)
setContentView(binding.root)
show()
}
val starList = listOf(
binding.ivStar1,
binding.ivStar2,
binding.ivStar3,
binding.ivStar4,
binding.ivStar5,
)
var score = 0
starList.forEachIndexed { index, view ->
view.setOnClickListener {
starList.forEachIndexed { index2, view2 ->
view2.setImageResource(if (index2 <= index) R.mipmap.star_s else R.mipmap.star_n)
if (index == index2) scoreAnimation(view2)
}
score = index + 1
binding.lottieFace.cancelAnimation()
binding.lottieFace.setAnimation(if (score != 5) "top_rate_sad.json" else "top_rate_happy.json")
binding.lottieFace.playAnimation()
}
}
binding.ivClose.setOnClickListener {
view?.isEnabled = true
dialog.dismiss()
}
binding.tvSubmit.setOnClickListener {
if (score == 5) {
SpUtils.getInstance().putInt(KEY_SCORE, score)
}
try {
val url = "https://play.google.com/store/apps/details?id=${context.packageName}"
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
} catch (_: Exception) {
}
view?.isEnabled = true
dialog.dismiss()
}
return dialog
}
private fun scoreAnimation(view: View) {
ObjectAnimator.ofFloat(
view,
View.SCALE_X,
0.75f,
1.2f,
1f
).apply {
duration = 500
interpolator = LinearInterpolator()
start()
}
ObjectAnimator.ofFloat(
view,
View.SCALE_Y,
0.75f,
1.2f,
1f
).apply {
duration = 500
interpolator = LinearInterpolator()
start()
}
}
fun showDeleteDialog(context: Context, view: View, confirm: (() -> Unit?)?): DialogDeleteBinding {
view.isEnabled = false
val binding = DialogDeleteBinding.inflate(LayoutInflater.from(context))
val dialog = Dialog(context, R.style.CustomDialogStyle).apply {
setCancelable(false)
setCanceledOnTouchOutside(false)
setContentView(binding.root)
show()
}
binding.tvCancel.setOnClickListener {
dialog.dismiss()
view.isEnabled = true
}
binding.tvDelete.setOnClickListener {
it.isEnabled = false
dialog.dismiss()
confirm?.invoke()
view.isEnabled = true
}
return binding
}
fun showConfirmDialog(context: Context, view: View, confirm: (() -> Unit?)?) {
val binding = showDeleteDialog(context, view, confirm)
binding.tvTitle.text = context.getString(R.string.confirm)
binding.tvContent.text = context.getString(R.string.confirm_content)
binding.tvDelete.text = context.getString(R.string.compress)
}
fun showExitDialog(
context: Activity,
exit: ExitType,
confirm: () -> Unit,
dismiss: () -> Unit
) {
showExitDialog(context, context.getString(exit.title), context.getString(exit.content), confirm, dismiss)
}
fun showExitDialog(
context: Activity,
title: String,
content: CharSequence,
confirm: () -> Unit,
dismiss: () -> Unit
) {
val binding = DialogExitBinding.inflate(LayoutInflater.from(context))
val dialog = Dialog(context, R.style.CustomDialogStyle).apply {
setCancelable(false)
setCanceledOnTouchOutside(false)
setContentView(binding.root)
show()
}
binding.tvTitle.text = title
binding.tvContent.text = content
binding.ivCancel.setOnClickListener {
dialog.dismiss()
dismiss.invoke()
}
binding.tvCancel.setOnClickListener {
dialog.dismiss()
dismiss.invoke()
}
binding.tvSure.setOnClickListener {
it.isEnabled = false
dialog.dismiss()
confirm.invoke()
}
AdmobHelps.showNativeAd(context, completed = {
binding.adNative.setExitNativeAd(it)
}, maxCompleted = { nativeAdLoader, nativeMaxAd ->
binding.adNative.setExitNativeAd(nativeAdLoader, nativeMaxAd)
})
}
fun showLogoutDialog(context: Activity, confirm: () -> Unit, check: () -> Unit) {
val binding = DialogLogoutBinding.inflate(LayoutInflater.from(context))
val dialog = Dialog(context, R.style.CustomDialogStyle).apply {
setCancelable(false)
setCanceledOnTouchOutside(false)
setContentView(binding.root)
show()
}
binding.ivCancel.setOnClickListener { dialog.dismiss() }
binding.tvCancel.setOnClickListener {
it.isEnabled = false
dialog.dismiss()
check.invoke()
}
binding.tvExit.setOnClickListener {
it.isEnabled = false
dialog.dismiss()
confirm.invoke()
}
AdmobHelps.showNativeAd(context, completed = {
binding.adNative.setExitNativeAd(it)
}, maxCompleted = { nativeAdLoader, nativeMaxAd ->
binding.adNative.setExitNativeAd(nativeAdLoader, nativeMaxAd)
})
}
fun showLoadingDialog(context: Context): Dialog {
val binding = DialogLoadingBinding.inflate(LayoutInflater.from(context))
val dialog = Dialog(context, R.style.CustomDialogStyle).apply {
setCancelable(false)
setCanceledOnTouchOutside(false)
setContentView(binding.root)
show()
}
return dialog
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.os.Environment
import java.io.File
object FileHelps {
private const val WHATS_APP_MEDIA_DIR = "Android/media/com.whatsapp/WhatsApp/Media/"
fun findWhatsappFiles(): MutableList<FileBean> {
val rootDir = File(getAppSpecificDirPath(WHATS_APP_MEDIA_DIR))
// val rootDir = File(getAppSpecificDirPath("Pictures/"))
val list = findFilesRecursive(rootDir, arrayOf())
list.sortByDescending { it.lastModified }
return list
}
fun findEmptyFolders(): MutableList<FileBean> {
val externalStorageDir = Environment.getExternalStorageDirectory()
val filters = arrayOf("/storage/emulated/0/Android/data", "/storage/emulated/0/Android/obb")
val emptyFolders = getAllEmptyFolders(externalStorageDir, filters)
return emptyFolders.map { FileBean(it.name, it.path, length = 4 * 1024) }.toMutableList()
}
fun findTempFiles(): MutableList<FileBean> {
val rootDir = Environment.getExternalStorageDirectory()
return findFilesRecursive(rootDir, arrayOf(".temp"))
}
fun findApkFiles(): MutableList<FileBean> {
val rootDir = Environment.getExternalStorageDirectory()
return findFilesRecursive(rootDir, arrayOf(".apk", ".aab"))
}
fun findLogFiles(): MutableList<FileBean> {
val rootDir = Environment.getExternalStorageDirectory()
return findFilesRecursive(rootDir, arrayOf(".log"))
}
fun deleteFile(filePath: String) {
File(filePath).deleteIfExists()
}
fun File?.deleteIfExists(): Boolean {
if (this?.exists() == true) {
return this.delete()
}
return false
}
private fun findFilesRecursive(dir: File, suffixes: Array<String>): MutableList<FileBean> {
return dir.walk()
.filter { it.isFile && it.endsWith(suffixes) }
.map { FileBean(it.name, it.path, length = it.length(), lastModified = it.lastModified()) }
.toMutableList()
}
private fun File.endsWith(suffixes: Array<String>): Boolean {
return suffixes.isEmpty() || suffixes.any { name.lowercase().endsWith(it.lowercase()) }
}
private fun getAppSpecificDirPath(relativePath: String): String {
return "${Environment.getExternalStorageDirectory()}/$relativePath"
}
private fun getAllEmptyFolders(root: File, filters: Array<String>): List<File> {
return root.walk()
.filter {
it.isDirectory && !filters.contains(it.path) && !it.isHidden && it.list()?.isEmpty() == true
}
.toList()
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
class FunctionBean(
val icon: Int = 0,
val name: Int,
val content: Int = 0,
val text: Int = 0,
val backgroundId: Int = 0
)
\ No newline at end of file
package com.base.scanqrclear.luma
enum class LottieType(val data: String, val images: String? = null) {
APP_MANAGER("app_manager/scan/data.json", "app_manager/scan/images"),
APP_PROCESS("app_process/scan/data.json", "app_process/scan/images"),
BATTERY_INFO("battery_info/scan/data.json", "battery_info/scan/images"),
LARGE_FILE("large_files/scan/data.json", "large_files/scan/images"),
PHOTO_COMPRESSION("photo_compression/scan/data.json", "photo_compression/scan/images"),
PHOTO_COMPRESSION_COMPRESS("photo_compression/compress/data.json", "photo_compression/compress/images"),
SCREENSHOT("screenshot/scan/data.json", "screenshot/scan/images"),
SIMILAR_PHOTOS("similar_photos/scan/data.json", "similar_photos/scan/images"),
WHATSAPP("whatsapp/scan/data.json", "whatsapp/scan/images"),
CLEAN("clean.json")
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.annotation.SuppressLint
import android.content.Context
import android.database.Cursor
import android.media.MediaScannerConnection
import android.net.Uri
import android.provider.MediaStore
import java.io.File
import java.text.SimpleDateFormat
import java.util.Locale
object MediaHelps {
private val projection = arrayOf(
MediaStore.Files.FileColumns.DISPLAY_NAME,
MediaStore.Files.FileColumns.DATA,
MediaStore.Files.FileColumns.SIZE,
MediaStore.Files.FileColumns.DATE_MODIFIED,
MediaStore.Files.FileColumns.MIME_TYPE
)
private const val EXTERNAL = "external"
fun updateMedia(context:Context, paths: Array<String>) {
MediaScannerConnection.scanFile(context, paths, null, null)
}
fun findFiles(context: Context, size: Long = 0): List<FileBean> {
return queryFilesWithSize(context, MediaStore.Files.getContentUri(EXTERNAL), size)
}
fun findSpecifiedFiles(context: Context): List<FileBean> {
val suffixes = arrayOf("%.log", "%.apk", "%.aab", "%.temp", "%.LOG", "%.APK", "%.AAB", "%.TEMP")
return queryFilesWithSuffixes(context, MediaStore.Files.getContentUri(EXTERNAL), suffixes)
}
fun findScreenshotsFiles(context: Context): Map<String, MutableList<FileBean>> {
val selection = "${MediaStore.Images.Media.RELATIVE_PATH} LIKE ?"
val selectionArgs = arrayOf("%Screenshots%")
val list = query(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, projection[3])
val map = mutableMapOf<String, MutableList<FileBean>>()
val dateFormat = SimpleDateFormat("yyyy/MM", Locale.getDefault())
list.forEach { map.getOrPut(dateFormat.format(it.lastModified)) { mutableListOf() }.add(it) }
return map
}
fun findImageFiles(context: Context, size: Long = 0): List<FileBean> {
return queryFilesWithSize(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, size)
}
fun findVideoFiles(context: Context, size: Long = 0): List<FileBean> {
return queryFilesWithSize(context, MediaStore.Video.Media.EXTERNAL_CONTENT_URI, size)
}
fun findAudioFiles(context: Context, size: Long = 0): List<FileBean> {
return queryFilesWithSize(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, size)
}
fun findDocFiles(context: Context, size: Long = 0): List<FileBean> {
val mimeTypes = arrayOf(
"text/plain",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/pdf",
)
return queryFilesWithMimeTypes(context, MediaStore.Files.getContentUri(EXTERNAL), mimeTypes, size)
}
private fun queryFilesWithSuffixes(context: Context, uri: Uri, suffixes: Array<String>): List<FileBean> {
val selection = suffixes.joinToString(separator = " OR ") { "${MediaStore.Files.FileColumns.DISPLAY_NAME} LIKE ?" }
return query(context, uri, projection, selection, suffixes)
}
private fun queryFilesWithSize(context: Context, uri: Uri, size: Long): List<FileBean> {
var selection: String? = null
var selectionArgs: Array<String>? = null
if (size > 0) {
selection = "${MediaStore.Files.FileColumns.SIZE} >= ?"
selectionArgs = arrayOf(size.toString())
}
return query(context, uri, projection, selection, selectionArgs)
}
private fun queryFilesWithMimeTypes(context: Context, uri: Uri, mimeTypes: Array<String>, size: Long): List<FileBean> {
val (selection, selectionArgs) = buildSelectionWithMimeTypes(mimeTypes, size)
return query(context, uri, projection, selection, selectionArgs)
}
private fun buildSelectionWithMimeTypes(mimeTypes: Array<String>, size: Long): Pair<String, Array<String>> {
val mimeTypeConditions = mimeTypes.joinToString(separator = " OR ") { "${MediaStore.Files.FileColumns.MIME_TYPE}=?" }
val sizeCondition = "${MediaStore.Files.FileColumns.SIZE} >=?"
val selection = "($mimeTypeConditions) AND ($sizeCondition)"
val selectionArgs = mimeTypes + size.toString()
return selection to selectionArgs
}
private fun buildSelectionWithMimeTypes(mimeTypes: Array<String>): Pair<String, Array<String>> {
val selection = mimeTypes.joinToString(prefix = "${MediaStore.Files.FileColumns.MIME_TYPE}=?", separator = " OR ") { "'$it'" }
val selectionArgs = mimeTypes
return Pair(selection, selectionArgs)
}
@SuppressLint("Range")
private fun query(
context: Context,
uri: Uri,
projection: Array<String>,
selection: String? = null,
selectionArgs: Array<String>? = null,
sortOrder: String = MediaStore.Files.FileColumns.DATE_MODIFIED
): List<FileBean> {
val list = mutableListOf<FileBean>()
var cursor: Cursor? = null
try {
val contentResolver = context.contentResolver
cursor = contentResolver.query(
uri,
projection,
selection,
selectionArgs,
"${sortOrder} DESC"
)
cursor?.let {
while (it.moveToNext()) {
val filePath = it.getString(it.getColumnIndex(projection[1]))
if (!File(filePath).exists()) continue
val displayName = it.getString(it.getColumnIndex(projection[0]))
val size = it.getLong(it.getColumnIndex(projection[2]))
val dateModified = it.getLong(it.getColumnIndex(projection[3])) * 1000
val mineType = it.getString(it.getColumnIndex(projection[4]))
list.add(FileBean(displayName, filePath, 0, size, dateModified, mineType))
}
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
cursor?.close()
}
return list
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.LayoutRes
import com.applovin.mediation.MaxAd
import com.applovin.mediation.nativeAds.MaxNativeAdLoader
import com.applovin.mediation.nativeAds.MaxNativeAdView
import com.applovin.mediation.nativeAds.MaxNativeAdViewBinder
import com.base.scanqrclear.R
import com.google.android.gms.ads.nativead.NativeAd
import com.google.android.gms.ads.nativead.NativeAdView
class NativeView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
): FrameLayout(context, attrs) {
fun setExitNativeAd(nativeAd: NativeAd) {
setNativeAd(nativeAd, R.layout.layout_ad_native_exit)
}
fun setExitNativeAd(
nativeAdLoader: MaxNativeAdLoader,
nativeAd: MaxAd,
@LayoutRes resource: Int = R.layout.layout_ad_native_exit
) {
setNativeAd(nativeAdLoader, nativeAd, resource)
}
fun setNativeAd(
nativeAdLoader: MaxNativeAdLoader,
nativeAd: MaxAd,
@LayoutRes resource: Int = R.layout.layout_ad_native
) {
val builder = MaxNativeAdViewBinder.Builder(resource)
.setTitleTextViewId(R.id.ad_headline)
.setIconImageViewId(R.id.ad_icon)
.setMediaContentViewGroupId(R.id.ad_media)
.setCallToActionButtonId(R.id.ad_call_to_action)
if (resource != R.layout.layout_ad_native)
builder.setBodyTextViewId(R.id.ad_body)
visibility = VISIBLE
val adView = MaxNativeAdView(builder.build(), context)
nativeAdLoader.render(adView, nativeAd)
removeAllViews()
addView(adView)
}
fun setNativeAd(nativeAd: NativeAd, @LayoutRes resource: Int ?= R.layout.layout_ad_native) {
visibility = VISIBLE
val adView = resource?.let { LayoutInflater.from(context).inflate(it, null) } as NativeAdView
adView.mediaView = adView.findViewById(R.id.ad_media)
adView.headlineView = adView.findViewById(R.id.ad_headline)
adView.callToActionView = adView.findViewById(R.id.ad_call_to_action)
adView.iconView = adView.findViewById(R.id.ad_icon)
(adView.headlineView as TextView?)?.text = nativeAd.headline
adView.mediaView!!.mediaContent = nativeAd.mediaContent
if (nativeAd.callToAction != null) {
(adView.callToActionView as TextView?)?.text = nativeAd.callToAction
}
if (nativeAd.icon != null) {
(adView.iconView as ImageView?)?.setImageDrawable(nativeAd.icon!!.drawable)
}
val body = adView.findViewById<TextView>(R.id.ad_body)
if (body != null) {
adView.bodyView = body
if (nativeAd.body == null) {
adView.bodyView?.visibility = GONE
} else {
adView.bodyView?.visibility = VISIBLE
(adView.bodyView as TextView?)?.text = nativeAd.body
}
}
adView.setNativeAd(nativeAd)
removeAllViews()
addView(adView)
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.Settings
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import com.base.scanqrclear.utils.ActivityLauncher
object PermissionHelps {
fun requestFilesAccessPermission(
context: Context,
launcher: ActivityLauncher,
result: (Boolean) -> Unit
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
try {
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
intent.addCategory("android.intent.category.DEFAULT")
intent.data = Uri.parse("package:${context.packageName}")
launcher.launch(intent) {
result.invoke(checkFilesAccessPermission(context))
}
} catch (_: Exception) { }
} else {
val array = arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
launcher.launch(array) { permissions ->
result(permissions.values.all { it })
}
}
}
fun requestNotificationPermission(
context: Context,
launcher: ActivityLauncher,
result: (Boolean) -> Unit
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val array = arrayOf(Manifest.permission.POST_NOTIFICATIONS)
launcher.launch(array) { permissions ->
val flag = permissions.values.all { it }
if (!flag) notificationSettings(context, launcher, result)
}
} else {
notificationSettings(context, launcher, result)
}
}
fun notificationSettings(
context: Context,
launcher: ActivityLauncher,
result: (Boolean) -> Unit
) {
val intent = Intent()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
} else {
intent.action = "android.settings.APP_NOTIFICATION_SETTINGS"
intent.putExtra("app_package", context.packageName)
}
launcher.launch(intent) {
result.invoke(checkNotificationPermission(context))
}
}
fun checkNotificationPermission(context: Context): Boolean {
return NotificationManagerCompat.from(context).areNotificationsEnabled()
}
fun checkFilesAccessPermission(context: Context): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
return Environment.isExternalStorageManager()
} else {
val readPermission = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE)
val writePermission = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)
return readPermission == PackageManager.PERMISSION_GRANTED && writePermission == PackageManager.PERMISSION_GRANTED
}
}
}
\ No newline at end of file
This diff is collapsed.
package com.base.scanqrclear.luma
import android.content.Context
import android.content.SharedPreferences
import com.base.scanqrclear.MyApplication
import org.json.JSONObject
class SpUtils private constructor(context: Context) {
private val sharedPreferences: SharedPreferences = context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE)
// 通用的保存数据方法
fun <T> put(key: String, value: T) {
when (value) {
is String -> putString(key, value)
is Int -> putInt(key, value)
is Long -> putLong(key, value)
is Boolean -> putBoolean(key, value)
is Float -> putFloat(key, value)
else -> throw IllegalArgumentException("Unsupported type")
}
}
// 通用的获取数据方法
fun <T> get(key: String, defaultValue: T): T {
return when (defaultValue) {
is String -> getString(key, defaultValue)
is Int -> getInt(key, defaultValue)
is Long -> getLong(key, defaultValue)
is Boolean -> getBoolean(key, defaultValue)
is Float -> getFloat(key, defaultValue)
else -> throw IllegalArgumentException("Unsupported type")
} as T
}
// 保存字符串
fun putString(key: String, value: String) {
sharedPreferences.edit().putString(getKey(key), value).apply()
}
// 获取字符串
fun getString(key: String, defaultValue: String = ""): String {
return sharedPreferences.getString(getKey(key), defaultValue) ?: defaultValue
}
// 保存整数
fun putInt(key: String, value: Int) {
sharedPreferences.edit().putInt(getKey(key), value).apply()
}
// 获取整数
fun getInt(key: String, defaultValue: Int = 0): Int {
return sharedPreferences.getInt(getKey(key), defaultValue)
}
// 保存长整数
fun putLong(key: String, value: Long) {
sharedPreferences.edit().putLong(getKey(key), value).apply()
}
// 获取长整数
fun getLong(key: String, defaultValue: Long = 0): Long {
return sharedPreferences.getLong(getKey(key), defaultValue)
}
// 保存布尔值
fun putBoolean(key: String, value: Boolean) {
sharedPreferences.edit().putBoolean(getKey(key), value).apply()
}
// 获取布尔值
fun getBoolean(key: String, defaultValue: Boolean = false): Boolean {
return sharedPreferences.getBoolean(getKey(key), defaultValue)
}
// 保存浮点数
fun putFloat(key: String, value: Float) {
sharedPreferences.edit().putFloat(getKey(key), value).apply()
}
// 获取浮点数
fun getFloat(key: String, defaultValue: Float = 0f): Float {
return sharedPreferences.getFloat(getKey(key), defaultValue)
}
// 删除键值对
fun remove(key: String) {
sharedPreferences.edit().remove(getKey(key)).apply()
}
// 清除所有数据
fun clear() {
sharedPreferences.edit().clear().apply()
}
// 检查键是否存在
fun contains(key: String): Boolean {
return sharedPreferences.contains(getKey(key))
}
// 保存 JSON 对象
fun saveJsonObjectToSp(json: String) {
try {
if (json.isEmpty()) return
val jsonObject = JSONObject(json)
sharedPreferences.edit().apply {
jsonObject.keys().forEachRemaining { key ->
val value = jsonObject.get(key)
val newKey = getKey(key)
when (value) {
is String -> putString(newKey, value)
is Int -> putInt(newKey, value)
is Long -> putLong(newKey, value)
is Boolean -> putBoolean(newKey, value)
else -> putString(newKey, value.toString())
}
}
apply()
}
} catch (_:Exception) { }
}
fun <T> getValue(key: String, default: T): T {
val newKey = getKey(key)
val value = get(newKey, default)
return value
}
private fun getKey(key: String): String = "${MyApplication.appContext.packageName}_$key"
companion object {
@Volatile
private var instance: SpUtils? = null
// 单例模式获取实例
fun getInstance(context: Context = MyApplication.appContext): SpUtils {
return instance ?: synchronized(this) {
instance ?: SpUtils(context).also {
instance = it
}
}
}
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.app.Activity
import android.graphics.Color
import android.view.View
import android.view.WindowManager
import androidx.annotation.ColorInt
import androidx.core.view.WindowCompat
object StatusBarHelps {
fun immersiveStatusBar(activity: Activity, @ColorInt statusBarColor: Int, isDark: Boolean) {
activity.window.apply {
// 透明状态栏
addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
this.statusBarColor = statusBarColor
if (isDark) {
decorView.systemUiVisibility =
decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
} else{
decorView.systemUiVisibility =
decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
}
}
}
fun setDark(activity: Activity, isDark: Boolean) {
activity.window.apply {
if (isDark) {
decorView.systemUiVisibility =
decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
} else {
decorView.systemUiVisibility =
decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
}
}
}
fun immersive(activity: Activity, @ColorInt statusBarColor: Int) {
immersiveStatusBar(activity, statusBarColor, false)
}
fun immersive(activity: Activity) {
// 设置状态栏透明
activity.window.statusBarColor = Color.TRANSPARENT
WindowCompat.setDecorFitsSystemWindows(activity.window, false)
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.content.Context
import java.math.BigDecimal
import java.math.RoundingMode
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
object Utils {
fun getFormatSize(bytes: Number): String {
val value: Double
val unit: String
if (bytes.toDouble() < 1024) {
value = bytes.toDouble()
unit = " B"
} else if (bytes.toDouble() < 1024 * 1024) {
value = bytes.toDouble() / 1024
unit = " KB"
} else if (bytes.toDouble() < 1024 * 1024 * 1024) {
value = bytes.toDouble() / (1024 * 1024)
unit = " MB"
} else {
value = bytes.toDouble() / (1024 * 1024 * 1024)
unit = " GB"
}
val formattedNumber = String.format("%.2f", value)
return formattedNumber + unit
}
fun getSize(bytes: Long): String {
if (bytes == 0.toLong()) return "0 B"
val value: Double
val unit: String
if (bytes.toDouble() < 1024) {
value = bytes.toDouble()
unit = " B"
} else if (bytes.toDouble() < 1024 * 1024) {
value = bytes.toDouble() / 1024
unit = " KB"
} else if (bytes.toDouble() < 1024 * 1024 * 1024) {
value = bytes.toDouble() / (1024 * 1024)
unit = " MB"
} else {
value = bytes.toDouble() / (1024 * 1024 * 1024)
unit = " GB"
}
val formattedNumber = String.format("%.1f", value)
return formattedNumber + unit
}
fun getSizeArray(bytes: Long): Array<String> {
val value = getSize(bytes)
val size = value.substring(0, value.indexOf(" "))
val unit = value.substring(value.indexOf(" ") + 1)
return arrayOf(size, unit)
}
fun Long.toDateString(): String {
val formatter = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
return formatter.format(Date(this))
}
fun Context.toDate(): String {
val formatter = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
return formatter.format(Date())
}
fun getCurrentMinute(): Int {
val calendar = Calendar.getInstance()
return calendar.get(Calendar.MINUTE)
}
fun calculate(dividend: Int, divisor: Int): String {
val bigDecimalDividend = BigDecimal(dividend)
val bigDecimalDivisor = BigDecimal(divisor)
// 执行除法操作,并保留一位小数,不四舍五入
val result = bigDecimalDividend.divide(bigDecimalDivisor, 1, RoundingMode.DOWN)
// 将结果转换回Double
return result.toString()
}
}
\ No newline at end of file
package com.base.scanqrclear.utils
import com.base.scanqrclear.R
import com.tool.luma.smart.cleaner.R
enum class ExitType(val title: Int, val content: Int) {
APP_MANAGER(R.string.exit_app_manager, R.string.exit_app_manager_content),
BATTERY_INFO(R.string.exit_battery_info, R.string.exit_battery_info_content),
LARGE_FILE(R.string.exit_large_file_clean, R.string.exit_large_file_clean_content),
PHOTO_COMPRESSION(R.string.exit_photo_compression, R.string.exit_photo_compression_content),
SCREENSHOT(R.string.exit_screenshot_cleaner, R.string.exit_screenshot_cleaner_content),
SIMILAR_PHOTOS(R.string.exit_similar_photos, R.string.exit_similar_photos_content),
WHATSAPP(R.string.exit_whatsapp_clean, R.string.exit_whatsapp_clean_content),
CLEAN(R.string.exit_clean_junk, R.string.exit_clean_junk_content),
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_f0f0f0" />
<corners android:radius="16dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<solid android:color="@color/color_ffcda0" />
<corners android:radius="8dp" />
</shape>
</item>
<item android:id="@android:id/progress">
<scale android:scaleWidth="100%">
<shape>
<solid android:color="@color/white" />
<corners android:radius="8dp" />
</shape>
</scale>
</item>
</layer-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="4dp" />
<solid android:color="@color/white" />
<stroke android:width="1dp" android:color="@color/color_aeb4bd" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<solid android:color="@color/colorPrimary" />
</shape>
</item>
<item android:id="@android:id/progress">
<scale android:scaleWidth="100%">
<shape>
<solid android:color="@color/white" />
</shape>
</scale>
</item>
</layer-list>
\ No newline at end of file
<?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:background="@drawable/white_background">
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie_face"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
app:lottie_fileName="top_rate_nor.json"
app:lottie_loop="true"
app:lottie_autoPlay="true"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:src="@mipmap/icon_close_pingfen"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginHorizontal="16dp"
android:text="@string/score_title"
android:textAlignment="center"
android:textColor="@color/color_181b1f"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/lottie_face" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginHorizontal="16dp"
android:text="@string/score_content"
android:textAlignment="center"
android:textColor="@color/color_4f4f4f"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_star"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/ll_star"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_star1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="6dp"
android:src="@mipmap/star_n"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@id/iv_star2" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_star2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="6dp"
android:src="@mipmap/star_n"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@id/iv_star3" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_star3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:src="@mipmap/star_n"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_star4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginStart="6dp"
android:src="@mipmap/star_n"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/iv_star3" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_star5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginStart="6dp"
android:src="@mipmap/star_n"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/iv_star4" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll_star_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="10dp"
app:layout_constraintEnd_toEndOf="@id/iv_star5"
app:layout_constraintTop_toBottomOf="@id/iv_star5">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@string/the_best_we_can_get"
android:textColor="@color/colorPrimary"
android:textSize="14sp" />
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:src="@mipmap/icon_zhixiang" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_submit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="48dp"
android:layout_marginHorizontal="28dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:text="@string/confirm"
android:textAllCaps="true"
android:textColor="@color/white"
android:textSize="16sp"
android:gravity="center"
android:background="@drawable/gradient"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/cl_star" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="@color/color_ff6400"
android:endColor="@color/color_ff8200"
android:angle="0"
android:centerX="0.5"
android:centerY="0.5" />
<corners android:radius="50dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="@color/color_ff6400"
android:endColor="@color/color_ff8200"
android:angle="0"
android:centerX="0.5"
android:centerY="0.5" />
<corners android:radius="37dp" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="@color/color_ff6400"
android:endColor="@color/color_ff8200"
android:angle="0"
android:centerX="0.5"
android:centerY="0.5" />
<corners android:radius="37dp" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="@color/color_ff6400"
android:endColor="@color/color_ff8200"
android:angle="0"
android:centerX="0.5"
android:centerY="0.5" />
<corners android:radius="4dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="@color/color_ffb764"
android:endColor="@color/color_ffae52"
android:angle="270"
android:centerX="0.5"
android:centerY="0.5" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="@color/color_ffb462"
android:endColor="@color/color_ffc889"
android:angle="0"
android:centerX="0.5"
android:centerY="0.5" />
<corners android:radius="50dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="@color/color_ffb462"
android:endColor="@color/color_ffc889"
android:angle="0"
android:centerX="0.5"
android:centerY="0.5" />
<corners android:radius="4dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="@color/color_ffe14a"
android:endColor="@color/color_ffcd58"
android:angle="0"
android:centerX="0.5"
android:centerY="0.5" />
<corners android:radius="50dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="@color/color_ffe8ce"
android:endColor="@color/color_f8f8fb"
android:angle="270"
android:centerX="0.5"
android:centerY="0.5" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="37dp" />
<solid android:color="@android:color/transparent" />
<stroke android:width="1dp" android:color="@color/color_ebebeb" />
</shape>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="28dp"
android:height="28dp"
android:viewportWidth="28"
android:viewportHeight="28">
<!-- <path-->
<!-- android:pathData="M3.281,0L24.719,0A3.281,3.281 0,0 1,28 3.281L28,24.719A3.281,3.281 0,0 1,24.719 28L3.281,28A3.281,3.281 0,0 1,0 24.719L0,3.281A3.281,3.281 0,0 1,3.281 0z"-->
<!-- android:fillColor="#A0A0A0"/>-->
<path
android:pathData="M24.502,19.893C24.604,19.694 24.888,19.694 24.99,19.893L25.699,21.287C25.725,21.337 25.766,21.379 25.817,21.405L27.204,22.125C27.401,22.226 27.401,22.508 27.204,22.61L25.817,23.329C25.766,23.355 25.725,23.397 25.699,23.448L24.99,24.842C24.888,25.041 24.604,25.041 24.502,24.842L23.793,23.448C23.767,23.397 23.726,23.355 23.675,23.329L22.288,22.61C22.092,22.508 22.092,22.226 22.288,22.125L23.675,21.405C23.726,21.379 23.767,21.337 23.793,21.287L24.502,19.893Z"
android:fillColor="#E2E2E2"/>
<path
android:pathData="M8.704,1.59C8.719,1.341 9.032,1.241 9.189,1.435L10.106,2.564C10.154,2.623 10.224,2.659 10.3,2.665L11.749,2.765C11.995,2.782 12.095,3.092 11.904,3.249L10.782,4.172C10.723,4.22 10.687,4.291 10.683,4.366L10.591,5.818C10.576,6.067 10.263,6.167 10.106,5.974L9.189,4.844C9.141,4.785 9.071,4.749 8.995,4.744L7.546,4.643C7.299,4.626 7.2,4.316 7.391,4.159L8.513,3.236C8.572,3.188 8.607,3.118 8.612,3.042L8.704,1.59Z"
android:fillColor="#E2E2E2"/>
<path
android:pathData="M3.28,8.232C3.292,8.099 3.449,8.035 3.55,8.122L3.982,8.494C4.008,8.517 4.04,8.53 4.075,8.534L4.642,8.584C4.775,8.596 4.839,8.754 4.752,8.855L4.38,9.287C4.358,9.313 4.344,9.345 4.341,9.379L4.29,9.947C4.278,10.08 4.121,10.144 4.02,10.057L3.588,9.685C3.562,9.662 3.529,9.649 3.495,9.646L2.927,9.595C2.794,9.583 2.731,9.425 2.818,9.324L3.19,8.892C3.212,8.866 3.226,8.834 3.229,8.8L3.28,8.232Z"
android:fillColor="#E2E2E2"/>
<group>
<clip-path
android:pathData="M5,5h15.85v18.9h-15.85z"/>
<path
android:pathData="M8.66,13.11C8.66,13.11 5.31,19.56 5.04,19.41C4.77,19.26 6.1,20.5 8.91,21.38L9.99,21.55L9.91,21.83C9.91,21.83 13.45,23.26 14.92,23.19L14.99,22.95C14.99,22.95 16.22,23.99 20.04,23.9C20.04,23.9 19.7,17.98 20.27,16.48L8.66,13.12V13.11Z"
android:fillColor="#DDDDDD"/>
<path
android:pathData="M17.535,5.196L17.016,5.046C16.358,4.855 15.671,5.234 15.48,5.892L14.035,10.877C13.845,11.535 14.224,12.222 14.881,12.413L15.4,12.563C16.058,12.754 16.746,12.375 16.936,11.717L18.381,6.732C18.571,6.075 18.192,5.387 17.535,5.196Z"
android:fillColor="#DDDDDD"/>
<path
android:pathData="M20.85,14.48C21.02,13.9 18.56,12.67 15.35,11.74C12.14,10.81 9.41,10.53 9.24,11.11C9.24,11.12 9.24,11.14 9.24,11.15L8.67,13.1L20.28,16.46L20.85,14.5C20.85,14.5 20.86,14.47 20.87,14.46L20.85,14.48Z"
android:fillColor="#BCBCBC"/>
<path
android:pathData="M16.385,10.348L15.232,10.014C14.707,9.862 14.158,10.165 14.006,10.69L13.889,11.093C13.737,11.618 14.039,12.167 14.564,12.319L15.717,12.653C16.242,12.806 16.791,12.503 16.943,11.978L17.06,11.575C17.212,11.05 16.91,10.5 16.385,10.348Z"
android:fillColor="#BCBCBC"/>
<path
android:pathData="M9.98,21.55L10.99,18.05C10.99,18.05 9.57,21.55 8.9,21.38C8.23,21.21 9.58,21.55 9.98,21.55Z"
android:fillColor="#BFBFBF"/>
<path
android:pathData="M14.98,22.95L16.36,18.18C16.36,18.18 15.24,23.06 15.74,23.32C15.65,23.28 15.09,23.06 14.97,22.95H14.98Z"
android:fillColor="#BFBFBF"/>
</group>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="8dp" />
<stroke android:width="1dp" android:color="@color/colorPrimary" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_66000000" />
<corners
android:bottomLeftRadius="8dp"
android:bottomRightRadius="8dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_66000000" />
<corners android:radius="8dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_f8fbff" />
<corners android:radius="8dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="@color/color_2b91f1"
android:endColor="@color/color_b5e0ffc"
android:angle="270"
android:centerX="0.5"
android:centerY="0.5" />
<corners android:radius="50dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<solid android:color="@color/color_e6e6e6" />
<corners android:radius="5dp" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<solid android:color="@color/color_2b91f1" />
<corners android:radius="5dp" />
</shape>
</clip>
</item>
</layer-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/tob_home" android:state_checked="true"/>
<item android:drawable="@mipmap/tob_home_n" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/tob_tools_s" android:state_checked="true"/>
<item android:drawable="@mipmap/tob_tools_n" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" />
<corners android:radius="12dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" />
<corners android:radius="16dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" />
<corners android:radius="8dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" />
<corners
android:bottomLeftRadius="15dp"
android:bottomRightRadius="15dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" />
<corners
android:topLeftRadius="15dp"
android:topRightRadius="15dp" />
</shape>
\ No newline at end of file
<?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="match_parent"
android:background="@color/color_f7fafa">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_top"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/gradient_background"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="6dp"
android:paddingBottom="6dp"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintTop_toTopOf="parent">
<FrameLayout
android:id="@+id/fl_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="11dp"
android:padding="4dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/icon_return_bar_nor" />
</FrameLayout>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="@id/fl_back"
app:layout_constraintBottom_toBottomOf="@id/fl_back"
app:layout_constraintStart_toEndOf="@id/fl_back" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_cleaned_up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="84dp"
android:text="@string/cleaned_up"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/ll_title" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginBottom="46dp"
android:text="@string/cleaned_up_content"
android:textColor="@color/white"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_cleaned_up" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_result"
android:layout_width="match_parent"
android:layout_height="0dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:scrollbars="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/cl_top" />
<com.airbnb.lottie.LottieAnimationView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
app:lottie_fileName="ok.json"
app:lottie_autoPlay="true"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
This diff is collapsed.
<?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="match_parent"
android:background="@drawable/gradient_background">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/gl_line"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0" />
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie_animation"
android:layout_width="wrap_content"
android:layout_height="290dp"
android:layout_marginTop="50dp"
android:adjustViewBounds="true"
app:lottie_loop="true"
app:lottie_autoPlay="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/gl_line" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="2dp"
android:gravity="center"
android:text="0%"
android:textAlignment="center"
android:textColor="@color/white"
android:textSize="30sp"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/lottie_animation" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/please_wait"
android:textAlignment="center"
android:textColor="@color/white"
android:textSize="14sp"
app:layout_constraintTop_toBottomOf="@id/tv_progress" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?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:background="@drawable/white_background">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:includeFontPadding="false"
android:lineSpacingExtra="4dp"
android:text="@string/delete_title"
android:textAlignment="center"
android:textColor="@color/color_181b1f"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:lineSpacingExtra="4dp"
android:includeFontPadding="false"
android:text="@string/delete_content"
android:textAlignment="center"
android:textColor="@color/color_666666"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="24dp"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_content">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_cancel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginEnd="8dp"
android:paddingVertical="8dp"
android:gravity="center"
android:background="@drawable/button_border_background"
android:text="@string/cancel"
android:textColor="@color/color_aeb4bd"
android:textSize="14sp" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_delete"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="8dp"
android:paddingVertical="8dp"
android:gravity="center"
android:background="@drawable/gradient_4"
android:text="@string/delete"
android:textColor="@color/white"
android:textSize="14sp" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?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">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_exit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/white_background_16"
android:paddingBottom="30dp"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:src="@mipmap/icon_close_pingfen"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="48dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="48dp"
android:includeFontPadding="false"
android:lineSpacingExtra="4dp"
android:text="@string/app_name"
android:textAlignment="center"
android:textColor="@color/color_181b1f"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="6dp"
android:layout_marginEnd="24dp"
android:includeFontPadding="false"
android:lineSpacingExtra="4dp"
android:text="@string/storage_permission_content"
android:textAlignment="center"
android:textColor="@color/color_666666"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_cancel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="8dp"
android:background="@drawable/gradient_not_clickable"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:text="@string/cancel"
android:textAlignment="center"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@id/tv_sure"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_content" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_sure"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="32dp"
android:background="@drawable/gradient"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:text="@string/sure"
android:textAlignment="center"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/tv_cancel"
app:layout_constraintTop_toBottomOf="@id/tv_content" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.base.scanqrclear.luma.NativeView
android:id="@+id/ad_native"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@drawable/white_background_16"
android:padding="11dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/cl_exit" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/white_background">
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
app:lottie_fileName="ad_loading.json"
app:lottie_loop="true"
app:lottie_autoPlay="true"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="24dp"
android:text="@string/loading"
android:textAlignment="center"
android:textColor="@color/color_181b1f"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/lottie_loading" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?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">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_top"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@mipmap/img_bj_pop"
android:paddingBottom="30dp"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_logo"
android:layout_width="66dp"
android:layout_height="66dp"
android:layout_marginTop="30dp"
android:src="@mipmap/logo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:src="@mipmap/icon_close_pop"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="37dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="37dp"
android:text="@string/please_wait_a_moment"
android:textAlignment="center"
android:textColor="@color/color_181b1f"
android:textSize="22sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv_logo" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="37dp"
android:layout_marginTop="6dp"
android:layout_marginEnd="37dp"
android:text="@string/logout_content"
android:textAlignment="center"
android:textColor="@color/color_666666"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_exit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="4dp"
android:background="@drawable/gradient_not_clickable"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:text="@string/exit"
android:textAlignment="center"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@id/tv_cancel"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_content" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_cancel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="32dp"
android:background="@drawable/gradient"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:text="@string/clean_now"
android:textAlignment="center"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="1.4"
app:layout_constraintStart_toEndOf="@id/tv_exit"
app:layout_constraintTop_toBottomOf="@id/tv_content" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.base.scanqrclear.luma.NativeView
android:id="@+id/ad_native"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@drawable/white_background_16"
android:padding="11dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/cl_top" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?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:background="@mipmap/img_tongzhi_pop_bj">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="20dp"
android:src="@mipmap/icon_close_pop"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="168dp"
android:text="@string/notification_title"
android:textAlignment="center"
android:textColor="@color/color_181b1f"
android:textSize="22sp"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginStart="42dp"
android:layout_marginEnd="42dp"
android:text="@string/notification_content"
android:textAlignment="center"
android:textColor="@color/color_666666"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_turn_on"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginBottom="44dp"
android:layout_marginStart="58dp"
android:layout_marginEnd="58dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:text="@string/turn_on"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold"
android:gravity="center"
android:background="@drawable/gradient"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_content" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?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:paddingTop="24dp"
android:paddingBottom="40dp"
android:background="@drawable/white_background_top">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:text="@string/storage_permission_title"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:text="@string/storage_permission_content"
android:textColor="@color/color_666666"
android:textSize="16sp"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_permission"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="17dp"
android:layout_marginHorizontal="15dp"
android:adjustViewBounds="true"
android:src="@mipmap/img_quanxian_pop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_content" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_open_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:text="@string/open_settings"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold"
android:gravity="center"
android:background="@drawable/gradient"
app:layout_constraintTop_toBottomOf="@id/iv_permission" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?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:background="@drawable/white_background">
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie_face"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:lottie_autoPlay="true"
app:lottie_fileName="top_rate_nor.json"
app:lottie_loop="true" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:src="@mipmap/icon_close_pingfen"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="8dp"
android:text="@string/score_title"
android:textAlignment="center"
android:textColor="@color/color_181b1f"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/lottie_face" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="4dp"
android:text="@string/score_content"
android:textAlignment="center"
android:textColor="@color/color_4f4f4f"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_star"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/ll_star"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_star1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="6dp"
android:src="@mipmap/star_n"
app:layout_constraintEnd_toStartOf="@id/iv_star2"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_star2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="6dp"
android:src="@mipmap/star_n"
app:layout_constraintEnd_toStartOf="@id/iv_star3"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_star3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:src="@mipmap/star_n"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_star4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginTop="24dp"
android:src="@mipmap/star_n"
app:layout_constraintStart_toEndOf="@id/iv_star3"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_star5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginTop="24dp"
android:src="@mipmap/star_n"
app:layout_constraintStart_toEndOf="@id/iv_star4"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll_star_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="10dp"
app:layout_constraintEnd_toEndOf="@id/iv_star5"
app:layout_constraintTop_toBottomOf="@id/iv_star5">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@string/the_best_we_can_get"
android:textColor="@color/colorPrimary"
android:textSize="14sp" />
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:src="@mipmap/icon_zhixiang" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_submit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="28dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="48dp"
android:background="@drawable/gradient"
android:gravity="center"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:text="@string/confirm"
android:textAllCaps="true"
android:textColor="@color/white"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cl_star" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?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_marginTop="12dp"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:padding="16dp"
android:background="@drawable/white_background">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/icon_clean_home"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/iv_image">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/clean_junk"
android:textColor="@color/color_181b1f"
android:textSize="16sp"
android:textStyle="bold" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/result_clean_junk"
android:textColor="@color/color_666666"
android:textSize="16sp" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_clean_now"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:gravity="center"
android:background="@drawable/gradient_4"
android:text="@string/clean_now"
android:textColor="@color/white"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/ll_content" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.ads.nativead.NativeAdView 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">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ad_native_background">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ad_small_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginStart="6dp"
android:src="@mipmap/icon_ad_pop"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<com.google.android.gms.ads.nativead.MediaView
android:id="@+id/ad_media"
android:layout_width="0dp"
android:layout_height="130dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="42dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/ad_small_icon" />
<ImageView
android:id="@+id/ad_icon"
android:layout_width="33dp"
android:layout_height="33dp"
android:layout_marginStart="14dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/ad_call_to_action"
app:layout_constraintBottom_toBottomOf="@id/ad_call_to_action" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/ad_headline"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:ellipsize="end"
android:maxLines="2"
android:text="@string/app_name"
android:textColor="@color/black"
android:textSize="16sp"
app:layout_constraintTop_toTopOf="@id/ad_call_to_action"
app:layout_constraintBottom_toBottomOf="@id/ad_call_to_action"
app:layout_constraintStart_toEndOf="@id/ad_icon"
app:layout_constraintEnd_toStartOf="@id/ad_call_to_action" />
<Button
android:id="@+id/ad_call_to_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_marginEnd="6dp"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:text="@string/open"
android:textColor="@color/white"
android:textSize="15sp"
android:textStyle="bold"
android:background="@drawable/gradient_26"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/ad_headline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/ad_media" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.gms.ads.nativead.NativeAdView>
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.ads.nativead.NativeAdView 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">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:background="@drawable/ad_native_background">
<com.google.android.gms.ads.nativead.MediaView
android:id="@+id/ad_media"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginEnd="8dp"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintTop_toTopOf="@id/ll_content"
app:layout_constraintBottom_toBottomOf="@id/ll_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/ll_content" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll_content"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginEnd="4dp"
android:orientation="vertical"
app:layout_constraintHorizontal_weight="1.3"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/ad_media">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/ad_headline"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/app_name"
android:textColor="@color/color_181b1f"
android:textSize="12sp" />
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ad_small_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/icon_ad_pop"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/ad_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="10dp"
android:text="@string/storage_permission_content"
android:ellipsize="end"
android:maxLines="2"
android:textColor="@color/color_666666"
android:textSize="10sp" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:orientation="horizontal">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ad_icon"
android:layout_width="33dp"
android:layout_height="33dp" />
</androidx.appcompat.widget.LinearLayoutCompat>
<Button
android:id="@+id/ad_call_to_action"
android:layout_width="wrap_content"
android:layout_height="38dp"
android:background="@drawable/gradient_26"
android:text="@string/open"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="14sp"
android:textStyle="bold" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.gms.ads.nativead.NativeAdView>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" />
<corners android:radius="12dp" />
</shape>
\ No newline at end of file
This diff is collapsed.
...@@ -79,4 +79,6 @@ ...@@ -79,4 +79,6 @@
<style name="CustomDialogStyle" parent="android:Theme.Material.Dialog"> <style name="CustomDialogStyle" parent="android:Theme.Material.Dialog">
<item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowBackground">@android:color/transparent</item>
</style> </style>
</resources> </resources>
\ No newline at end of file
...@@ -22,6 +22,8 @@ pangle = "6.3.0.4.0" ...@@ -22,6 +22,8 @@ pangle = "6.3.0.4.0"
protoliteWellKnownTypes = "18.0.0" protoliteWellKnownTypes = "18.0.0"
lottie = "6.5.2" lottie = "6.5.2"
expandablerecyclerview = "0.9.3" expandablerecyclerview = "0.9.3"
okhttp = "4.12.0"
...@@ -55,6 +57,9 @@ applovin_pangle = { group = "com.applovin.mediation", name = "bytedance-adapter" ...@@ -55,6 +57,9 @@ applovin_pangle = { group = "com.applovin.mediation", name = "bytedance-adapter"
protolite-well-known-types = { group = "com.google.firebase", name = "protolite-well-known-types", version.ref = "protoliteWellKnownTypes" } protolite-well-known-types = { group = "com.google.firebase", name = "protolite-well-known-types", version.ref = "protoliteWellKnownTypes" }
lottie = { group = "com.airbnb.android", name = "lottie", version.ref = "lottie" } lottie = { group = "com.airbnb.android", name = "lottie", version.ref = "lottie" }
expandablerecyclerview = { group = "com.github.pokercc", name = "ExpandableRecyclerView", version.ref = "expandablerecyclerview" } expandablerecyclerview = { group = "com.github.pokercc", name = "ExpandableRecyclerView", version.ref = "expandablerecyclerview" }
okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" }
logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment