Commit 9faec8a2 authored by jyx's avatar jyx

视频清理

parent ce010dc7
......@@ -16,7 +16,11 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".ui.setting.SettingActivity"></activity>
<activity android:name=".ui.albumClean.AlbumCleanActivity">
<activity android:name=".ui.albumClean.AlbumCleanActivity" />
<activity
android:name=".ui.multiClean.MultiCleanActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
......@@ -34,6 +38,22 @@
<activity android:name=".ui.NavigationActivity">
</activity>
<activity
android:name=".ui.PreviewActivity"
android:launchMode="singleTop"
android:theme="@style/CustomerTransparentTheme" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
</application>
</manifest>
\ No newline at end of file
package com.mints.cleaner.adapter
package com.mints.cleaner.adapter.albumClean
import android.widget.ImageView
import com.bumptech.glide.Glide
......@@ -11,7 +11,6 @@ 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) {
......@@ -22,7 +21,6 @@ class AlbumCleanAdapter(layoutResId: Int, data: List<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()
......@@ -30,7 +28,13 @@ class AlbumCleanAdapter(layoutResId: Int, data: List<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))
.apply(
RequestOptions()
.centerCrop()
.placeholder(drawable)
.dontAnimate()
.diskCacheStrategy(DiskCacheStrategy.NONE)
)
.into(this)
setOnClickListener {
......@@ -143,7 +147,7 @@ class AlbumCleanAdapter(layoutResId: Int, data: List<Image>) :
}
interface OnItemClickListener {
fun onItemClick(image: Image?, position: Int)
fun onItemClick(image: Image, position: Int)
}
}
\ No newline at end of file
package com.mints.cleaner.adapter.clean
package com.mints.cleaner.adapter.home
import android.widget.GridView
import android.widget.SimpleAdapter
......@@ -6,21 +6,21 @@ import com.chad.library.adapter.base.BaseMultiItemQuickAdapter
import com.chad.library.adapter.base.BaseViewHolder
import com.mints.cleaner.R
class CleanAdapter : BaseMultiItemQuickAdapter<CleanMultiItem, BaseViewHolder> {
class HomeAdapter : BaseMultiItemQuickAdapter<HomeMultiItem, BaseViewHolder> {
constructor(data: List<CleanMultiItem>) : super(data) {
addItemType(CleanMultiItem.ITEM_TOP, R.layout.item_clean_top)
addItemType(CleanMultiItem.ITEM_MID, R.layout.item_clean_mid)
addItemType(CleanMultiItem.ITEM_BOTTOM, R.layout.item_clean_bottom)
constructor(data: List<HomeMultiItem>) : super(data) {
addItemType(HomeMultiItem.ITEM_TOP, R.layout.item_clean_top)
addItemType(HomeMultiItem.ITEM_MID, R.layout.item_clean_mid)
addItemType(HomeMultiItem.ITEM_BOTTOM, R.layout.item_clean_bottom)
}
override fun convert(helper: BaseViewHolder, item: CleanMultiItem?) {
override fun convert(helper: BaseViewHolder, item: HomeMultiItem?) {
when (helper.itemViewType) {
CleanMultiItem.ITEM_TOP -> {
HomeMultiItem.ITEM_TOP -> {
helper.addOnClickListener(R.id.btn_clean)
}
CleanMultiItem.ITEM_MID -> {
HomeMultiItem.ITEM_MID -> {
val gridView = helper.getView<GridView>(R.id.gv_clean)
val simpleAdapter = SimpleAdapter(
gridView.context,
......@@ -36,7 +36,7 @@ class CleanAdapter : BaseMultiItemQuickAdapter<CleanMultiItem, BaseViewHolder> {
}
}
}
CleanMultiItem.ITEM_BOTTOM -> {
HomeMultiItem.ITEM_BOTTOM -> {
}
}
......
package com.mints.cleaner.adapter.clean
package com.mints.cleaner.adapter.home
import com.chad.library.adapter.base.entity.MultiItemEntity
class CleanMultiItem : MultiItemEntity {
class HomeMultiItem : MultiItemEntity {
private var itemType: Int = 0
......
package com.mints.cleaner.adapter.impl
// TODO 公用接口回调
\ No newline at end of file
package com.mints.cleaner.adapter.multiClean
import android.widget.ImageView
import android.widget.TextView
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.FileBean
import com.mints.cleaner.util.FormatUtils
import com.mints.cleaner.widget.RoundCheckBox
class MultiCleanAdapter(layoutResId: Int, data: List<FileBean>) :
BaseQuickAdapter<FileBean, BaseViewHolder>(layoutResId, data) {
// 选中图片数据
private var mSelectImages = arrayListOf<FileBean>()
// 复选框选中状态
private var mCheckBoxTags = arrayListOf<Int>()
private var mSelectListener: OnImageSelectListener? = null
private var mItemClickListener: OnItemClickListener? = null
override fun convert(helper: BaseViewHolder, item: FileBean) {
helper.getView<ImageView>(R.id.iv_item_multi).run {
Glide.with(mContext).load(item.path)
.apply(
RequestOptions()
.centerCrop()
.placeholder(drawable)
.dontAnimate()
.diskCacheStrategy(DiskCacheStrategy.NONE)
)
.into(this)
setOnClickListener {
mItemClickListener?.let {
it.onItemClick(item, helper.adapterPosition)
}
}
}
helper.getView<TextView>(R.id.tv_item_multi_name).text = item.name
helper.getView<TextView>(R.id.tv_item_multi_size).text = FormatUtils.formatFileSize(item.size)
helper.getView<TextView>(R.id.tv_item_multi_time).text = FormatUtils.formatDuration(item.time)
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<FileBean> {
return mSelectImages
}
// 更新数据
fun refreshData(data: List<FileBean>) {
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: FileBean) {
mSelectImages.add(image)
mSelectListener?.let {
it.onImageSelect(mSelectImages.size)
}
}
/**
* 取消选中图片
*/
private fun unSelectImage(file: FileBean) {
mSelectImages.remove(file)
mSelectListener?.let {
it.onImageSelect(mSelectImages.size)
}
}
interface OnImageSelectListener {
fun onImageSelect(
selectCount: Int
)
}
interface OnItemClickListener {
fun onItemClick(file: FileBean, position: Int)
}
}
\ No newline at end of file
package com.mints.cleaner.model.bean
import android.view.View
import androidx.databinding.BaseObservable
import androidx.databinding.Bindable
import com.mints.cleaner.BR
import com.mints.cleaner.R
class CleanHeaderTitle : BaseObservable {
class CleanHeaderTitle(
// 标题内容
var title: Int,
// 左边图标
var leftIcon: Int,
var leftIcon: Int = 0
// 左边图标点击事件
var leftAction: () -> Unit,
var leftAction: () -> Unit = {}
// 右边文字是否显示
val rightInfoVisible: Int,
// 右边文字内容
val rightInfo: String,
var rightInfoVisible: Int = View.GONE
// 右边文字点击事件
val rightInfoAction: () -> Unit,
var rightInfoAction: () -> Unit = {}
// 背景颜色
val background: Int
)
\ No newline at end of file
var background: Int = R.color.theme
@get:Bindable
// 标题内容
var title: String? = null
set(value) {
field = value
notifyPropertyChanged(BR.title)
}
@get:Bindable
// 右边文字内容
var rightInfo: String? = null
set(value) {
field = value
notifyPropertyChanged(BR.rightInfo)
}
constructor(
title: String,
leftIcon: Int,
leftAction: () -> Unit,
rightInfoVisible: Int,
rightInfo: String,
rightInfoAction: () -> Unit,
background: Int
) {
this.title = title
this.leftIcon = leftIcon
this.leftAction = leftAction
this.rightInfo = rightInfo
this.rightInfoVisible = rightInfoVisible
this.rightInfoAction = rightInfoAction
this.background = background
}
}
\ No newline at end of file
package com.mints.cleaner.model.bean
import android.os.Parcel
import android.os.Parcelable
data class FileBean(
val thumbPath: String,
val path: String,
val time: Long,
val modifyTime: Long,
val name: String,
val size: Long
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString()!!,
parcel.readString()!!,
parcel.readLong(),
parcel.readLong(),
parcel.readString()!!,
parcel.readLong()
)
override fun writeToParcel(dest: Parcel?, flags: Int) {
dest?.run {
writeString(thumbPath)
writeString(path)
writeLong(time)
writeLong(modifyTime)
writeString(name)
writeLong(size)
}
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<FileBean> {
override fun createFromParcel(parcel: Parcel): FileBean {
return FileBean(parcel)
}
override fun newArray(size: Int): Array<FileBean?> {
return arrayOfNulls(size)
}
}
}
\ No newline at end of file
......@@ -3,7 +3,7 @@ package com.mints.cleaner.model.bean
class HeaderTitle(
// 标题内容
var title: Int,
var title: String,
// 返回箭头是否显示
var leftIconVisible: Int,
// 左边图标
......
package com.mints.cleaner.model.bean
import android.net.Uri
import android.os.Parcel
import android.os.Parcelable
data class Image(
val path: String,
......@@ -9,4 +11,38 @@ data class Image(
val mimeType: String,
val uri: Uri,
val size: Long
)
\ No newline at end of file
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString()!!,
parcel.readLong(),
parcel.readString()!!,
parcel.readString()!!,
parcel.readParcelable<Uri>(Uri::class.java.classLoader) as Uri,
parcel.readLong()
)
override fun writeToParcel(dest: Parcel?, flags: Int) {
dest?.run {
writeString(path)
writeLong(time)
writeString(name)
writeString(mimeType)
writeParcelable(uri, 0)
writeLong(size)
}
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Image> {
override fun createFromParcel(parcel: Parcel): Image {
return Image(parcel)
}
override fun newArray(size: Int): Array<Image?> {
return arrayOfNulls(size)
}
}
}
\ 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.adapter.home.HomeMultiItem
import com.mints.cleaner.model.api.ApiService
import com.mints.cleaner.model.api.client.BaseRepository
......@@ -18,11 +18,11 @@ class MainRepository(val service: ApiService) : BaseRepository() {
R.mipmap.ic_launcher
)
private var multiItemList: ArrayList<CleanMultiItem> = arrayListOf()
private var multiItemList: ArrayList<HomeMultiItem> = arrayListOf()
private val gvDataList: MutableList<Map<String, Any>> = ArrayList()
fun getHomeData(): ArrayList<CleanMultiItem> {
fun getHomeData(): ArrayList<HomeMultiItem> {
for (i in gvNames.indices) {
val item: MutableMap<String, Any> = HashMap()
item["item_gv_icon"] = gvIcons[i]
......@@ -31,12 +31,12 @@ class MainRepository(val service: ApiService) : BaseRepository() {
}
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)
HomeMultiItem(HomeMultiItem.ITEM_TOP),
HomeMultiItem(HomeMultiItem.ITEM_MID, gvDataList),
HomeMultiItem(HomeMultiItem.ITEM_BOTTOM),
HomeMultiItem(HomeMultiItem.ITEM_BOTTOM),
HomeMultiItem(HomeMultiItem.ITEM_BOTTOM),
HomeMultiItem(HomeMultiItem.ITEM_BOTTOM)
)
return multiItemList
......
package com.mints.cleaner.ui
import android.widget.ImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.RequestOptions
import com.github.chrisbanes.photoview.PhotoViewAttacher
import com.mints.cleaner.R
import com.mints.cleaner.model.bean.Image
import com.mints.cleaner.util.VersionUtils
import com.mints.core.base.BaseActivity
import kotlinx.android.synthetic.main.activity_preview.*
class PreviewActivity : BaseActivity() {
companion object {
const val IMAGE = "image"
}
private val image: Image by lazy { intent.getParcelableExtra(IMAGE) as Image }
override fun getLayoutResId() = R.layout.activity_preview
override fun initView() {
val photoViewAttacher = PhotoViewAttacher(pv_preview)
pv_preview.scaleType = ImageView.ScaleType.FIT_CENTER
Glide.with(mContext)
.load(if (VersionUtils.isAndroidQ()) image.uri else image.path)
.apply(RequestOptions().diskCacheStrategy(DiskCacheStrategy.NONE)).override(720, 1080)
.into(pv_preview)
photoViewAttacher.update()
photoViewAttacher.setOnPhotoTapListener { _, _, _ ->
onBackPressed()
}
}
override fun initData() {
}
}
\ No newline at end of file
......@@ -6,20 +6,20 @@ 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.adapter.albumClean.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.ui.PreviewActivity
import com.mints.cleaner.util.FileUtils
import com.mints.cleaner.util.LogUtil
import com.mints.cleaner.util.FormatUtils
import com.mints.core.base.BaseVMActivity
import com.mints.ktx.ext.startKtxActivity
import kotlinx.android.synthetic.main.activity_album_clean.*
import java.io.File
import java.util.*
class AlbumCleanActivity : BaseVMActivity(), AlbumCleanAdapter.OnImageSelectListener,
AlbumCleanAdapter.OnItemClickListener {
......@@ -29,7 +29,6 @@ class AlbumCleanActivity : BaseVMActivity(), AlbumCleanAdapter.OnImageSelectList
// 是否全选
private var flag = false
private var rightInfo = "全选"
private val albumAdapter: AlbumCleanAdapter by lazy {
AlbumCleanAdapter(
......@@ -41,20 +40,22 @@ class AlbumCleanActivity : BaseVMActivity(), AlbumCleanAdapter.OnImageSelectList
override fun initView() {
binding.run {
title = CleanHeaderTitle(
R.string.app_name,
getString(R.string.album_clean),
R.mipmap.ic_activity_arrow,
{
onBackPressed()
},
View.VISIBLE,
rightInfo,
getString(R.string.full_choice),
{
rightInfo = if (!flag) {
if (!flag) {
albumAdapter.fullSelectImage()
"取消全选"
title?.rightInfo = getString(R.string.cancel_full_choice)
title?.title = "已选中" + albumAdapter.getSelectImageList().size + "项"
} else {
albumAdapter.cancelFullSelectImage()
"全选"
title?.rightInfo = getString(R.string.full_choice)
title?.title = getString(R.string.album_clean)
}
flag = !flag
......@@ -110,24 +111,23 @@ class AlbumCleanActivity : BaseVMActivity(), AlbumCleanAdapter.OnImageSelectList
}
override fun onImageSelect(selectCount: Int) {
// 改变 删除按钮数据
updateBtnText(selectCount)
}
override fun onItemClick(image: Image?, position: Int) {
LogUtil.d("onItemClick: $position")
override fun onItemClick(image: Image, position: Int) {
startKtxActivity<PreviewActivity>(value = PreviewActivity.IMAGE to image)
}
// 删除图片后更新图库
private fun updateAlbum(imgPath: String) {
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
......@@ -135,7 +135,7 @@ class AlbumCleanActivity : BaseVMActivity(), AlbumCleanAdapter.OnImageSelectList
for (element in selectImageList) {
selectSize += element.size
}
val selectSizeStr = FileUtils.formatFileSize(selectSize)
val selectSizeStr = FormatUtils.formatFileSize(selectSize)
btn_clean.text = "删除($selectSizeStr)"
} else {
btn_clean.background = ContextCompat.getDrawable(this, R.drawable.btn_clean_unselected)
......
......@@ -103,7 +103,7 @@ object AlbumCleanModel {
var folders: ArrayList<Folder>? = null
if (cacheImageList == null || isPreload) {
val imageList: ArrayList<Image> = loadImage(context)
Collections.sort(imageList, Comparator<Image> { image, t1 ->
imageList.sortWith(Comparator { image, t1 ->
when {
image.time > t1.time -> {
1
......
......@@ -4,7 +4,7 @@ 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.home.HomeAdapter
import com.mints.cleaner.databinding.FragmentCleanBinding
import com.mints.cleaner.model.bean.HeaderTitle
import com.mints.cleaner.ui.main.MainViewModel
......@@ -18,7 +18,7 @@ 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(mainViewModel.repository.getHomeData()) }
private val cleanAdapter by lazy { HomeAdapter(mainViewModel.repository.getHomeData()) }
override fun initView() {
binding.run {
......@@ -27,7 +27,7 @@ class HomeFragment : BaseVMFragment<FragmentCleanBinding>(R.layout.fragment_clea
adapter = cleanAdapter
title = HeaderTitle(
R.string.app_name,
getString(R.string.app_name),
View.GONE,
R.mipmap.ic_activity_arrow,
{},
......@@ -71,7 +71,7 @@ class HomeFragment : BaseVMFragment<FragmentCleanBinding>(R.layout.fragment_clea
}
// 网格布局功能点击事件
setOnGridViewItemClickListener(object : CleanAdapter.OnGridViewItemClickListener {
setOnGridViewItemClickListener(object : HomeAdapter.OnGridViewItemClickListener {
override fun onGridViewItemClick(position: Int) {
when (position) {
0 -> {
......
package com.mints.cleaner.ui.multiClean
import android.content.Intent
import android.net.Uri
import android.view.View
import androidx.core.content.ContextCompat
import com.mints.cleaner.R
import com.mints.cleaner.adapter.multiClean.MultiCleanAdapter
import com.mints.cleaner.databinding.ActivityMultiCleanBinding
import com.mints.cleaner.model.bean.CleanHeaderTitle
import com.mints.cleaner.model.bean.FileBean
import com.mints.cleaner.util.FileUtils
import com.mints.cleaner.util.FormatUtils
import com.mints.cleaner.util.IntentUtils
import com.mints.core.base.BaseVMActivity
import kotlinx.android.synthetic.main.activity_album_clean.btn_clean
import kotlinx.android.synthetic.main.activity_multi_clean.*
import java.io.File
import java.util.ArrayList
class MultiCleanActivity : BaseVMActivity(), MultiCleanAdapter.OnImageSelectListener,
MultiCleanAdapter.OnItemClickListener {
private val binding by binding<ActivityMultiCleanBinding>(R.layout.activity_multi_clean)
private val dataList = arrayListOf<FileBean>()
private val multiAdapter: MultiCleanAdapter by lazy {
MultiCleanAdapter(
R.layout.item_multi_clean,
dataList
)
}
// 是否全选
private var flag = false
override fun initView() {
binding.run {
title = CleanHeaderTitle(
getString(R.string.video_clean),
R.mipmap.ic_activity_arrow,
{
onBackPressed()
},
View.VISIBLE,
getString(R.string.full_choice),
{
if (!flag) {
multiAdapter.fullSelectImage()
title?.rightInfo = getString(R.string.cancel_full_choice)
title?.title = "已选中" + multiAdapter.getSelectImageList().size + "项"
} else {
multiAdapter.cancelFullSelectImage()
title?.rightInfo = getString(R.string.full_choice)
title?.title = getString(R.string.album_clean)
}
flag = !flag
},
R.color.theme
)
}
initRecyclerView()
btn_clean.setOnClickListener {
val selectImageList = multiAdapter.getSelectImageList()
if (selectImageList.isEmpty()) return@setOnClickListener
for (element in selectImageList) {
FileUtils.deleteImage(element.path, this)
updateFile(element.path)
}
dataList.removeAll(selectImageList)
multiAdapter.cleanSelectImage()
multiAdapter.notifyDataSetChanged()
}
}
private fun initRecyclerView() {
recyclerview_multi.run {
adapter = multiAdapter
multiAdapter.setOnImageSelectListener(this@MultiCleanActivity)
multiAdapter.setOnItemClickListener1(this@MultiCleanActivity)
}
}
override fun initData() {
MultiCleanModel.loadVideoForSDCard(this, object : MultiCleanModel.DataCallback {
override fun onSuccess(files: ArrayList<FileBean>?) {
files?.let {
dataList.addAll(it)
}
runOnUiThread {
multiAdapter.notifyDataSetChanged()
}
}
})
}
override fun startObserve() {
}
override fun onImageSelect(selectCount: Int) {
// 改变 删除按钮数据
updateBtnText(selectCount)
}
override fun onItemClick(fileBean: FileBean, position: Int) {
val videoFileIntent = IntentUtils.getVideoFileIntent(this, fileBean.path)
startActivity(videoFileIntent)
}
// 删除后更新手机
private fun updateFile(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 = multiAdapter.getSelectImageList()
for (element in selectImageList) {
selectSize += element.size
}
val selectSizeStr = FormatUtils.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.multiClean
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.database.ContentObserver
import android.database.Cursor
import android.net.Uri
import android.provider.MediaStore
import androidx.core.content.ContextCompat
import com.mints.cleaner.model.bean.FileBean
import com.mints.cleaner.ui.albumClean.AlbumCleanModel
import com.mints.cleaner.util.UriUtils
import java.io.File
import java.util.*
import kotlin.Comparator
object MultiCleanModel {
/**
* 缓存图片
*/
private var cacheImageList: ArrayList<FileBean>? = 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) {
//有权限,加载图片。
loadVideoForSDCard(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 loadVideoForSDCard(
context: Context,
callback: DataCallback?
) {
loadVideoForSDCard(context, false, callback)
}
/**
* 从SDCard加载图片
*
* @param context
* @param isPreload 是否是预加载
* @param callback
*/
private fun loadVideoForSDCard(
context: Context,
isPreload: Boolean,
callback: DataCallback?
) {
//由于扫描图片是耗时的操作,所以要在子线程处理。
Thread(Runnable {
synchronized(AlbumCleanModel::class.java) {
var files: ArrayList<FileBean>?
if (cacheImageList == null || isPreload) {
val imageList: ArrayList<FileBean> = loadVideo(context)
imageList.sortWith(Comparator { image, t1 ->
when {
image.time > t1.time -> {
1
}
image.time < t1.time -> {
-1
}
else -> {
0
}
}
})
files = imageList
if (isNeedCache) {
cacheImageList = imageList
}
} else {
files = cacheImageList
}
callback?.onSuccess(files)
}
}).start()
}
/**
* 从SDCard加载图片
*
* @param context
* @return
*/
@Synchronized
private fun loadVideo(context: Context): ArrayList<FileBean> {
// 扫描视频
val mImageUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
val proj = arrayOf(
MediaStore.Video.Thumbnails._ID
, MediaStore.Video.Thumbnails.DATA
, MediaStore.Video.Media.DURATION
, MediaStore.Video.Media.SIZE
, MediaStore.Video.Media.DISPLAY_NAME
, MediaStore.Video.Media.DATE_MODIFIED
)
val mContentResolver = context.contentResolver
val mCursor: Cursor? = mContentResolver.query(
mImageUri,
proj,
MediaStore.Video.Media.MIME_TYPE + "=?",
arrayOf("video/mp4"),
MediaStore.Video.Media.DATE_MODIFIED + " DESC"
)
val files: ArrayList<FileBean> = arrayListOf()
mCursor?.run {
while (moveToNext()) {
// 获取视频的路径
val id = getInt(getColumnIndex(MediaStore.Video.Media._ID))
val path = getString(getColumnIndex(MediaStore.Video.Media.DATA))
// 获取视频的时间长短
val duration = getInt(getColumnIndex(MediaStore.Video.Media.DURATION))
// 获取视频的大小
var size = getLong(getColumnIndex(MediaStore.Video.Media.SIZE))
if (size < 0) {
//某些设备获取size<0,直接计算
size = File(path).length()
}
// 获取视频的名称
val displayName = getString(getColumnIndex(MediaStore.Video.Media.DISPLAY_NAME))
// 获取视频的修改时间
val modifyTime = getLong(getColumnIndex(MediaStore.Video.Media.DATE_MODIFIED))
//提前生成缩略图,再获取:http://stackoverflow.com/questions/27903264/how-to-get-the-video-thumbnail-path-and-not-the-bitmap
MediaStore.Video.Thumbnails.getThumbnail(
context.contentResolver,
id.toLong(),
MediaStore.Video.Thumbnails.MICRO_KIND,
null
)
val projection = arrayOf(
MediaStore.Video.Thumbnails._ID,
MediaStore.Video.Thumbnails.DATA
)
val cursor: Cursor? = context.contentResolver.query(
MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI
, projection
, MediaStore.Video.Thumbnails.VIDEO_ID + "=?"
, arrayOf(id.toString()), null
)
var thumbPath = ""
cursor?.run {
while (moveToNext()) {
thumbPath = getString(getColumnIndex(MediaStore.Video.Thumbnails.DATA))
}
close()
}
files.add(
FileBean(
thumbPath, path,
duration.toLong(),
modifyTime,
displayName,
size
)
)
}
close()
}
return files
}
/**
* 检查图片是否存在。ContentResolver查询处理的数据有可能文件路径并不存在。
*
* @param filePath
* @return
*/
private fun checkFileExists(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()
)
}
/**
* 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 ""
}
interface DataCallback {
fun onSuccess(files: ArrayList<FileBean>?)
}
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
......@@ -14,7 +14,7 @@ class SettingActivity : BaseVMActivity() {
override fun initView() {
binding.run {
title = HeaderTitle(
R.string.app_name,
getString(R.string.app_name),
View.GONE,
R.mipmap.ic_activity_arrow,
{},
......
......@@ -11,35 +11,7 @@ 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 {
fun deleteImage(imgPath: String?, context: Context): Boolean {
val resolver: ContentResolver = context.contentResolver
val cursor: Cursor = MediaStore.Images.Media.query(
resolver,
......
package com.mints.cleaner.util
import java.text.DecimalFormat
import kotlin.math.roundToLong
object FormatUtils {
//定义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 {
if (bytes <= 0) return ""
//格式化小数
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 formatDuration(duration: Long): String {
if (duration <= 0) return ""
var time: String? = ""
val minute: Long = duration / 60000
val seconds: Long = duration % 60000
val second = (seconds.toFloat() / 1000).roundToLong()
if (minute < 10) {
time += "0"
}
time += "$minute:"
if (second < 10) {
time += "0"
}
time += second
return time!!
}
}
\ No newline at end of file
......@@ -11,5 +11,4 @@ class RoundCheckBox : androidx.appcompat.widget.AppCompatCheckBox {
constructor(context: Context) : this(context, null)
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
......@@ -15,7 +16,7 @@
<include
layout="@layout/clean_header_bar"
title="title" />
app:title="@{title}" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview_album"
......
<?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.CleanHeaderTitle" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
layout="@layout/clean_header_bar"
app:title="@{title}" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview_multi"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
<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>
\ 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="match_parent"
android:background="@color/black_01">
<com.github.chrisbanes.photoview.PhotoView
android:id="@+id/pv_preview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
......@@ -20,8 +20,8 @@
<ImageView
android:id="@+id/iv_header_left_clean"
onClick="@{title.leftAction}"
icon="@{title.leftIcon}"
onClick="@{title.leftAction}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
......
......@@ -2,13 +2,12 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp">
android:padding="2dp">
<ImageView
android:id="@+id/iv_item_album"
android:layout_width="match_parent"
android:layout_height="150dp"
android:scaleType="centerCrop" />
android:layout_height="130dp" />
<com.mints.cleaner.widget.RoundCheckBox
android:id="@+id/cb_item"
......
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center_vertical">
<ImageView
android:id="@+id/iv_item_multi"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginStart="10dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/tv_item_multi_name"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_toEndOf="@id/iv_item_multi"
android:ellipsize="middle"
android:singleLine="true"
android:focusable="true"
android:marqueeRepeatLimit="marquee_forever"
android:focusableInTouchMode="true"
android:scrollHorizontally="true"
android:textColor="@color/black"
android:textSize="18sp" />
<TextView
android:id="@+id/tv_item_multi_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_item_multi_name"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_toEndOf="@id/iv_item_multi"
android:textColor="@color/gray"
android:textSize="18sp" />
<TextView
android:id="@+id/tv_item_multi_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_item_multi_name"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_toEndOf="@id/tv_item_multi_size"
android:textColor="@color/gray"
android:textSize="18sp" />
<com.mints.cleaner.widget.RoundCheckBox
android:id="@+id/cb_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true" />
</RelativeLayout>
\ No newline at end of file
......@@ -11,6 +11,8 @@
<color name="theme">#6200EE</color>
<color name="black">#000000</color>
<color name="black_01">#2A2B3D</color>
<color name="gray">#999999</color>
<color name="gray_01">#F5F5F5</color>
<color name="gray_02">#E8E8F0</color>
......
......@@ -23,6 +23,9 @@
<string name="file_clean">文件清理</string>
<string name="music_clean">音乐清理</string>
<string name="album_clean">相册清理</string>
<string name="apk_clean">安装包清理</string>
<string name="video_clean">视频清理</string>
<string name="zip_clean">压缩包清理</string>
<string name="file_clean_info">释放更多空间</string>
<string name="music_clean_info">清理不喜欢的音乐</string>
......@@ -32,6 +35,9 @@
<string name="feature_set">功能设置</string>
<string name="about_us">关于我们</string>
<string name="full_choice">全选</string>
<string name="cancel_full_choice">取消全选</string>
<string name="selector_all_image">全部图片</string>
......
......@@ -2,10 +2,15 @@
<!-- 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>p
<style name="CustomerTransparentTheme" parent="AppTheme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
<style name="DrawerArrowStyle" parent="Widget.AppCompat.DrawerArrowToggle">
......@@ -24,4 +29,5 @@
<item name="android:background">@color/gray_02</item>
</style>
</resources>
\ No newline at end of file
......@@ -4,6 +4,10 @@ import android.view.View
import androidx.databinding.BindingAdapter
@BindingAdapter("onClick", requireAll = false)
fun View.init(action: () -> Unit) {
setOnClickListener { action() }
fun View.init(action: (() -> Unit)?) {
setOnClickListener {
if (action != null) {
action()
}
}
}
\ No newline at end of file
......@@ -104,6 +104,7 @@ inline fun <reified T : Context> Context.getIntent(
is Array<*> -> putExtra(name, value)
is ArrayList<*> -> putExtra(name, value)
is Serializable -> putExtra(name, value)
is Parcelable -> putExtra(name, value)
is BooleanArray -> putExtra(name, value)
is ByteArray -> putExtra(name, value)
is ShortArray -> putExtra(name, value)
......
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