Commit ce010dc7 authored by jyx's avatar jyx

相册清理

parent 0505771a
...@@ -159,6 +159,7 @@ dependencies { ...@@ -159,6 +159,7 @@ dependencies {
implementation Deps.banner implementation Deps.banner
implementation Deps.glide implementation Deps.glide
kapt Deps.glide_compiler kapt Deps.glide_compiler
implementation Deps.photoView
implementation Deps.livedata_ktx implementation Deps.livedata_ktx
implementation Deps.viewPager2 implementation Deps.viewPager2
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mints.cleaner"> 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.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
...@@ -14,8 +15,16 @@ ...@@ -14,8 +15,16 @@
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> 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 <meta-data
android:name="android.max_aspect" android:name="android.max_aspect"
android:value="2.4" /> android:value="2.4" />
...@@ -23,11 +32,7 @@ ...@@ -23,11 +32,7 @@
<activity android:name=".ui.login.LoginActivity" /> <activity android:name=".ui.login.LoginActivity" />
<activity android:name=".ui.splash.SplashActivity" /> <activity android:name=".ui.splash.SplashActivity" />
<activity android:name=".ui.NavigationActivity"> <activity android:name=".ui.NavigationActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity> </activity>
</application> </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 ...@@ -8,9 +8,6 @@ import com.mints.cleaner.R
class CleanAdapter : BaseMultiItemQuickAdapter<CleanMultiItem, BaseViewHolder> { class CleanAdapter : BaseMultiItemQuickAdapter<CleanMultiItem, BaseViewHolder> {
private val names = arrayOf("手机加速", "微信清理", "QQ清理", "软件管理", "相册清理", "视频清理")
constructor(data: List<CleanMultiItem>) : super(data) { constructor(data: List<CleanMultiItem>) : super(data) {
addItemType(CleanMultiItem.ITEM_TOP, R.layout.item_clean_top) addItemType(CleanMultiItem.ITEM_TOP, R.layout.item_clean_top)
addItemType(CleanMultiItem.ITEM_MID, R.layout.item_clean_mid) addItemType(CleanMultiItem.ITEM_MID, R.layout.item_clean_mid)
...@@ -24,21 +21,13 @@ class CleanAdapter : BaseMultiItemQuickAdapter<CleanMultiItem, BaseViewHolder> { ...@@ -24,21 +21,13 @@ class CleanAdapter : BaseMultiItemQuickAdapter<CleanMultiItem, BaseViewHolder> {
} }
CleanMultiItem.ITEM_MID -> { 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 gridView = helper.getView<GridView>(R.id.gv_clean)
val simpleAdapter = SimpleAdapter( val simpleAdapter = SimpleAdapter(
gridView.context, gridView.context,
listitem, item?.gvDataList,
R.layout.item_gv_clean, R.layout.item_gv_clean,
arrayOf("item_gv_text"), arrayOf("item_gv_icon", "item_gv_text"),
intArrayOf(R.id.item_gv_text) intArrayOf(R.id.item_gv_img, R.id.item_gv_text)
) )
gridView.adapter = simpleAdapter gridView.adapter = simpleAdapter
gridView.setOnItemClickListener { _, _, position, _ -> gridView.setOnItemClickListener { _, _, position, _ ->
......
...@@ -5,15 +5,16 @@ import com.chad.library.adapter.base.entity.MultiItemEntity ...@@ -5,15 +5,16 @@ import com.chad.library.adapter.base.entity.MultiItemEntity
class CleanMultiItem : MultiItemEntity { class CleanMultiItem : MultiItemEntity {
private var itemType: Int = 0 private var itemType: Int = 0
private var itemIndex: Int = 0
var gvDataList: MutableList<Map<String, Any>> = ArrayList()
constructor(itemType: Int) { constructor(itemType: Int) {
this.itemType = itemType this.itemType = itemType
} }
constructor(itemType: Int, itemIndex: Int) { constructor(itemType: Int, gvDataList: MutableList<Map<String, Any>>) {
this.itemType = itemType this.itemType = itemType
this.itemIndex = itemIndex this.gvDataList = gvDataList
} }
companion object { companion object {
......
...@@ -2,12 +2,10 @@ package com.mints.cleaner.model.api.client ...@@ -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.CashException
import com.mints.cleaner.model.api.neterror.ServerException 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.cleaner.model.repository.BaseResponse
import com.mints.core.Result import com.mints.core.Result
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import java.io.IOException
import java.lang.Exception import java.lang.Exception
open class BaseRepository { 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 package com.mints.cleaner.model.bean
data class HeaderTitle(
class HeaderTitle(
// 标题内容 // 标题内容
val title: Int, var title: Int,
// 返回箭头是否显示 // 返回箭头是否显示
val backArrowVisible: Int, var leftIconVisible: Int,
// 右边图标 // 左边图标
val rightIcon: Int, var leftIcon: Int,
// 左边图标点击事件
var leftAction: () -> Unit,
// 背景颜色 // 背景颜色
val background: Int 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 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.ApiService
import com.mints.cleaner.model.api.client.BaseRepository import com.mints.cleaner.model.api.client.BaseRepository
class MainRepository(val service: ApiService) : 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.home package com.mints.cleaner.ui.home
import android.graphics.Color
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.widget.Toast import android.widget.Toast
import com.mints.cleaner.R import com.mints.cleaner.R
import com.mints.cleaner.adapter.clean.CleanAdapter import com.mints.cleaner.adapter.clean.CleanAdapter
import com.mints.cleaner.adapter.clean.CleanMultiItem
import com.mints.cleaner.databinding.FragmentCleanBinding import com.mints.cleaner.databinding.FragmentCleanBinding
import com.mints.cleaner.model.bean.HeaderTitle import com.mints.cleaner.model.bean.HeaderTitle
import com.mints.cleaner.ui.main.MainViewModel import com.mints.cleaner.ui.main.MainViewModel
...@@ -20,29 +18,21 @@ import org.koin.androidx.viewmodel.ext.android.viewModel ...@@ -20,29 +18,21 @@ import org.koin.androidx.viewmodel.ext.android.viewModel
class HomeFragment : BaseVMFragment<FragmentCleanBinding>(R.layout.fragment_clean) { class HomeFragment : BaseVMFragment<FragmentCleanBinding>(R.layout.fragment_clean) {
private val mainViewModel by viewModel<MainViewModel>() private val mainViewModel by viewModel<MainViewModel>()
private val cleanAdapter by lazy { CleanAdapter(multiItemList) } private val cleanAdapter by lazy { CleanAdapter(mainViewModel.repository.getHomeData()) }
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)
)
override fun initView() { override fun initView() {
binding.run { binding.run {
viewModel = mainViewModel viewModel = mainViewModel
adapter = cleanAdapter adapter = cleanAdapter
title = HeaderTitle( title = HeaderTitle(
R.string.app_name, R.string.app_name,
View.GONE, View.GONE,
R.mipmap.ic_activity_arrow, R.mipmap.ic_activity_arrow,
{},
R.color.theme R.color.theme
) )
} }
initRecyclerView() initRecyclerView()
...@@ -53,7 +43,7 @@ class HomeFragment : BaseVMFragment<FragmentCleanBinding>(R.layout.fragment_clea ...@@ -53,7 +43,7 @@ class HomeFragment : BaseVMFragment<FragmentCleanBinding>(R.layout.fragment_clea
addFooterView(LayoutInflater.from(activity).inflate(R.layout.home_footer, null)) addFooterView(LayoutInflater.from(activity).inflate(R.layout.home_footer, null))
// 一键清理 // 一键清理
setOnItemChildClickListener { adapter, view, position -> setOnItemChildClickListener { _, _, _ ->
// 一键清理 // 一键清理
activity?.let { toast(it, "一键清理", Toast.LENGTH_SHORT) } 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.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 @@ ...@@ -8,44 +8,40 @@
type="com.mints.cleaner.model.bean.HeaderTitle" /> type="com.mints.cleaner.model.bean.HeaderTitle" />
</data> </data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@{title.background}"
android:paddingTop="30dp">
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="80dp" android:layout_height="50dp">
android:background="@{title.background}">
<ImageView <ImageView
android:id="@+id/iv_header_left" android:id="@+id/iv_header_left"
onClick="@{title.leftAction}"
icon="@{title.leftIcon}"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="20dp" android:layout_centerVertical="true"
android:layout_marginTop="40dp" android:layout_marginStart="10dp"
android:scaleType="center" android:scaleType="center"
android:src="@mipmap/ic_activity_arrow" android:visibility="@{title.leftIconVisible}" />
android:visibility="@{title.backArrowVisible}" />
<TextView <TextView
android:id="@+id/tv_activity_title" android:id="@+id/tv_activity_title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="20dp" android:layout_centerVertical="true"
android:layout_marginTop="40dp" android:layout_marginStart="10dp"
android:layout_toEndOf="@id/iv_header_left" android:layout_toEndOf="@id/iv_header_left"
android:text="@{title.title}" android:text="@{title.title}"
android:textColor="@color/product_net_text" android:textColor="@color/product_net_text"
android:textSize="18sp" /> 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> </RelativeLayout>
</FrameLayout>
</layout> </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 @@ ...@@ -14,6 +14,7 @@
<color name="gray">#999999</color> <color name="gray">#999999</color>
<color name="gray_01">#F5F5F5</color> <color name="gray_01">#F5F5F5</color>
<color name="gray_02">#E8E8F0</color> <color name="gray_02">#E8E8F0</color>
<color name="green">#00FF00</color>
<color name="status_bg">#002444</color> <color name="status_bg">#002444</color>
<color name="product_net_text">#121B32</color> <color name="product_net_text">#121B32</color>
......
...@@ -28,4 +28,11 @@ ...@@ -28,4 +28,11 @@
<string name="music_clean_info">清理不喜欢的音乐</string> <string name="music_clean_info">清理不喜欢的音乐</string>
<string name="zip_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> </resources>
\ No newline at end of file
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar"> <style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- Customize your theme here. --> <!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item> <!-- <item name="colorPrimary">@color/colorPrimary</item>-->
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <!-- <item name="colorPrimaryDark">@color/colorPrimaryDark</item>-->
<item name="colorAccent">@color/colorAccent</item> <!-- <item name="colorAccent">@color/colorAccent</item>-->
<item name="drawerArrowStyle">@style/DrawerArrowStyle</item> <item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
</style> </style>
......
...@@ -27,6 +27,7 @@ object Versions { ...@@ -27,6 +27,7 @@ object Versions {
const val banner = "1.4.10" const val banner = "1.4.10"
const val glide = "4.11.0" const val glide = "4.11.0"
const val glide_compiler = "4.11.0" const val glide_compiler = "4.11.0"
const val photoView = "2.0.0"
const val cardView = "1.0.0" const val cardView = "1.0.0"
const val verticalTabLayout = "1.2.5" const val verticalTabLayout = "1.2.5"
const val flowLayout = "1.1.2" const val flowLayout = "1.1.2"
...@@ -75,6 +76,7 @@ object Deps { ...@@ -75,6 +76,7 @@ object Deps {
const val orhanobut_logger = "com.orhanobut:logger:${Versions.orhanobut_logger}" const val orhanobut_logger = "com.orhanobut:logger:${Versions.orhanobut_logger}"
// third // third
const val photoView = "com.github.chrisbanes:PhotoView:${Versions.photoView}"
const val circleimageview = "de.hdodenhof:circleimageview:${Versions.circleImageview}" const val circleimageview = "de.hdodenhof:circleimageview:${Versions.circleImageview}"
const val leakCanary = "com.squareup.leakcanary:leakcanary-android:${Versions.leakcanary}" const val leakCanary = "com.squareup.leakcanary:leakcanary-android:${Versions.leakcanary}"
const val baseRecyclerViewAdapterHelper = "com.github.CymChad:BaseRecyclerViewAdapterHelper:${Versions.baseRecyclerViewAdapterHelper}" 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