Commit ce010dc7 authored by jyx's avatar jyx

相册清理

parent 0505771a
......@@ -159,6 +159,7 @@ dependencies {
implementation Deps.banner
implementation Deps.glide
kapt Deps.glide_compiler
implementation Deps.photoView
implementation Deps.livedata_ktx
implementation Deps.viewPager2
......
......@@ -2,6 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mints.cleaner">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
......@@ -14,8 +15,16 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".ui.setting.SettingActivity"></activity>
<activity android:name=".ui.albumClean.AlbumCleanActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--屏幕适配-->
<!-- 屏幕适配 -->
<meta-data
android:name="android.max_aspect"
android:value="2.4" />
......@@ -23,11 +32,7 @@
<activity android:name=".ui.login.LoginActivity" />
<activity android:name=".ui.splash.SplashActivity" />
<activity android:name=".ui.NavigationActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
......
package com.mints.cleaner.adapter
import android.widget.ImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.RequestOptions
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.BaseViewHolder
import com.mints.cleaner.R
import com.mints.cleaner.model.bean.Image
import com.mints.cleaner.util.VersionUtils
import com.mints.cleaner.widget.RoundCheckBox
class AlbumCleanAdapter(layoutResId: Int, data: List<Image>) :
BaseQuickAdapter<Image, BaseViewHolder>(layoutResId, data) {
// 选中图片数据
private var mSelectImages = arrayListOf<Image>()
// 复选框选中状态
private var mCheckBoxTags = arrayListOf<Int>()
private var mSelectListener: OnImageSelectListener? = null
private var mItemClickListener: OnItemClickListener? = null
private val isViewImage = false
private val isAndroidQ: Boolean = VersionUtils.isAndroidQ()
override fun convert(helper: BaseViewHolder, item: Image) {
helper.getView<ImageView>(R.id.iv_item_album).run {
Glide.with(mContext).load(if (isAndroidQ) item.uri else item.path)
.apply(RequestOptions().diskCacheStrategy(DiskCacheStrategy.NONE))
.into(this)
setOnClickListener {
mItemClickListener?.let {
it.onItemClick(item, helper.adapterPosition)
}
}
}
helper.getView<RoundCheckBox>(R.id.cb_item).run {
setOnCheckedChangeListener(null)
tag = helper.adapterPosition
isChecked = mCheckBoxTags.contains(helper.adapterPosition)
setOnCheckedChangeListener { _, _ ->
if (mSelectImages.contains(item)) {
unSelectImage(item)
} else {
selectImage(item)
}
if (isChecked) {
mCheckBoxTags.add(helper.adapterPosition)
} else {
mCheckBoxTags.remove(helper.adapterPosition)
}
}
}
}
fun setOnImageSelectListener(listener: OnImageSelectListener?) {
mSelectListener = listener
}
fun setOnItemClickListener1(listener: OnItemClickListener?) {
mItemClickListener = listener
}
fun getSelectImageList(): List<Image> {
return mSelectImages
}
// 更新数据
fun refreshData(data: List<Image>) {
mData = data
notifyDataSetChanged()
}
// 清空复选框标识
fun cleanSelectImage() {
mSelectImages = arrayListOf()
mCheckBoxTags = arrayListOf()
mSelectListener?.let {
it.onImageSelect(mSelectImages.size)
}
notifyDataSetChanged()
}
// 全选
fun fullSelectImage() {
for (index in 0 until mData.size) {
mCheckBoxTags.add(index)
mSelectImages.add(mData[index])
}
mSelectListener?.let {
it.onImageSelect(mSelectImages.size)
}
notifyDataSetChanged()
}
// 取消全选
fun cancelFullSelectImage() {
// 取消全选
mSelectImages = arrayListOf()
mCheckBoxTags = arrayListOf()
mSelectListener?.let {
it.onImageSelect(mSelectImages.size)
}
notifyDataSetChanged()
}
/**
* 选中图片
*/
private fun selectImage(image: Image) {
mSelectImages.add(image)
mSelectListener?.let {
it.onImageSelect(mSelectImages.size)
}
}
/**
* 取消选中图片
*/
private fun unSelectImage(image: Image) {
mSelectImages.remove(image)
mSelectListener?.let {
it.onImageSelect(mSelectImages.size)
}
}
interface OnImageSelectListener {
fun onImageSelect(
selectCount: Int
)
}
interface OnItemClickListener {
fun onItemClick(image: Image?, position: Int)
}
}
\ No newline at end of file
......@@ -8,9 +8,6 @@ import com.mints.cleaner.R
class CleanAdapter : BaseMultiItemQuickAdapter<CleanMultiItem, BaseViewHolder> {
private val names = arrayOf("手机加速", "微信清理", "QQ清理", "软件管理", "相册清理", "视频清理")
constructor(data: List<CleanMultiItem>) : super(data) {
addItemType(CleanMultiItem.ITEM_TOP, R.layout.item_clean_top)
addItemType(CleanMultiItem.ITEM_MID, R.layout.item_clean_mid)
......@@ -24,21 +21,13 @@ class CleanAdapter : BaseMultiItemQuickAdapter<CleanMultiItem, BaseViewHolder> {
}
CleanMultiItem.ITEM_MID -> {
val listitem: MutableList<Map<String, Any>> =
ArrayList()
for (i in names.indices) {
val item: MutableMap<String, Any> = HashMap()
item["item_gv_text"] = names[i]
listitem.add(item)
}
val gridView = helper.getView<GridView>(R.id.gv_clean)
val simpleAdapter = SimpleAdapter(
gridView.context,
listitem,
item?.gvDataList,
R.layout.item_gv_clean,
arrayOf("item_gv_text"),
intArrayOf(R.id.item_gv_text)
arrayOf("item_gv_icon", "item_gv_text"),
intArrayOf(R.id.item_gv_img, R.id.item_gv_text)
)
gridView.adapter = simpleAdapter
gridView.setOnItemClickListener { _, _, position, _ ->
......
......@@ -5,15 +5,16 @@ import com.chad.library.adapter.base.entity.MultiItemEntity
class CleanMultiItem : MultiItemEntity {
private var itemType: Int = 0
private var itemIndex: Int = 0
var gvDataList: MutableList<Map<String, Any>> = ArrayList()
constructor(itemType: Int) {
this.itemType = itemType
}
constructor(itemType: Int, itemIndex: Int) {
constructor(itemType: Int, gvDataList: MutableList<Map<String, Any>>) {
this.itemType = itemType
this.itemIndex = itemIndex
this.gvDataList = gvDataList
}
companion object {
......
......@@ -2,12 +2,10 @@ package com.mints.cleaner.model.api.client
import com.mints.cleaner.model.api.neterror.CashException
import com.mints.cleaner.model.api.neterror.ServerException
import com.mints.cleaner.model.api.neterror.Throwable
import com.mints.cleaner.model.repository.BaseResponse
import com.mints.core.Result
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
import java.io.IOException
import java.lang.Exception
open class BaseRepository {
......
package com.mints.cleaner.model.bean
class CleanHeaderTitle(
// 标题内容
var title: Int,
// 左边图标
var leftIcon: Int,
// 左边图标点击事件
var leftAction: () -> Unit,
// 右边文字是否显示
val rightInfoVisible: Int,
// 右边文字内容
val rightInfo: String,
// 右边文字点击事件
val rightInfoAction: () -> Unit,
// 背景颜色
val background: Int
)
\ No newline at end of file
package com.mints.cleaner.model.bean
class Folder {
var name: String
var images: ArrayList<Image> = arrayListOf()
constructor(name: String) {
this.name = name
}
constructor(name: String, images: ArrayList<Image>) {
this.name = name
this.images = images
}
fun addImage(image: Image?) {
if (image != null && image.path.isEmpty()) {
if (images == null) {
images = ArrayList()
}
images.add(image)
}
}
}
\ No newline at end of file
package com.mints.cleaner.model.bean
data class HeaderTitle(
class HeaderTitle(
// 标题内容
val title: Int,
var title: Int,
// 返回箭头是否显示
val backArrowVisible: Int,
// 右边图标
val rightIcon: Int,
var leftIconVisible: Int,
// 左边图标
var leftIcon: Int,
// 左边图标点击事件
var leftAction: () -> Unit,
// 背景颜色
val background: Int
)
\ No newline at end of file
package com.mints.cleaner.model.bean
import android.net.Uri
data class Image(
val path: String,
val time: Long,
val name: String,
val mimeType: String,
val uri: Uri,
val size: Long
)
\ No newline at end of file
package com.mints.cleaner.model.repository
import com.mints.cleaner.R
import com.mints.cleaner.adapter.clean.CleanMultiItem
import com.mints.cleaner.model.api.ApiService
import com.mints.cleaner.model.api.client.BaseRepository
class MainRepository(val service: ApiService) : BaseRepository() {
// 网格布局data
private val gvNames = arrayOf("手机加速", "微信清理", "QQ清理", "软件管理", "相册清理", "视频清理")
private val gvIcons = arrayOf(
R.mipmap.ic_launcher,
R.mipmap.ic_launcher,
R.mipmap.ic_launcher,
R.mipmap.ic_launcher,
R.mipmap.ic_launcher,
R.mipmap.ic_launcher
)
private var multiItemList: ArrayList<CleanMultiItem> = arrayListOf()
private val gvDataList: MutableList<Map<String, Any>> = ArrayList()
fun getHomeData(): ArrayList<CleanMultiItem> {
for (i in gvNames.indices) {
val item: MutableMap<String, Any> = HashMap()
item["item_gv_icon"] = gvIcons[i]
item["item_gv_text"] = gvNames[i]
gvDataList.add(item)
}
multiItemList = arrayListOf(
CleanMultiItem(CleanMultiItem.ITEM_TOP),
CleanMultiItem(CleanMultiItem.ITEM_MID, gvDataList),
CleanMultiItem(CleanMultiItem.ITEM_BOTTOM),
CleanMultiItem(CleanMultiItem.ITEM_BOTTOM),
CleanMultiItem(CleanMultiItem.ITEM_BOTTOM),
CleanMultiItem(CleanMultiItem.ITEM_BOTTOM)
)
return multiItemList
}
}
\ No newline at end of file
package com.mints.cleaner.ui.albumClean
import android.content.Intent
import android.net.Uri
import android.view.View
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.GridLayoutManager
import com.mints.cleaner.R
import com.mints.cleaner.adapter.AlbumCleanAdapter
import com.mints.cleaner.databinding.ActivityAlbumCleanBinding
import com.mints.cleaner.model.bean.CleanHeaderTitle
import com.mints.cleaner.model.bean.Folder
import com.mints.cleaner.model.bean.HeaderTitle
import com.mints.cleaner.model.bean.Image
import com.mints.cleaner.util.FileUtils
import com.mints.cleaner.util.LogUtil
import com.mints.core.base.BaseVMActivity
import kotlinx.android.synthetic.main.activity_album_clean.*
import java.io.File
import java.util.*
class AlbumCleanActivity : BaseVMActivity(), AlbumCleanAdapter.OnImageSelectListener,
AlbumCleanAdapter.OnItemClickListener {
private val binding by binding<ActivityAlbumCleanBinding>(R.layout.activity_album_clean)
private val dataList = arrayListOf<Image>()
// 是否全选
private var flag = false
private var rightInfo = "全选"
private val albumAdapter: AlbumCleanAdapter by lazy {
AlbumCleanAdapter(
R.layout.item_album_clean,
dataList
)
}
override fun initView() {
binding.run {
title = CleanHeaderTitle(
R.string.app_name,
R.mipmap.ic_activity_arrow,
{
onBackPressed()
},
View.VISIBLE,
rightInfo,
{
rightInfo = if (!flag) {
albumAdapter.fullSelectImage()
"取消全选"
} else {
albumAdapter.cancelFullSelectImage()
"全选"
}
flag = !flag
},
R.color.theme
)
}
initRecyclerView()
btn_clean.setOnClickListener {
val selectImageList = albumAdapter.getSelectImageList()
if (selectImageList.isEmpty()) return@setOnClickListener
for (element in selectImageList) {
FileUtils.deleteImage(element.path, this)
updateAlbum(element.path)
}
dataList.removeAll(selectImageList)
albumAdapter.cleanSelectImage()
albumAdapter.notifyDataSetChanged()
}
}
private fun initRecyclerView() {
recyclerview_album.run {
layoutManager = GridLayoutManager(this@AlbumCleanActivity, 3)
adapter = albumAdapter
albumAdapter.setOnImageSelectListener(this@AlbumCleanActivity)
albumAdapter.setOnItemClickListener1(this@AlbumCleanActivity)
}
}
override fun initData() {
AlbumCleanModel.loadImageForSDCard(this, object : AlbumCleanModel.DataCallback {
override fun onSuccess(folders: ArrayList<Folder>?) {
folders?.let {
for (index in 0 until folders.size) {
dataList.addAll(folders[index].images)
}
}
runOnUiThread {
albumAdapter.notifyDataSetChanged()
}
}
})
}
override fun startObserve() {
}
override fun onImageSelect(selectCount: Int) {
// 改变 删除按钮数据
updateBtnText(selectCount)
}
override fun onItemClick(image: Image?, position: Int) {
LogUtil.d("onItemClick: $position")
}
// 删除图片后更新图库
private fun updateAlbum(imgPath: String) {
val intent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
intent.data = Uri.fromFile(File(imgPath))
sendBroadcast(intent)
}
private fun updateBtnText(selectCount: Int) {
// 若有选中图片,改变删除按钮样式,更新数据
if (selectCount > 0) {
btn_clean.background = ContextCompat.getDrawable(this, R.drawable.btn_clean_selected)
var selectSize = 0L
val selectImageList = albumAdapter.getSelectImageList()
for (element in selectImageList) {
selectSize += element.size
}
val selectSizeStr = FileUtils.formatFileSize(selectSize)
btn_clean.text = "删除($selectSizeStr)"
} else {
btn_clean.background = ContextCompat.getDrawable(this, R.drawable.btn_clean_unselected)
btn_clean.text = "删除(0KB)"
}
}
}
\ No newline at end of file
package com.mints.cleaner.ui.albumClean
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.database.ContentObserver
import android.net.Uri
import android.provider.MediaStore
import androidx.core.content.ContextCompat
import com.mints.cleaner.R
import com.mints.cleaner.model.bean.Folder
import com.mints.cleaner.model.bean.Image
import com.mints.cleaner.util.ImageUtil
import com.mints.cleaner.util.UriUtils
import java.io.File
import java.util.*
object AlbumCleanModel {
/**
* 缓存图片
*/
private var cacheImageList: ArrayList<Folder>? = null
private var isNeedCache = false
private var observer: PhotoContentObserver? = null
/**
* 预加载图片
*
* @param context
*/
fun preloadAndRegisterContentObserver(context: Context) {
isNeedCache = true
if (observer == null) {
observer = PhotoContentObserver(context.applicationContext)
context.applicationContext.contentResolver.registerContentObserver(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, observer!!
)
}
preload(context)
}
private fun preload(context: Context) {
val hasWriteExternalPermission =
ContextCompat.checkSelfPermission(
context,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
if (hasWriteExternalPermission == PackageManager.PERMISSION_GRANTED) {
//有权限,加载图片。
loadImageForSDCard(context, true, null)
}
}
/**
* 清空缓存
*/
fun clearCache(context: Context) {
isNeedCache = false
if (observer != null) {
context.applicationContext.contentResolver.unregisterContentObserver(observer!!)
observer = null
}
Thread(Runnable {
synchronized(AlbumCleanModel::class.java) {
if (cacheImageList != null) {
cacheImageList!!.clear()
cacheImageList = null
}
}
}).start()
}
/**
* 从SDCard加载图片
*
* @param context
* @param callback
*/
fun loadImageForSDCard(
context: Context,
callback: DataCallback?
) {
loadImageForSDCard(context, false, callback)
}
/**
* 从SDCard加载图片
*
* @param context
* @param isPreload 是否是预加载
* @param callback
*/
private fun loadImageForSDCard(
context: Context,
isPreload: Boolean,
callback: DataCallback?
) {
//由于扫描图片是耗时的操作,所以要在子线程处理。
Thread(Runnable {
synchronized(AlbumCleanModel::class.java) {
val imageCacheDir: String = ImageUtil.getImageCacheDir(context)
var folders: ArrayList<Folder>? = null
if (cacheImageList == null || isPreload) {
val imageList: ArrayList<Image> = loadImage(context)
Collections.sort(imageList, Comparator<Image> { image, t1 ->
when {
image.time > t1.time -> {
1
}
image.time < t1.time -> {
-1
}
else -> {
0
}
}
})
val images: ArrayList<Image> = arrayListOf()
for (image in imageList) {
// 过滤不存在或未下载完成的图片
val exists =
"downloading" != getExtensionName(image.path) && checkImgExists(
image.path
)
//过滤剪切保存的图片;
val isCutImage: Boolean =
ImageUtil.isCutImage(imageCacheDir, image.path)
if (!isCutImage && exists) {
images.add(image)
}
}
images.reverse()
folders = splitFolder(context, images)
if (isNeedCache) {
cacheImageList = folders
}
} else {
folders = cacheImageList
}
callback?.onSuccess(folders)
}
}).start()
}
/**
* 从SDCard加载图片
*
* @param context
* @return
*/
@Synchronized
private fun loadImage(context: Context): ArrayList<Image> {
//扫描图片
val mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val mContentResolver = context.contentResolver
val mCursor = mContentResolver.query(
mImageUri, arrayOf(
MediaStore.Images.Media.DATA,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATE_ADDED,
MediaStore.Images.Media._ID,
MediaStore.Images.Media.MIME_TYPE,
MediaStore.Images.Media.SIZE
),
MediaStore.MediaColumns.SIZE + ">0",
null,
MediaStore.Images.Media.DATE_ADDED + " DESC"
)
val images: ArrayList<Image> = arrayListOf()
//读取扫描到的图片
if (mCursor != null) {
while (mCursor.moveToNext()) {
// 获取图片的路径
val id =
mCursor.getLong(mCursor.getColumnIndex(MediaStore.Images.Media._ID))
val path = mCursor.getString(
mCursor.getColumnIndex(MediaStore.Images.Media.DATA)
)
//获取图片名称
val name = mCursor.getString(
mCursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)
)
//获取图片时间
var time = mCursor.getLong(
mCursor.getColumnIndex(MediaStore.Images.Media.DATE_ADDED)
)
if (time.toString().length < 13) {
time *= 1000
}
//获取图片类型
val mimeType = mCursor.getString(
mCursor.getColumnIndex(MediaStore.Images.Media.MIME_TYPE)
)
//获取图片uri
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon()
.appendPath(id.toString()).build()
//获取图片size
var size = mCursor.getLong(
mCursor.getColumnIndex(MediaStore.Images.Media.SIZE)
)
images.add(Image(path, time, name, mimeType, uri, size))
}
mCursor.close()
}
return images
}
/**
* 检查图片是否存在。ContentResolver查询处理的数据有可能文件路径并不存在。
*
* @param filePath
* @return
*/
private fun checkImgExists(filePath: String): Boolean {
return File(filePath).exists()
}
private fun getPathForAndroidQ(
context: Context,
id: Long
): String? {
return UriUtils.getPathForUri(
context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon()
.appendPath(id.toString()).build()
)
}
/**
* 把图片按文件夹拆分,第一个文件夹保存所有的图片
*
* @param images
* @return
*/
private fun splitFolder(
context: Context,
images: ArrayList<Image>
): ArrayList<Folder> {
val folders: ArrayList<Folder> = ArrayList<Folder>()
folders.add(Folder(context.getString(R.string.selector_all_image), images))
if (images != null && images.isNotEmpty()) {
val size = images.size
for (i in 0 until size) {
val path: String = images[i]!!.path
val name = getFolderName(path)
if (name.isNotEmpty()) {
val folder: Folder = getFolder(name, folders)
folder.addImage(images[i])
}
}
}
return folders
}
/**
* Java文件操作 获取文件扩展名
*/
fun getExtensionName(filename: String?): String {
if (filename != null && filename.isNotEmpty()) {
val dot = filename.lastIndexOf('.')
if (dot > -1 && dot < filename.length - 1) {
return filename.substring(dot + 1)
}
}
return ""
}
/**
* 根据图片路径,获取图片文件夹名称
*
* @param path
* @return
*/
private fun getFolderName(path: String): String {
if (path.isNotEmpty()) {
val strings =
path.split(File.separator.toRegex()).toTypedArray()
if (strings.size >= 2) {
return strings[strings.size - 2]
}
}
return ""
}
private fun getFolder(
name: String,
folders: MutableList<Folder>
): Folder {
if (folders.isNotEmpty()) {
val size = folders.size
for (i in 0 until size) {
val folder: Folder = folders[i]
if (name == folder.name) {
return folder
}
}
}
val newFolder = Folder(name)
folders.add(newFolder)
return newFolder
}
interface DataCallback {
fun onSuccess(folders: ArrayList<Folder>?)
}
private class PhotoContentObserver(private val context: Context) :
ContentObserver(null) {
override fun onChange(
selfChange: Boolean,
uri: Uri
) {
super.onChange(selfChange, uri)
preload(context)
}
}
}
\ No newline at end of file
package com.mints.cleaner.ui.home
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.widget.Toast
import com.mints.cleaner.R
import com.mints.cleaner.adapter.clean.CleanAdapter
import com.mints.cleaner.adapter.clean.CleanMultiItem
import com.mints.cleaner.databinding.FragmentCleanBinding
import com.mints.cleaner.model.bean.HeaderTitle
import com.mints.cleaner.ui.main.MainViewModel
......@@ -20,29 +18,21 @@ import org.koin.androidx.viewmodel.ext.android.viewModel
class HomeFragment : BaseVMFragment<FragmentCleanBinding>(R.layout.fragment_clean) {
private val mainViewModel by viewModel<MainViewModel>()
private val cleanAdapter by lazy { CleanAdapter(multiItemList) }
private val multiItemList =
arrayListOf(
CleanMultiItem(CleanMultiItem.ITEM_TOP),
CleanMultiItem(CleanMultiItem.ITEM_MID),
CleanMultiItem(CleanMultiItem.ITEM_BOTTOM, 0),
CleanMultiItem(CleanMultiItem.ITEM_BOTTOM, 1),
CleanMultiItem(CleanMultiItem.ITEM_BOTTOM, 2),
CleanMultiItem(CleanMultiItem.ITEM_BOTTOM, 3)
)
private val cleanAdapter by lazy { CleanAdapter(mainViewModel.repository.getHomeData()) }
override fun initView() {
binding.run {
viewModel = mainViewModel
adapter = cleanAdapter
title = HeaderTitle(
R.string.app_name,
View.GONE,
R.mipmap.ic_activity_arrow,
{},
R.color.theme
)
}
initRecyclerView()
......@@ -53,7 +43,7 @@ class HomeFragment : BaseVMFragment<FragmentCleanBinding>(R.layout.fragment_clea
addFooterView(LayoutInflater.from(activity).inflate(R.layout.home_footer, null))
// 一键清理
setOnItemChildClickListener { adapter, view, position ->
setOnItemChildClickListener { _, _, _ ->
// 一键清理
activity?.let { toast(it, "一键清理", Toast.LENGTH_SHORT) }
}
......
package com.mints.cleaner.ui.setting
import android.view.View
import com.mints.cleaner.R
import com.mints.cleaner.databinding.ActivitySettingBinding
import com.mints.cleaner.model.bean.HeaderTitle
import com.mints.core.base.BaseVMActivity
import kotlinx.android.synthetic.main.header_bar.*
class SettingActivity : BaseVMActivity() {
private val binding by binding<ActivitySettingBinding>(R.layout.activity_setting)
override fun initView() {
binding.run {
title = HeaderTitle(
R.string.app_name,
View.GONE,
R.mipmap.ic_activity_arrow,
{},
R.color.theme
)
}
iv_header_left.setOnClickListener {
onBackPressed()
}
}
override fun initData() {
}
override fun startObserve() {
}
}
\ No newline at end of file
package com.mints.cleaner.util
import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.provider.MediaStore
import java.text.DecimalFormat
object FileUtils {
//定义GB的计算常量
private const val GB = 1024 * 1024 * 1024
//定义MB的计算常量
private const val MB = 1024 * 1024
//定义KB的计算常量
private const val KB = 1024
fun formatFileSize(bytes: Long): String {
//格式化小数
val format = DecimalFormat("###.0")
return when {
bytes / GB >= 1 -> {
format.format(bytes.toDouble() / GB) + "GB"
}
bytes / MB >= 1 -> {
format.format(bytes.toDouble() / MB) + "MB"
}
bytes / KB >= 1 -> {
format.format(bytes.toDouble() / KB) + "KB"
}
else -> {
bytes.toString() + "B"
}
}
}
fun deleteImage(imgPath: String, context: Context): Boolean {
val resolver: ContentResolver = context.contentResolver
val cursor: Cursor = MediaStore.Images.Media.query(
resolver,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
arrayOf(MediaStore.Images.Media._ID),
MediaStore.Images.Media.DATA + "=?",
arrayOf(imgPath),
null
)
var result = false
var uri: Uri?
if (cursor.moveToFirst()) {
val id = cursor.getLong(0)
val contentUri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
uri = ContentUris.withAppendedId(contentUri, id)
val count: Int = context.contentResolver.delete(uri, null, null)
result = count == 1
} else {
val cursor2 = MediaStore.Images.Media.query(
resolver,
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
arrayOf(MediaStore.Images.Media._ID),
MediaStore.Images.Media.DATA + "=?",
arrayOf(imgPath),
null
)
if (cursor2.moveToFirst()) {
val id = cursor2.getLong(0)
val contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
uri = ContentUris.withAppendedId(contentUri, id)
val count: Int = context.contentResolver.delete(uri, null, null)
result = count == 1
}
}
return result
}
}
\ No newline at end of file
package com.mints.cleaner.util;
import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import android.util.Log;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class ImageUtil {
/**
* 获取缓存图片的文件夹
*
* @param context
* @return
*/
public static String getImageCacheDir(Context context) {
File file = null;
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|| !Environment.isExternalStorageRemovable()) {
if (VersionUtils.INSTANCE.isAndroidQ()) {
file = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
} else {
file = context.getExternalCacheDir();
}
}
if (file == null) {
file = context.getCacheDir();
}
return file.getPath() + File.separator + "image_select";
}
/**
* 保存图片
*
* @param bitmap
* @param path
* @param name
* @return
*/
public static String saveImage(Bitmap bitmap, String path, String name) {
FileOutputStream b = null;
File file = new File(path);
if (!file.exists()) {
file.mkdirs();// 创建文件夹
}
String fileName = path + File.separator + name + ".jpg";
try {
b = new FileOutputStream(fileName);
bitmap.compress(Bitmap.CompressFormat.JPEG, 75, b);// 把数据写入文件
return fileName;
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (b != null) {
b.flush();
b.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return "";
}
public static Bitmap zoomBitmap(Bitmap bm, int reqWidth, int reqHeight) {
// 获得图片的宽高
int width = bm.getWidth();
int height = bm.getHeight();
// 计算缩放比例
float scaleWidth = ((float) reqWidth) / width;
float scaleHeight = ((float) reqHeight) / height;
float scale = Math.min(scaleWidth, scaleHeight);
// 取得想要缩放的matrix参数
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
// 得到新的图片
Bitmap newbm = Bitmap.createBitmap(bm, 0, 0, width, height, matrix,
true);
return newbm;
}
/**
* 根据计算的inSampleSize,得到压缩后图片
*
* @param pathName
* @param reqWidth
* @param reqHeight
* @return
*/
@SuppressLint("NewApi")
public static Bitmap decodeSampledBitmapFromFile(Context context, String pathName, int reqWidth, int reqHeight) {
int degree = 0;
Uri uri = UriUtils.getImageContentUri(context, pathName);
ParcelFileDescriptor parcelFileDescriptor = null;
FileDescriptor fileDescriptor = null;
try {
parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "r");
fileDescriptor = parcelFileDescriptor.getFileDescriptor();
ExifInterface exifInterface = null;
if (VersionUtils.INSTANCE.isAndroidQ()) {
exifInterface = new ExifInterface(fileDescriptor);
} else {
exifInterface = new ExifInterface(pathName);
}
int result = exifInterface.getAttributeInt(
ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
switch (result) {
case ExifInterface.ORIENTATION_ROTATE_90:
degree = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
degree = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
degree = 270;
break;
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
try {
// 第一次解析将inJustDecodeBounds设置为true,来获取图片大小
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
if (VersionUtils.INSTANCE.isAndroidQ()) {
BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
} else {
BitmapFactory.decodeFile(pathName, options);
}
// 调用上面定义的方法计算inSampleSize值
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// 使用获取到的inSampleSize值再次解析图片
options.inJustDecodeBounds = false;
// options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = null;
if (VersionUtils.INSTANCE.isAndroidQ()) {
bitmap = getBitmapFromUri(context, uri, options);
} else {
bitmap = BitmapFactory.decodeFile(pathName, options);
}
parcelFileDescriptor.close();
if (degree != 0) {
Bitmap newBitmap = rotateImageView(bitmap, degree);
bitmap.recycle();
bitmap = null;
return newBitmap;
}
return bitmap;
} catch (OutOfMemoryError error) {
Log.e("eee", "内存泄露!");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 获取Bitmap
*
* @param context
* @param uri
* @return
*/
public static Bitmap getBitmapFromUri(Context context, Uri uri) {
return getBitmapFromUri(context, uri, null);
}
/**
* 获取Bitmap
*
* @param context
* @param uri
* @return
*/
public static Bitmap getBitmapFromUri(Context context, Uri uri, BitmapFactory.Options options) {
try {
ParcelFileDescriptor parcelFileDescriptor =
context.getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
parcelFileDescriptor.close();
return image;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 旋转图片
*
* @param bitmap
* @param angle
* @return Bitmap
*/
public static Bitmap rotateImageView(Bitmap bitmap, int angle) {
//旋转图片 动作
Matrix matrix = new Matrix();
matrix.postRotate(angle);
// 创建新的图片
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
/**
* 计算inSampleSize,用于压缩图片
*
* @param options
* @param reqWidth
* @param reqHeight
* @return
*/
private static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// 源图片的宽度
int width = options.outWidth;
int height = options.outHeight;
int inSampleSize = 1;
if (width > reqWidth && height > reqHeight) {
// 计算出实际宽度和目标宽度的比率
int widthRatio = Math.round((float) width / (float) reqWidth);
int heightRatio = Math.round((float) height / (float) reqHeight);
inSampleSize = Math.max(widthRatio, heightRatio);
}
return inSampleSize;
}
public static boolean isEffective(String path) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
return options.outWidth > 0 && options.outHeight > 0;
}
public static boolean isEffective(Context context, Uri uri) {
try {
ParcelFileDescriptor parcelFileDescriptor =
context.getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
return options.outWidth > 0 && options.outHeight > 0;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
/**
* 是否是剪切返回的图片
*
* @param context
* @param path
* @return
*/
public static boolean isCutImage(Context context, String path) {
return isCutImage(getImageCacheDir(context), path);
}
/**
* 是否是剪切返回的图片
*
* @param dir
* @param path
* @return
*/
public static boolean isCutImage(String dir, String path) {
if (!path.isEmpty()) {
return path.startsWith(dir);
}
return false;
}
/**
* 保存拍照的图片
*
* @param context
* @param uri
* @param takeTime 调起相机拍照的时间
*/
public static void savePicture(final Context context, final Uri uri, final long takeTime) {
new Thread(new Runnable() {
@Override
public void run() {
if (isNeedSavePicture(context, takeTime)) {
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
}
}
}).start();
}
/**
* 是否需要保存拍照的图片
*
* @param context
* @return
*/
private static boolean isNeedSavePicture(Context context, long takeTime) {
//扫描图片
Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver mContentResolver = context.getContentResolver();
Cursor mCursor = mContentResolver.query(mImageUri, new String[]{
MediaStore.Images.Media.DATE_ADDED,
MediaStore.Images.Media._ID,
MediaStore.Images.Media.SIZE},
MediaStore.MediaColumns.SIZE + ">0",
null,
MediaStore.Files.FileColumns._ID + " DESC limit 1 offset 0");
//读取扫描到的图片
if (mCursor != null && mCursor.getCount() > 0 && mCursor.moveToFirst()) {
//获取图片时间
long time = mCursor.getLong(mCursor.getColumnIndex(MediaStore.Images.Media.DATE_ADDED));
int id = mCursor.getInt(mCursor.getColumnIndex(MediaStore.Images.Media._ID));
if (String.valueOf(time).length() < 13) {
time *= 1000;
}
mCursor.close();
// 如果照片的插入时间大于相机的拍照时间,就认为是拍照图片已插入
return time + 1000 < takeTime;
}
return true;
}
}
\ No newline at end of file
package com.mints.cleaner.util;
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.util.Log;
import java.io.File;
/**
* @Author teach-梁任彦
* @Description
* @Date 2019-09-11
*/
public class UriUtils {
@SuppressLint("NewApi")
public static String getPathForUri(Context context,Uri uri){
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
if (VersionUtils.INSTANCE.isAndroidQ()) {
return context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) + "/" + split[1];
} else {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri)) {
return uri.getLastPathSegment();
}
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} catch (IllegalArgumentException ex) {
} finally {
if (cursor != null) {
cursor.close();
}
}
return null;
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
/**
* 判断是否是Google相册的图片,类似于content://com.google.android.apps.photos.content/...
**/
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
/**
* 判断是否是Google相册的图片,类似于content://com.google.android.apps.photos.contentprovider/0/1/mediakey:/local%3A821abd2f-9f8c-4931-bbe9-a975d1f5fabc/ORIGINAL/NONE/1075342619
**/
public static boolean isGooglePlayPhotosUri(Uri uri) {
return "com.google.android.apps.photos.contentprovider".equals(uri.getAuthority());
}
/**
* 图片路径转uri
* @param context
* @param path
* @return
*/
public static Uri getImageContentUri(Context context, String path) {
Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[] { MediaStore.Images.Media._ID }, MediaStore.Images.Media.DATA + "=? ",
new String[] { path }, null);
if (cursor != null && cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
Uri baseUri = Uri.parse("content://media/external/images/media");
return Uri.withAppendedPath(baseUri, "" + id);
} else {
if (new File(path).exists()) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, path);
return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} else {
return null;
}
}
}
}
package com.mints.cleaner.util
import android.os.Build
object VersionUtils {
/**
* 判断是否是Android L版本
*
* @return
*/
fun isAndroidL(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
}
/**
* 判断是否是Android N版本
*
* @return
*/
fun isAndroidN(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
}
/**
* 判断是否是Android P版本
*
* @return
*/
fun isAndroidP(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
}
/**
* 判断是否是Android Q版本
*
* @return
*/
fun isAndroidQ(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
}
}
\ No newline at end of file
package com.mints.cleaner.widget
import android.content.Context
import android.util.AttributeSet
class RoundCheckBox : androidx.appcompat.widget.AppCompatCheckBox {
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, androidx.appcompat.R.attr.radioButtonStyle)
constructor(context: Context) : this(context, null)
}
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
\ 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">
<solid android:color="@color/green" />
<corners android:radius="6dp" />
</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">
<solid android:color="@color/gray" />
<corners android:radius="6dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="title"
type="com.mints.cleaner.model.bean.CleanHeaderTitle" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
layout="@layout/clean_header_bar"
title="title" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview_album"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View style="@style/line_3" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_clean"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="10dp"
android:background="@drawable/btn_clean_unselected"
android:text="删除(0KB)"
android:textColor="@color/white"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
</layout>
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="title"
type="com.mints.cleaner.model.bean.HeaderTitle" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
layout="@layout/header_bar"
app:title="@{title}" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="20dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/feature_set"
android:textColor="@color/black"
android:textSize="18sp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_activity_arrow" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="20dp">
<TextView
android:id="@+id/tv_title2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/about_us"
android:textColor="@color/black"
android:textSize="18sp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_activity_arrow" />
</LinearLayout>
</LinearLayout>
</layout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="title"
type="com.mints.cleaner.model.bean.CleanHeaderTitle" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@{title.background}"
android:paddingTop="30dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp">
<ImageView
android:id="@+id/iv_header_left_clean"
onClick="@{title.leftAction}"
icon="@{title.leftIcon}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="10dp"
android:scaleType="center" />
<TextView
android:id="@+id/tv_activity_title_clean"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="10dp"
android:layout_toEndOf="@id/iv_header_left_clean"
android:text="@{title.title}"
android:textColor="@color/product_net_text"
android:textSize="18sp" />
<TextView
android:id="@+id/tv_activity_right_clean"
onClick="@{title.rightInfoAction}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="10dp"
android:text="@{title.rightInfo}"
android:textColor="@color/product_net_text"
android:textSize="18sp"
android:visibility="@{title.rightInfoVisible}" />
</RelativeLayout>
</FrameLayout>
</layout>
\ No newline at end of file
......@@ -8,44 +8,40 @@
type="com.mints.cleaner.model.bean.HeaderTitle" />
</data>
<RelativeLayout
<FrameLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@{title.background}">
<ImageView
android:id="@+id/iv_header_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="40dp"
android:scaleType="center"
android:src="@mipmap/ic_activity_arrow"
android:visibility="@{title.backArrowVisible}" />
<TextView
android:id="@+id/tv_activity_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="40dp"
android:layout_toEndOf="@id/iv_header_left"
android:text="@{title.title}"
android:textColor="@color/product_net_text"
android:textSize="18sp" />
<ImageView
android:id="@+id/iv_header_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginTop="40dp"
android:layout_marginEnd="20dp"
android:scaleType="center"
android:src="@{title.rightIcon}" />
<View
style="@style/line_3"
android:layout_alignParentBottom="true" />
</RelativeLayout>
android:layout_height="wrap_content"
android:background="@{title.background}"
android:paddingTop="30dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp">
<ImageView
android:id="@+id/iv_header_left"
onClick="@{title.leftAction}"
icon="@{title.leftIcon}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="10dp"
android:scaleType="center"
android:visibility="@{title.leftIconVisible}" />
<TextView
android:id="@+id/tv_activity_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="10dp"
android:layout_toEndOf="@id/iv_header_left"
android:text="@{title.title}"
android:textColor="@color/product_net_text"
android:textSize="18sp" />
</RelativeLayout>
</FrameLayout>
</layout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp">
<ImageView
android:id="@+id/iv_item_album"
android:layout_width="match_parent"
android:layout_height="150dp"
android:scaleType="centerCrop" />
<com.mints.cleaner.widget.RoundCheckBox
android:id="@+id/cb_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|bottom" />
</FrameLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="20dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_activity_arrow" />
</LinearLayout>
\ No newline at end of file
......@@ -14,6 +14,7 @@
<color name="gray">#999999</color>
<color name="gray_01">#F5F5F5</color>
<color name="gray_02">#E8E8F0</color>
<color name="green">#00FF00</color>
<color name="status_bg">#002444</color>
<color name="product_net_text">#121B32</color>
......
......@@ -28,4 +28,11 @@
<string name="music_clean_info">清理不喜欢的音乐</string>
<string name="zip_clean_info">清理无用的压缩包</string>
<string name="about">清理无用的压缩包</string>
<string name="feature_set">功能设置</string>
<string name="about_us">关于我们</string>
<string name="selector_all_image">全部图片</string>
</resources>
\ No newline at end of file
......@@ -2,9 +2,9 @@
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<!-- <item name="colorPrimary">@color/colorPrimary</item>-->
<!-- <item name="colorPrimaryDark">@color/colorPrimaryDark</item>-->
<!-- <item name="colorAccent">@color/colorAccent</item>-->
<item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
</style>
......
......@@ -27,6 +27,7 @@ object Versions {
const val banner = "1.4.10"
const val glide = "4.11.0"
const val glide_compiler = "4.11.0"
const val photoView = "2.0.0"
const val cardView = "1.0.0"
const val verticalTabLayout = "1.2.5"
const val flowLayout = "1.1.2"
......@@ -75,6 +76,7 @@ object Deps {
const val orhanobut_logger = "com.orhanobut:logger:${Versions.orhanobut_logger}"
// third
const val photoView = "com.github.chrisbanes:PhotoView:${Versions.photoView}"
const val circleimageview = "de.hdodenhof:circleimageview:${Versions.circleImageview}"
const val leakCanary = "com.squareup.leakcanary:leakcanary-android:${Versions.leakcanary}"
const val baseRecyclerViewAdapterHelper = "com.github.CymChad:BaseRecyclerViewAdapterHelper:${Versions.baseRecyclerViewAdapterHelper}"
......
package com.mints.core.binding
import android.widget.ImageView
import androidx.databinding.BindingAdapter
@BindingAdapter("icon", requireAll = false)
fun ImageView.init(iconResId: Int) {
setImageResource(iconResId)
}
\ No newline at end of file
package com.mints.core.binding
import android.view.View
import androidx.databinding.BindingAdapter
@BindingAdapter("onClick", requireAll = false)
fun View.init(action: () -> Unit) {
setOnClickListener { action() }
}
\ No newline at end of file
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