Commit a34aa488 authored by wanglei's avatar wanglei Committed by wanglei

完善代码

parent 484a940f
......@@ -52,4 +52,5 @@ dependencies {
androidTestImplementation(libs.androidx.espresso.core)
implementation(libs.androidx.navigation.fragment.ktx)
implementation(libs.androidx.navigation.ui.ktx)
implementation(libs.glide)
}
\ No newline at end of file
......@@ -22,22 +22,29 @@
tools:targetApi="31">
<activity
android:name=".kokoInternalstorage.KoInternalkoActivity"
android:exported="false" />
android:exported="false"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".kokodup.KoDupFilekoActivity"
android:exported="false" />
android:exported="false"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".kokolistfile.KoListFilekoActivity"
android:exported="false"
android:screenOrientation="portrait"
tools:ignore="LockedOrientationActivity" />
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".gridfile.KoGridFilekoActivity"
android:exported="false" />
android:name=".kokogridfile.KoGridFilekoActivity"
android:exported="false"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".KokoLaunchActivity"
android:exported="true"
android:screenOrientation="portrait">
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
......@@ -47,7 +54,8 @@
<activity
android:name=".MainActivity"
android:exported="true"
android:screenOrientation="portrait" />
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
</application>
</manifest>
\ No newline at end of file
package com.zxhy.fastfilemanagerpro
import android.content.Context
import android.os.Environment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.koFileDatako
import com.zxhy.fastfilemanagerpro.kokotools.HelperTraverse
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import java.io.File
import java.util.Stack
import kotlin.reflect.KFunction1
abstract class CommonViewModel : ViewModel() {
/**
* 只删除文件列表
*/
fun deleteFiles(files: List<File>, finishAction: () -> Unit) =
viewModelScope.launch(Dispatchers.IO) {
runCatching {
files.forEach {
if (it.exists()) {
it.delete()
}
}
}
finishAction.invoke()
}
fun deleteFileOrDir(files: List<File>, finishAction: () -> Unit) =
viewModelScope.launch(Dispatchers.IO) {
runCatching {
files.forEach {
if (it.exists()) {
if (it.isFile) it.delete() else deleteDirectory(it)
}
}
}
finishAction.invoke()
}
/**
*删除文件夹
*/
fun deleteDirectory(dir: File): Boolean {
val stackFiles = Stack<File>()
stackFiles.push(dir)
while (stackFiles.size > 0) {
val currentFile = stackFiles.peek()
val subFiles = currentFile.listFiles()
if (subFiles != null) {
for (i in subFiles.indices) {
if (subFiles[i].isFile) {
if (!subFiles[i].delete()) {
return false
}
} else {
stackFiles.push(subFiles[i])
}
}
}
if (currentFile === stackFiles.peek()) {
if (!currentFile.delete()) {
return false
}
stackFiles.pop()
}
}
return true
}
/**
* 复制文件夹
* @param source 原文件夹
* @param target 目标文件夹
*/
fun copyDirectory(source: File, target: File) {
try {
if (source.isDirectory) {
if (!target.exists()) target.mkdir()
source.list()?.map { sub ->
copyDirectory(File(source, sub), File(target, sub))
}
} else {
source.copyTo(target, overwrite = true)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
fun loadFile(
context: Context,
filter: (file: File) -> Boolean,
onDo: (list: List<KoFileDatako>) -> Unit,
onFinish: (list: List<KoFileDatako>) -> Unit
) {
viewModelScope.launch(Dispatchers.IO) {
val root = Environment.getExternalStorageDirectory()
val resultList = arrayListOf<KoFileDatako>()
var firstSend = false
HelperTraverse.linkedLisTraverseFolder(root) { file ->
if (filter(file)) {
resultList.add(file.koFileDatako(context))
if (resultList.size == 20 && !firstSend) {
onDo.invoke(resultList)
resultList.clear()
firstSend = true
}
}
}
onFinish.invoke(resultList)
}
}
fun loadAllFile(
context: Context,
filter: (file: File) -> Boolean,
onFinish: (list: List<KoFileDatako>) -> Unit
) {
viewModelScope.launch(Dispatchers.IO) {
val root = Environment.getExternalStorageDirectory()
val resultList = arrayListOf<KoFileDatako>()
HelperTraverse.linkedLisTraverseFolder(root) { file ->
if (filter(file)) {
resultList.add(file.koFileDatako(context))
}
}
onFinish.invoke(resultList)
}
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro
import android.app.Application
import com.bumptech.glide.annotation.GlideModule
@GlideModule
class GlideApp : Application() {
}
\ No newline at end of file
......@@ -5,6 +5,7 @@ import android.view.MenuItem
import android.view.View
import android.widget.AdapterView
import androidx.activity.enableEdgeToEdge
import androidx.annotation.ColorRes
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
......@@ -13,12 +14,17 @@ import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import com.google.android.material.navigation.NavigationBarView
import com.zxhy.fastfilemanagerpro.databinding.ActivityMainBinding
import com.zxhy.fastfilemanagerpro.kokotools.ActivityLauncher
import com.zxhy.fastfilemanagerpro.kokotools.permission.PermissionCheck.storePermissionCheck
import com.zxhy.fastfilemanagerpro.kokotools.permission.StorePermissionEx.requestStoreFollow
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var activityLauncher: ActivityLauncher
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
activityLauncher = ActivityLauncher(this)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
......@@ -77,5 +83,18 @@ class MainActivity : AppCompatActivity() {
return true
}
})
if (!storePermissionCheck()) {
requestStoreFollow(activityLauncher,
disAgreeAction = {
},
agreeAction = {
})
}
}
fun setSystemBarColor(@ColorRes colorRes: Int) {
// color_b3000000 权限窗口颜色
window.statusBarColor = ContextCompat.getColor(this, colorRes)
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.gridfile
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.zxhy.fastfilemanagerpro.R
import com.zxhy.fastfilemanagerpro.databinding.ActivityKoGridFilekoBinding
class KoGridFilekoActivity : AppCompatActivity() {
private lateinit var binding: ActivityKoGridFilekoBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
binding = ActivityKoGridFilekoBinding.inflate(layoutInflater)
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
}
companion object {
const val IMAGE_FILE = "Image file"
const val VIDEO_FILE = "Video file"
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokoInternalstorage
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
import android.os.Environment
import android.view.KeyEvent
import android.view.View
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope
import com.zxhy.fastfilemanagerpro.R
import com.zxhy.fastfilemanagerpro.databinding.ActivityKoInternalkoBinding
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.koFileDatako
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.toFile
import com.zxhy.fastfilemanagerpro.kokodialog.FileNameDialog.showFileNameDialog
import com.zxhy.fastfilemanagerpro.kokotools.ActivityLauncher
import com.zxhy.fastfilemanagerpro.kokotools.permission.PermissionCheck.storePermissionCheck
import com.zxhy.fastfilemanagerpro.kokotools.permission.StorePermissionEx.requestStoreFollow
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.io.File
class KoInternalkoActivity : AppCompatActivity() {
private lateinit var binding: ActivityKoInternalkoBinding
private val viewModel: KoInternalkoViewModel by viewModels()
private lateinit var adapter: KoInternalkoAdapter
private lateinit var activityLauncher: ActivityLauncher
private lateinit var context: Context
private var currentMode = BROWSER_MODE
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_ko_internalko)
context = this
activityLauncher = ActivityLauncher(this)
binding = ActivityKoInternalkoBinding.inflate(layoutInflater)
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
adapter = KoInternalkoAdapter(context,
allSelect = {
binding.ivAllSelector.isSelected = it
enableOperationItem()
},
pageCount = {
binding.tvItems.text = "total:$it items"
}
)
binding.rv.adapter = adapter
binding.ivAllSelector.setOnClickListener {
it.isSelected = !it.isSelected
adapter.toggleSelect(it.isSelected)
enableOperationItem()
}
if (storePermissionCheck()) {
showPermissionSet(false)
loadInternalStorage()
} else {
showPermissionSet(true)
}
}
@SuppressLint("SetTextI18n")
private fun loadInternalStorage() {
val root = Environment.getExternalStorageDirectory()
val data = root.listFiles()?.map { it.koFileDatako(context) } ?: listOf()
adapter.setData(data)
browserMode()
binding.tvItems.text = "total:${adapter.itemCount} items"
}
private fun browserMode() {
currentMode = BROWSER_MODE
adapter.setCanPage(true)
binding.llEditSelect.visibility = View.VISIBLE
binding.tvEdit.visibility = View.VISIBLE
binding.ivAllSelector.visibility = View.GONE
binding.tvAll.visibility = View.GONE
binding.clOperation.visibility = View.GONE
binding.tvEdit.setOnClickListener {
operationMode()
}
adapter.showSelectMode(false)
}
private fun operationMode() {
currentMode = OPERATION_MODE
adapter.setCanPage(false)
binding.llEditSelect.visibility = View.VISIBLE
binding.tvEdit.visibility = View.GONE
binding.ivAllSelector.visibility = View.VISIBLE
binding.ivAllSelector.isSelected = false
binding.tvAll.visibility = View.VISIBLE
binding.clOperation.visibility = View.VISIBLE
binding.llOperation.visibility = View.VISIBLE
binding.clOperationConfirm.visibility = View.GONE
adapter.showSelectMode(true)
enableOperationItem()
binding.llShare.setOnClickListener {
}
binding.llRename.setOnClickListener {
val list = adapter.getSelectData()
if (list.isNotEmpty()) {
val selectFile = list.first().toFile()
showFileNameDialog(selectFile) { name ->
viewModel.renameFile(selectFile, name) {
lifecycleScope.launch(Dispatchers.Main) {
showOperationResult("Rename successful!")
adapter.clearCannotDir()
adapter.notifyCurrentDir()
browserMode()
}
}
}
}
}
binding.llDelete.setOnClickListener {
val list = adapter.getSelectData().map { it.toFile() }
viewModel.deleteFileOrDir(list) {
lifecycleScope.launch(Dispatchers.Main) {
showOperationResult()
adapter.notifyCurrentDir()
browserMode()
}
}
}
binding.llCopy.setOnClickListener {
val data = adapter.getSelectData().map { it.toFile() }
operationConfirmMode(OPERATION_COPY, data)
}
binding.llMove.setOnClickListener {
val data = adapter.getSelectData().map { it.toFile() }
operationConfirmMode(OPERATION_MOVE, data)
}
}
@SuppressLint("SetTextI18n")
private fun operationConfirmMode(operation: String, data: List<File>) {
currentMode = OPERATION_CONFIRM_MODE
binding.llEditSelect.visibility = View.GONE
adapter.setCanPage(true)
binding.clOperation.visibility = View.VISIBLE
binding.llOperation.visibility = View.GONE
binding.clOperationConfirm.visibility = View.VISIBLE
adapter.showSelectMode(false)
adapter.setCannotDir(data.filter { it.isDirectory })
binding.tvConfirmItems.text = "${data.size} items"
when (operation) {
OPERATION_COPY -> {
binding.tvConfirm.text = "Copy"
binding.tvConfirm.setOnClickListener {
val destDir = adapter.getCurrentDir()
viewModel.copyFiles(data, destDir) {
lifecycleScope.launch(Dispatchers.Main) {
showOperationResult("Copy successful!")
adapter.clearCannotDir()
adapter.notifyCurrentDir()
browserMode()
}
}
}
}
OPERATION_MOVE -> {
binding.tvConfirm.text = "Motion"
binding.tvConfirm.setOnClickListener {
val destDir = adapter.getCurrentDir()
viewModel.moveFiles(data, destDir) {
lifecycleScope.launch(Dispatchers.Main) {
showOperationResult("Move successful!")
adapter.clearCannotDir()
adapter.notifyCurrentDir()
browserMode()
}
}
}
}
}
binding.tvCancel.setOnClickListener {
browserMode()
}
}
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
if (event.keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {
when (currentMode) {
BROWSER_MODE -> {
if (adapter.pageBefore()) super.dispatchKeyEvent(event) else return false
}
OPERATION_MODE -> {
browserMode()
return false
}
OPERATION_CONFIRM_MODE -> {
if (adapter.pageBefore()) super.dispatchKeyEvent(event) else return false
}
}
}
return super.dispatchKeyEvent(event)
}
//region 公共代码
private fun showPermissionSet(show: Boolean) {
if (show) {
binding.clContent.visibility = View.GONE
binding.clPermissionSet.visibility = View.VISIBLE
window.statusBarColor = ContextCompat.getColor(context, R.color.color_b3000000)
binding.tvSet.setOnClickListener {
requestStoreFollow(activityLauncher, disAgreeAction = {
showPermissionSet(true)
}, agreeAction = {
showPermissionSet(false)
loadInternalStorage()
})
}
} else {
binding.clContent.visibility = View.VISIBLE
binding.clPermissionSet.visibility = View.GONE
window.statusBarColor = ContextCompat.getColor(context, R.color.white)
}
}
private fun showOperationResult(tips: String = "Delete successful!") =
lifecycleScope.launch(Dispatchers.Main) {
binding.tvOperationResult.text = tips
binding.llResult.visibility = View.VISIBLE
delay(500)
binding.llResult.visibility = View.GONE
}
private fun showEmptyList() {
if (adapter.itemCount == 0) {
binding.clEmpty.visibility = View.VISIBLE
binding.clShowContent.visibility = View.GONE
binding.llEditSelect.visibility = View.GONE
} else {
binding.clEmpty.visibility = View.GONE
binding.clShowContent.visibility = View.VISIBLE
binding.llEditSelect.visibility = View.VISIBLE
}
}
private fun enableOperationItem() {
val selectData = adapter.getSelectData()
if (selectData.isEmpty()) {
binding.llShare.isEnabled = false
binding.llDelete.isEnabled = false
binding.llCopy.isEnabled = false
binding.llMove.isEnabled = false
binding.llRename.isEnabled = false
} else if (selectData.size == 1) {
binding.llShare.isEnabled = true
binding.llDelete.isEnabled = true
binding.llCopy.isEnabled = true
binding.llMove.isEnabled = true
binding.llRename.isEnabled = true
} else {
binding.llShare.isEnabled = true
binding.llDelete.isEnabled = true
binding.llCopy.isEnabled = true
binding.llMove.isEnabled = true
binding.llRename.isEnabled = false
}
}
//endregion
companion object {
const val OPERATION_COPY = "operation_copy"
const val OPERATION_MOVE = "operation_move"
const val BROWSER_MODE = "browser_mode"
const val OPERATION_MODE = "operation_mode"
const val OPERATION_CONFIRM_MODE = "operation_confirm_mode"
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokoInternalstorage
import android.annotation.SuppressLint
import android.content.Context
import android.os.Environment
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.zxhy.fastfilemanagerpro.R
import com.zxhy.fastfilemanagerpro.databinding.ItemKokoListFileBinding
import com.zxhy.fastfilemanagerpro.kokoadapter.CommonAdapter
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.koFileDatako
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.loadImageIcon
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.toFile
import com.zxhy.fastfilemanagerpro.kokotools.XmlEx.inflate
import java.io.File
class KoInternalkoAdapter(
private val context: Context,
private val allSelect: (flag: Boolean) -> Unit,
private val pageCount: ((count: Int) -> Unit)? = null
) : CommonAdapter<KoInternalkoAdapter.KoInternalkoViewHolder>() {
private var selectMode = false
private var currentDir = Environment.getExternalStorageDirectory()
private var cannotFiles = arrayListOf<String>()
private var canPage = true
fun setCanPage(canPage: Boolean) {
this.canPage = canPage
}
fun getCurrentDir(): File {
return currentDir
}
@SuppressLint("NotifyDataSetChanged")
fun showSelectMode(show: Boolean) {
selectMode = show
notifyDataSetChanged()
}
class KoInternalkoViewHolder(view: View) : ViewHolder(view) {
val binding = ItemKokoListFileBinding.bind(view)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): KoInternalkoViewHolder {
return KoInternalkoViewHolder(R.layout.item_koko_list_file.inflate(parent))
}
override fun onBindViewHolder(holder: KoInternalkoViewHolder, position: Int) {
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(
holder: KoInternalkoViewHolder,
position: Int,
payloads: MutableList<Any>
) {
val context = holder.binding.root.context
val data = fileList[position]
if (payloads.isEmpty()) {
holder.binding.apply {
data.loadImageIcon(context, ivIcon)
if (cannotFiles.contains(data.toFile().absolutePath)) {
root.setBackgroundColor(ContextCompat.getColor(context, R.color.color_606060))
root.setOnClickListener { }
} else {
root.setBackgroundColor(ContextCompat.getColor(context, R.color.color_ffffff))
root.setOnClickListener {
if (canPage) {
pageNext(context, data)
}
}
}
tvName.text = data.name
tvInfo.text = "${data.timeE} ${data.sizeF}"
if (selectMode) {
ivSelector.visibility = View.VISIBLE
ivSelector.isSelected = data.isSelect
ivSelector.setOnClickListener {
data.isSelect = !data.isSelect
ivSelector.isSelected = data.isSelect
notifyItemChanged(position, "局部刷洗")
allSelect.invoke(fileList.all { it.isSelect })
}
} else {
ivSelector.visibility = View.GONE
}
}
} else {
holder.binding.apply {
ivSelector.isSelected = data.isSelect
}
super.onBindViewHolder(holder, position, payloads)
}
}
private fun pageNext(context: Context, data: KoFileDatako) {
val list = data.toFile().listFiles()?.map { it.koFileDatako(context) } ?: listOf()
setData(list)
currentDir = data.toFile()
pageCount?.invoke(list.size)
}
/**
* @return 是否是根目录
*/
fun pageBefore(): Boolean {
return if (currentDir.absolutePath == Environment.getExternalStorageDirectory().absolutePath) {
true
} else {
val parentDir = currentDir.parentFile ?: File("")
if (parentDir.exists()) {
val data = parentDir.listFiles()?.map { it.koFileDatako(context) } ?: listOf()
setData(data)
currentDir = parentDir
pageCount?.invoke(data.size)
}
false
}
}
fun notifyCurrentDir() {
val data = currentDir.listFiles()?.map { it.koFileDatako(context) } ?: listOf()
setData(data)
pageCount?.invoke(itemCount)
}
@SuppressLint("NotifyDataSetChanged")
fun setCannotDir(dirs: List<File>) {
cannotFiles.addAll(dirs.map { it.absolutePath })
notifyDataSetChanged()
}
fun clearCannotDir() {
cannotFiles.clear()
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokoInternalstorage
import android.content.IntentSender.OnFinished
import androidx.lifecycle.viewModelScope
import com.zxhy.fastfilemanagerpro.CommonViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
class KoInternalkoViewModel : CommonViewModel() {
fun renameFile(selectFile: File, newName: String, result: () -> Unit) {
runCatching {
val flag = selectFile.renameTo(File(selectFile.parentFile, newName))
if (flag) {
result.invoke()
}
}
}
fun copyFiles(files: List<File>, destDir: File, result: () -> Unit) =
viewModelScope.launch(Dispatchers.IO) {
runCatching {
files.map {
if (it.isFile) {
it.copyTo(File(destDir, it.name), overwrite = true)
} else {
copyDirectory(it, File(destDir, it.name))
}
}
}
result.invoke()
}
fun moveFiles(files: List<File>, destDir: File, result: () -> Unit) =
viewModelScope.launch(Dispatchers.IO) {
runCatching {
files.map {
if (it.isFile) {
it.copyTo(File(destDir, it.name), overwrite = true)
it.delete()
} else {
copyDirectory(it, File(destDir, it.name))
deleteDirectory(it)
}
}
}
result.invoke()
}
}
\ No newline at end of file
......@@ -3,13 +3,13 @@ package com.zxhy.fastfilemanagerpro.kokoadapter
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako
interface AdapterCommonDataFunction {
interface AdapterCommonDataFunction<T> {
abstract fun setData(data: List<KoFileDatako>)
abstract fun addData(data: List<KoFileDatako>)
abstract fun setData(data: List<T>)
abstract fun addData(data: List<T>)
abstract fun clearData()
abstract fun removeData(data: List<KoFileDatako>)
abstract fun getSelectData(): List<KoFileDatako>
abstract fun removeData(data: List<T>)
abstract fun getSelectData(): List<T>
abstract fun toggleSelect(select: Boolean)
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokoadapter
import android.annotation.SuppressLint
import android.util.Log
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako
abstract class CommonAdapter<T : ViewHolder?>() : RecyclerView.Adapter<T>(),
AdapterCommonDataFunction {
AdapterCommonDataFunction<KoFileDatako> {
protected val fileList = arrayListOf<KoFileDatako>()
private var firstRefresh = true
......@@ -53,9 +54,8 @@ abstract class CommonAdapter<T : ViewHolder?>() : RecyclerView.Adapter<T>(),
@SuppressLint("NotifyDataSetChanged")
override fun toggleSelect(select: Boolean) {
fileList.forEach {
fileBean ->
fileBean.isSelect=select
fileList.forEach { fileBean ->
fileBean.isSelect = select
}
notifyDataSetChanged()
}
......
package com.zxhy.fastfilemanagerpro.kokodata
import android.content.Context
import android.net.Uri
import android.text.format.Formatter
import android.widget.ImageView
import com.zxhy.fastfilemanagerpro.R
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.toFile
import com.zxhy.fastfilemanagerpro.kokotools.GlideHelper.loadImageView
import java.io.File
import java.text.SimpleDateFormat
import java.util.Locale
data class KoFileDatako(
var name: String,
var path: String,
var name: String = "",
var path: String = "",
var uri: Uri = Uri.EMPTY,
val timeE: String = "",
var isSelect: Boolean = false,
val sizeF: String = ""
) {
companion object {
fun KoFileDatako.loadImageIcon(context: Context, imageView: ImageView) {
when {
isImage() or isVideo() -> imageView.loadImageView(context, toFile())
isAudio() -> imageView.setImageResource(R.mipmap.zd_8871110)
isLog() -> imageView.setImageResource(R.mipmap.zd_001123)
isZip() -> imageView.setImageResource(R.mipmap.eqwe_878979)
isApk() -> imageView.setImageResource(R.mipmap.eqwe_88599)
isDocuments() -> imageView.setImageResource(R.mipmap.qwe_889989)
toFile().isDirectory -> imageView.setImageResource(R.mipmap.dd_89896330)
else -> imageView.setImageResource(R.mipmap.qwe_889989111)
}
}
fun KoFileDatako.isImage(): Boolean {
return name.contains(".jpg") or name.contains(".png") or name.contains(".gif")
}
fun KoFileDatako.isAudio(): Boolean {
return name.contains(".mp3") or
name.contains(".aac") or
name.contains(".ogg") or
name.contains(".aac")
}
fun KoFileDatako.isLog(): Boolean {
return name.contains("log") or name.contains("Log")
}
fun KoFileDatako.isZip(): Boolean {
return name.contains(".zip") or name.contains(".7z")
}
fun KoFileDatako.isApk(): Boolean {
return name.contains(".zip") or name.contains(".7z")
}
fun KoFileDatako.isDocuments(): Boolean {
return name.contains(".doc") or
name.contains(".docx") or
name.contains(".ppt") or
name.contains(".pptx") or
name.contains(".xls") or
name.contains(".xlsx") or
name.contains(".txt") or
name.contains(".pdf")
}
fun KoFileDatako.isVideo(): Boolean {
return name.contains(".mp4") or
name.contains(".avi") or
name.contains(".flv") or
name.contains(".rmvb") or
name.contains(".mkv")
}
fun KoFileDatako.toFile(): File {
return File(path)
}
......
package com.zxhy.fastfilemanagerpro.kokodialog
import android.app.Dialog
import android.content.Context
import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog
import com.zxhy.fastfilemanagerpro.R
import com.zxhy.fastfilemanagerpro.databinding.DialogKokoFileNameBinding
import java.io.File
object FileNameDialog {
fun Context.showFileNameDialog(
file: File,
sureAction: (name: String) -> Unit
): Dialog {
val binding = DialogKokoFileNameBinding.inflate(LayoutInflater.from(this))
val dialog = AlertDialog.Builder(this).setView(binding.root).create()
dialog.show()
dialog.setCanceledOnTouchOutside(false)
//修改dialog的尺寸
val lp = dialog.window?.attributes
lp?.width = this.resources.getDimensionPixelOffset(R.dimen.dp_260)
lp?.height = this.resources.getDimensionPixelOffset(R.dimen.dp_190)
dialog.window?.attributes = lp
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
binding.apply {
edit.setText(file.name.toString())
tvSure.setOnClickListener {
runCatching {
if (!edit.text.isNullOrEmpty()) {
dialog.dismiss()
sureAction.invoke(edit.text.toString())
}
}
}
ivDelete.setOnClickListener {
dialog.dismiss()
}
}
return dialog
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokodialog
import android.app.Dialog
import android.content.Context
import android.view.LayoutInflater
import android.view.animation.Animation
import android.view.animation.LinearInterpolator
import android.view.animation.RotateAnimation
import androidx.appcompat.app.AlertDialog
import com.zxhy.fastfilemanagerpro.R
import com.zxhy.fastfilemanagerpro.databinding.DialogKokoLoadingBinding
object LoadingDialog {
fun Context.showLoadingDialog(): Dialog {
val binding = DialogKokoLoadingBinding.inflate(LayoutInflater.from(this))
val dialog = AlertDialog.Builder(this).setView(binding.root).create()
dialog.show()
dialog.setCanceledOnTouchOutside(false)
//修改dialog的尺寸
val lp = dialog.window?.attributes
lp?.width = this.resources.getDimensionPixelOffset(R.dimen.dp_260)
lp?.height = this.resources.getDimensionPixelOffset(R.dimen.dp_190)
dialog.window?.attributes = lp
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
// 添加旋转动画
val rotateAnimation = RotateAnimation(
0f, 360f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
)
rotateAnimation.duration = 1500
rotateAnimation.interpolator = LinearInterpolator()
rotateAnimation.repeatCount = Animation.INFINITE
binding.ivLoading.startAnimation(rotateAnimation)
return dialog
}
}
......@@ -4,6 +4,7 @@ import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako
class KoDupFileDatako(
val md5: String,
val dups: List<KoFileDatako>
val dups: ArrayList<KoFileDatako>,
var isSelect: Boolean = false,
) {
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokodup
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.view.View
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope
import com.zxhy.fastfilemanagerpro.R
import com.zxhy.fastfilemanagerpro.databinding.ActivityKoDupFilekoBinding
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.toFile
import com.zxhy.fastfilemanagerpro.kokodialog.LoadingDialog.showLoadingDialog
import com.zxhy.fastfilemanagerpro.kokotools.ActivityLauncher
import com.zxhy.fastfilemanagerpro.kokotools.permission.PermissionCheck.storePermissionCheck
import com.zxhy.fastfilemanagerpro.kokotools.permission.StorePermissionEx.requestStoreFollow
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class KoDupFilekoActivity : AppCompatActivity() {
private lateinit var binding: ActivityKoDupFilekoBinding
private val viewModel: KoDupFilekoViewModel by viewModels()
private lateinit var context: Context
private lateinit var adapter: KoDupFilekoAdapter
private lateinit var activityLauncher: ActivityLauncher
private var tittle: String = ""
private var dialog: Dialog? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
activityLauncher = ActivityLauncher(this)
context = this
binding = ActivityKoDupFilekoBinding.inflate(layoutInflater)
setContentView(binding.root)
......@@ -27,27 +44,122 @@ class KoDupFilekoActivity : AppCompatActivity() {
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
adapter = KoDupFilekoAdapter {
binding.ivAllSelector.isSelected = it
enableDelete()
}
binding.llAll.setOnClickListener {
it.isSelected = !it.isSelected
adapter.toggleSelect(it.isSelected)
enableDelete()
}
binding.rv.adapter = adapter
tittle = intent.extras?.getString("Tittle") ?: ""
binding.tvTittle.text = tittle
if (storePermissionCheck()) {
showPermissionSet(false)
loadListFile()
} else {
showPermissionSet(true)
}
}
private fun loadListFile() {
dialog = showLoadingDialog()
when (tittle) {
DUP_IMAGE -> viewModel.loadDupImage(context, ::onFinishList)
DUP_FILE -> viewModel.loadDupFile(context, ::onFinishList)
}
}
@SuppressLint("SetTextI18n")
private fun onFinishList(list: List<KoDupFileDatako>) =
lifecycleScope.launch(Dispatchers.Main) {
adapter.setData(list)
showEmptyList()
enableDelete()
binding.tvItems.text = "total:${adapter.itemCount} items"
dialog?.dismiss()
}
fun enableDelete(enable: Boolean) {
binding.tvDelete.isEnabled = enable
//region 公共ui逻辑
private fun showEmptyList() {
if (adapter.itemCount == 0) {
binding.clEmpty.visibility = View.VISIBLE
binding.clShowContent.visibility = View.GONE
binding.llAll.visibility = View.GONE
} else {
binding.clEmpty.visibility = View.GONE
binding.clShowContent.visibility = View.VISIBLE
binding.llAll.visibility = View.VISIBLE
}
}
if (enable) {
private fun enableDelete() {
val selectSubData = adapter.getSelectSubData()
if (selectSubData.isEmpty()) {
binding.tvDelete.isEnabled = false
binding.tvDelete.background =
ContextCompat.getDrawable(context, R.drawable.bg_fff4f4f4_corners)
binding.tvDelete.setTextColor(ContextCompat.getColor(context, R.color.color_999999))
} else {
binding.tvDelete.isEnabled = true
binding.tvDelete.background =
ContextCompat.getDrawable(context, R.drawable.bg_ffff6767_corners)
binding.tvDelete.setTextColor(ContextCompat.getColor(context, R.color.white))
binding.tvDelete.setOnClickListener {
deleteFiles(selectSubData)
}
}
}
fun showOperationResult() = lifecycleScope.launch(Dispatchers.Main) {
binding.llResult.visibility = View.VISIBLE
delay(500)
binding.llResult.visibility = View.GONE
}
fun showPermissionSet(show: Boolean) {
if (show) {
binding.clContent.visibility = View.GONE
binding.clPermissionSet.visibility = View.VISIBLE
window.statusBarColor = ContextCompat.getColor(context, R.color.color_b3000000)
binding.tvSet.setOnClickListener {
requestStoreFollow(activityLauncher, disAgreeAction = {
showPermissionSet(true)
}, agreeAction = {
showPermissionSet(false)
loadListFile()
})
}
} else {
binding.tvDelete.background =
ContextCompat.getDrawable(context, R.drawable.bg_fff4f4f4_corners)
binding.tvDelete.setTextColor(ContextCompat.getColor(context, R.color.color_999999))
binding.clContent.visibility = View.VISIBLE
binding.clPermissionSet.visibility = View.GONE
window.statusBarColor = ContextCompat.getColor(context, R.color.white)
}
}
private fun deleteFiles(selectSubData: List<KoFileDatako>) {
val files = selectSubData.map { it.toFile() }
viewModel.deleteFiles(files) {
lifecycleScope.launch(Dispatchers.Main) {
showOperationResult()
adapter.removeSubData(selectSubData)
showEmptyList()
enableDelete()
}
}
}
//endregion
companion object {
const val DUP_IMAGE = "Scan for duplicate pictures"
const val DUP_FILE = "Scan for duplicate files"
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokodup
import android.annotation.SuppressLint
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
......@@ -7,10 +8,19 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.zxhy.fastfilemanagerpro.R
import com.zxhy.fastfilemanagerpro.databinding.ItemKokoDupFileBinding
import com.zxhy.fastfilemanagerpro.databinding.ItemKokoDupImageBinding
import com.zxhy.fastfilemanagerpro.kokoadapter.AdapterCommonDataFunction
import com.zxhy.fastfilemanagerpro.kokoadapter.CommonAdapter
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.loadImageIcon
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.toFile
import com.zxhy.fastfilemanagerpro.kokotools.GlideHelper.loadImageView
import com.zxhy.fastfilemanagerpro.kokotools.XmlEx.inflate
class KoDupFilekoAdapter : RecyclerView.Adapter<KoDupFilekoAdapter.KoDupFilekoViewHolder>() {
@SuppressLint("NotifyDataSetChanged")
class KoDupFilekoAdapter(
private val allSelect: (flag: Boolean) -> Unit
) : RecyclerView.Adapter<KoDupFilekoAdapter.KoDupFilekoViewHolder>(),
AdapterCommonDataFunction<KoDupFileDatako> {
private var dupFileList = arrayListOf<KoDupFileDatako>()
......@@ -29,20 +39,103 @@ class KoDupFilekoAdapter : RecyclerView.Adapter<KoDupFilekoAdapter.KoDupFilekoVi
override fun onBindViewHolder(holder: KoDupFilekoViewHolder, position: Int) {
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(
holder: KoDupFilekoViewHolder,
position: Int,
payloads: MutableList<Any>
) {
val context = holder.binding.root.context
val data = dupFileList[position]
if (payloads.isEmpty()) {
holder.binding.apply {
val adapter = DupImageAdapter {
data.isSelect = it
notifyItemChanged(position, "局部刷洗")
allSelect.invoke(dupFileList.all { it.isSelect })
}
rv.adapter = adapter
adapter.setData(data.dups)
ivSelector.isSelected = data.isSelect
ivSelector.setOnClickListener {
data.isSelect = !data.isSelect
ivSelector.isSelected = data.isSelect
notifyItemChanged(position, "局部刷洗")
adapter.toggleSelect(data.isSelect)
allSelect.invoke(dupFileList.all { it.isSelect })
}
tvItems.text = "${data.dups.size} items"
}
} else {
holder.binding.apply {
ivSelector.isSelected = data.isSelect
}
super.onBindViewHolder(holder, position, payloads)
}
}
inner class DupImageAdapter : CommonAdapter<DupImageAdapter.DupImageViewHolder>() {
override fun setData(data: List<KoDupFileDatako>) {
dupFileList.clear()
dupFileList.addAll(data)
notifyDataSetChanged()
}
override fun addData(data: List<KoDupFileDatako>) {
dupFileList.addAll(data)
notifyDataSetChanged()
}
override fun clearData() {
if (dupFileList.size == 0) return
dupFileList.clear()
notifyDataSetChanged()
}
override fun getSelectData(): List<KoDupFileDatako> {
return dupFileList.filter { it.isSelect }
}
fun getSelectDupData(): List<KoDupFileDatako> {
return dupFileList.filter { it.isSelect }
}
fun getSelectSubData(): List<KoFileDatako> {
return dupFileList.flatMap { it.dups }.filter { it.isSelect }
}
override fun toggleSelect(select: Boolean) {
dupFileList.forEach { fileBean ->
fileBean.isSelect = select
fileBean.dups.forEach { koFileDatako ->
koFileDatako.isSelect = select
}
}
notifyDataSetChanged()
}
override fun removeData(data: List<KoDupFileDatako>) {
data.forEach {
val index = dupFileList.indexOf(it)
if (index != -1) {
dupFileList.removeAt(index)
notifyItemRemoved(index)
}
}
}
fun removeSubData(data: List<KoFileDatako>) {
dupFileList.forEach { koDupFileDatako ->
data.forEach { koFileDatako ->
koDupFileDatako.dups.remove(koFileDatako)
}
}
val removedList = dupFileList.filter { it.dups.size > 1 }
setData(removedList)
}
inner class DupImageAdapter(
private val allSelect: (flag: Boolean) -> Unit
) : CommonAdapter<DupImageAdapter.DupImageViewHolder>() {
inner class DupImageViewHolder(view: View) : ViewHolder(view) {
val binding = ItemKokoDupImageBinding.bind(view)
}
......@@ -54,17 +147,35 @@ class KoDupFilekoAdapter : RecyclerView.Adapter<KoDupFilekoAdapter.KoDupFilekoVi
override fun onBindViewHolder(holder: DupImageViewHolder, position: Int) {
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(
holder: DupImageViewHolder,
position: Int,
payloads: MutableList<Any>
) {
val content = holder.binding.root.context
val data = fileList[position]
if (payloads.isEmpty()) {
holder.binding.apply {
data.loadImageIcon(content, iv)
tvName.text = data.name
tvInfo.text = "${data.timeE} ${data.sizeF}"
ivSelector.isSelected = data.isSelect
ivSelector.setOnClickListener {
data.isSelect = !data.isSelect
ivSelector.isSelected = data.isSelect
notifyItemChanged(position, "局部刷洗")
allSelect.invoke(fileList.all { it.isSelect })
}
}
} else {
holder.binding.apply {
ivSelector.isSelected = data.isSelect
}
super.onBindViewHolder(holder, position, payloads)
}
}
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokodup
import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.zxhy.fastfilemanagerpro.CommonViewModel
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.toFile
import com.zxhy.fastfilemanagerpro.kokotools.Md5Ex.byteArrayToHexString
import com.zxhy.fastfilemanagerpro.kokotools.Md5Ex.digestMd5
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
class KoDupFilekoViewModel : CommonViewModel() {
fun isImageFilter(file: File): Boolean {
return file.name.contains(".jpg") or
file.name.contains(".gif") or
file.name.contains(".png")
}
fun isDupFileFilter(file: File): Boolean {
return file.length() > 0
}
fun loadDupImage(
context: Context,
onFinish: (list: List<KoDupFileDatako>) -> Unit
) = viewModelScope.launch(Dispatchers.IO) {
loadAllFile(context, ::isImageFilter) { list ->
onFinish.invoke(calculateDup(list))
}
}
fun loadDupFile(
context: Context,
onFinish: (list: List<KoDupFileDatako>) -> Unit
) = viewModelScope.launch(Dispatchers.IO) {
loadAllFile(context, ::isDupFileFilter) { list ->
onFinish.invoke(calculateDup(list))
}
}
private fun calculateDup(data: List<KoFileDatako>): List<KoDupFileDatako> {
val dupMap = HashMap<String, ArrayList<KoFileDatako>>()
data.forEach {
val md5 = it.toFile().digestMd5().byteArrayToHexString()
val dupList = dupMap[md5]
if (dupList == null) {
val newList = arrayListOf<KoFileDatako>()
dupMap[md5] = newList
newList.add(it)
} else {
dupList.add(it)
}
}
val dupList = dupMap.filter { it.value.size > 1 }
.map { map ->
KoDupFileDatako(md5 = map.key, dups = map.value)
}
return dupList
}
class KoDupFilekoViewModel : ViewModel() {
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokogridfile
import android.util.Log
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.zxhy.fastfilemanagerpro.R
import com.zxhy.fastfilemanagerpro.databinding.ItemKokoGridFileBinding
import com.zxhy.fastfilemanagerpro.kokoadapter.CommonAdapter
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.isImage
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.isVideo
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.toFile
import com.zxhy.fastfilemanagerpro.kokotools.GlideHelper.loadImageView
import com.zxhy.fastfilemanagerpro.kokotools.XmlEx.inflate
class KoFileGridkoAdapter(
private val allSelect: (flag: Boolean) -> Unit
) : CommonAdapter<KoFileGridkoAdapter.KoFileGridkoViewHolder>() {
inner class KoFileGridkoViewHolder(view: View) : ViewHolder(view) {
val binding = ItemKokoGridFileBinding.bind(view)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): KoFileGridkoViewHolder {
return KoFileGridkoViewHolder(R.layout.item_koko_grid_file.inflate(parent))
}
override fun onBindViewHolder(holder: KoFileGridkoViewHolder, position: Int) {
}
override fun onBindViewHolder(
holder: KoFileGridkoViewHolder,
position: Int,
payloads: MutableList<Any>
) {
val context = holder.binding.root.context
val data = fileList[position]
if (payloads.isEmpty()) {
holder.binding.apply {
ivIcon.loadImageView(context, data.toFile())
if (data.isImage()) {
ivCamera.visibility = View.GONE
}
if (data.isVideo()) {
ivCamera.visibility = View.VISIBLE
}
ivSelector.isSelected = data.isSelect
ivSelector.setOnClickListener {
data.isSelect = !data.isSelect
ivSelector.isSelected = data.isSelect
notifyItemChanged(position, "局部刷新")
allSelect.invoke(fileList.all { it.isSelect })
}
}
} else {
holder.binding.apply {
ivSelector.isSelected = data.isSelect
}
super.onBindViewHolder(holder, position, payloads)
}
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokogridfile
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.view.View
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope
import com.zxhy.fastfilemanagerpro.R
import com.zxhy.fastfilemanagerpro.databinding.ActivityKoGridFilekoBinding
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.toFile
import com.zxhy.fastfilemanagerpro.kokodialog.LoadingDialog.showLoadingDialog
import com.zxhy.fastfilemanagerpro.kokotools.ActivityLauncher
import com.zxhy.fastfilemanagerpro.kokotools.permission.PermissionCheck.storePermissionCheck
import com.zxhy.fastfilemanagerpro.kokotools.permission.StorePermissionEx.requestStoreFollow
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class KoGridFilekoActivity : AppCompatActivity() {
private lateinit var binding: ActivityKoGridFilekoBinding
private val viewModel: KoGridFilekoViewModel by viewModels()
private lateinit var activityLauncher: ActivityLauncher
private var tittle = ""
private lateinit var adapter: KoFileGridkoAdapter
private lateinit var context: Context
private var dialog: Dialog? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
context = this
activityLauncher = ActivityLauncher(this)
binding = ActivityKoGridFilekoBinding.inflate(layoutInflater)
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
tittle = intent.extras?.getString("Tittle") ?: ""
binding.tvTittle.text = tittle
adapter = KoFileGridkoAdapter {
binding.ivAllSelector.isSelected = it
enableDelete()
}
binding.rv.adapter = adapter
binding.ivAllSelector.setOnClickListener {
it.isSelected = !it.isSelected
adapter.toggleSelect(it.isSelected)
enableDelete()
}
binding.ivBack.setOnClickListener {
finish()
}
if (storePermissionCheck()) {
showPermissionSet(false)
loadListFile()
} else {
showPermissionSet(true)
}
}
//region
fun showOperationResult() = lifecycleScope.launch(Dispatchers.Main) {
binding.llResult.visibility = View.VISIBLE
delay(500)
binding.llResult.visibility = View.GONE
}
fun showPermissionSet(show: Boolean) {
if (show) {
binding.clContent.visibility = View.GONE
binding.clPermissionSet.visibility = View.VISIBLE
window.statusBarColor = ContextCompat.getColor(context, R.color.color_b3000000)
binding.tvSet.setOnClickListener {
requestStoreFollow(activityLauncher, disAgreeAction = {
showPermissionSet(true)
}, agreeAction = {
showPermissionSet(false)
loadListFile()
})
}
} else {
binding.clContent.visibility = View.VISIBLE
binding.clPermissionSet.visibility = View.GONE
window.statusBarColor = ContextCompat.getColor(context, R.color.white)
}
}
fun enableDelete() {
val enable = adapter.getSelectData().isNotEmpty()
binding.tvDelete.isEnabled = enable
if (enable) {
binding.tvDelete.background =
ContextCompat.getDrawable(context, R.drawable.bg_ffff6767_corners)
binding.tvDelete.setTextColor(ContextCompat.getColor(context, R.color.white))
binding.tvDelete.setOnClickListener {
deleteFiles()
}
} else {
binding.tvDelete.background =
ContextCompat.getDrawable(context, R.drawable.bg_fff4f4f4_corners)
binding.tvDelete.setTextColor(ContextCompat.getColor(context, R.color.color_999999))
binding.tvDelete.setOnClickListener {}
}
}
private fun deleteFiles() {
val selectData = adapter.getSelectData()
val files = selectData.map { it.toFile() }
viewModel.deleteFiles(files) {
lifecycleScope.launch(Dispatchers.Main) {
showOperationResult()
adapter.removeData(selectData)
showEmptyList()
enableDelete()
}
}
}
private fun showEmptyList() {
if (adapter.itemCount == 0) {
binding.clEmpty.visibility = View.VISIBLE
binding.clShowContent.visibility = View.GONE
binding.llAll.visibility = View.GONE
} else {
binding.clEmpty.visibility = View.GONE
binding.clShowContent.visibility = View.VISIBLE
binding.llAll.visibility = View.VISIBLE
}
}
private fun onDoList(list: List<KoFileDatako>) = lifecycleScope.launch(Dispatchers.Main) {
adapter.setData(list)
}
@SuppressLint("SetTextI18n")
private fun onFinishList(list: List<KoFileDatako>) = lifecycleScope.launch(Dispatchers.Main) {
adapter.setData(list)
showEmptyList()
enableDelete()
binding.tvItems.text = "total:${adapter.itemCount} items"
dialog?.dismiss()
}
//endregion
private fun loadListFile() {
dialog = showLoadingDialog()
when (tittle) {
IMAGE_FILE -> viewModel.loadImageFile(context, ::onDoList, ::onFinishList)
VIDEO_FILE -> viewModel.loadVideoFile(context, ::onDoList, ::onFinishList)
}
}
companion object {
const val IMAGE_FILE = "Image file"
const val VIDEO_FILE = "Video file"
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokogridfile
import android.content.Context
import com.zxhy.fastfilemanagerpro.CommonViewModel
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako
import java.io.File
class KoGridFilekoViewModel : CommonViewModel() {
fun isImageFilter(file: File): Boolean {
return file.name.contains(".jpg") or
file.name.contains(".png") or
file.name.contains(".gif")
}
fun isVideoFilter(file: File): Boolean {
return file.name.contains(".mp4") or
file.name.contains(".avi") or
file.name.contains(".flv") or
file.name.contains(".rmvb") or
file.name.contains(".mkv")
}
fun loadImageFile(
context: Context,
onDo: (list: List<KoFileDatako>) -> Unit,
onFinish: (list: List<KoFileDatako>) -> Unit
) {
loadFile(context, filter = (::isImageFilter),
onDo = { list ->
onDo.invoke(list)
},
onFinish = { list ->
onFinish.invoke(list)
}
)
}
fun loadVideoFile(
context: Context,
onDo: (list: List<KoFileDatako>) -> Unit,
onFinish: (list: List<KoFileDatako>) -> Unit
) {
loadFile(context, filter = (::isVideoFilter),
onDo = { list ->
onDo.invoke(list)
},
onFinish = { list ->
onFinish.invoke(list)
}
)
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokohome
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
......@@ -9,6 +10,9 @@ import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import com.zxhy.fastfilemanagerpro.R
import com.zxhy.fastfilemanagerpro.databinding.FragmentKoHomekoBinding
import com.zxhy.fastfilemanagerpro.kokoInternalstorage.KoInternalkoActivity
import com.zxhy.fastfilemanagerpro.kokodup.KoDupFilekoActivity.Companion.DUP_FILE
import com.zxhy.fastfilemanagerpro.kokodup.KoDupFilekoActivity.Companion.DUP_IMAGE
import com.zxhy.fastfilemanagerpro.kokolistfile.KoListFilekoActivity.Companion.EMPTY_FILE
import com.zxhy.fastfilemanagerpro.kokolistfile.KoListFilekoActivity.Companion.LARGE_FILE
import com.zxhy.fastfilemanagerpro.kokotools.DiskHelper
......@@ -50,10 +54,19 @@ class KoHomekoFragment : Fragment() {
findNavController().navigate(R.id.koListFilekoActivity, bundle)
}
binding.tvScanDupImage.setOnClickListener {
val bundle = Bundle().apply {
putString("Tittle", DUP_IMAGE)
}
findNavController().navigate(R.id.koDupFilekoActivity, bundle)
}
binding.tvScanDupFiles.setOnClickListener {
val bundle = Bundle().apply {
putString("Tittle", DUP_FILE)
}
findNavController().navigate(R.id.koDupFilekoActivity, bundle)
}
binding.flStorage.setOnClickListener {
startActivity(Intent(context, KoInternalkoActivity::class.java))
}
}
......
package com.zxhy.fastfilemanagerpro.kokolistfile
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.view.View
......@@ -15,6 +16,7 @@ import com.zxhy.fastfilemanagerpro.R
import com.zxhy.fastfilemanagerpro.databinding.ActivityKoListFilekoBinding
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.toFile
import com.zxhy.fastfilemanagerpro.kokodialog.LoadingDialog.showLoadingDialog
import com.zxhy.fastfilemanagerpro.kokotools.ActivityLauncher
import com.zxhy.fastfilemanagerpro.kokotools.permission.PermissionCheck.storePermissionCheck
import com.zxhy.fastfilemanagerpro.kokotools.permission.StorePermissionEx.requestStoreFollow
......@@ -30,6 +32,7 @@ class KoListFilekoActivity : AppCompatActivity() {
private lateinit var adapter: KoListFilekoAdapter
private var tittle = ""
private lateinit var context: Context
private var dialog: Dialog? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
......@@ -79,6 +82,7 @@ class KoListFilekoActivity : AppCompatActivity() {
if (show) {
binding.clContent.visibility = View.GONE
binding.clPermissionSet.visibility = View.VISIBLE
window.statusBarColor = ContextCompat.getColor(context, R.color.color_b3000000)
binding.tvSet.setOnClickListener {
requestStoreFollow(activityLauncher, disAgreeAction = {
showPermissionSet(true)
......@@ -90,11 +94,13 @@ class KoListFilekoActivity : AppCompatActivity() {
} else {
binding.clContent.visibility = View.VISIBLE
binding.clPermissionSet.visibility = View.GONE
window.statusBarColor = ContextCompat.getColor(context, R.color.white)
}
}
private fun loadListFile() {
dialog = showLoadingDialog()
when (tittle) {
EMPTY_FILE -> viewModel.loadEmptyFile(context, ::onDoList, ::onFinishList)
LARGE_FILE -> viewModel.loadLargeFile(context, ::onDoList, ::onFinishList)
......@@ -148,7 +154,8 @@ class KoListFilekoActivity : AppCompatActivity() {
adapter.setData(list)
showEmptyList()
enableDelete()
binding.tvTittle.text = "total:${adapter.itemCount} items"
binding.tvItems.text = "total:${adapter.itemCount} items"
dialog?.dismiss()
}
......
......@@ -8,13 +8,13 @@ import com.zxhy.fastfilemanagerpro.R
import com.zxhy.fastfilemanagerpro.databinding.ActivityKoListFilekoBinding
import com.zxhy.fastfilemanagerpro.databinding.ItemKokoListFileBinding
import com.zxhy.fastfilemanagerpro.kokoadapter.CommonAdapter
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.loadImageIcon
import com.zxhy.fastfilemanagerpro.kokotools.XmlEx.inflate
class KoListFilekoAdapter(
private val allSelect: (flag: Boolean) -> Unit
) : CommonAdapter<KoListFilekoAdapter.ItemKokoListFileViewHolder>() {
inner class ItemKokoListFileViewHolder(view: View) : ViewHolder(view) {
val binding = ItemKokoListFileBinding.bind(view)
}
......@@ -37,11 +37,13 @@ class KoListFilekoAdapter(
val data = fileList[position]
if (payloads.isEmpty()) {
holder.binding.apply {
data.loadImageIcon(context, ivIcon)
tvName.text = data.name
tvInfo.text = "${data.timeE} ${data.sizeF}"
ivSelector.isSelected = data.isSelect
ivSelector.setOnClickListener {
data.isSelect = !data.isSelect
ivSelector.isSelected = data.isSelect
notifyItemChanged(position, "局部刷洗")
allSelect.invoke(fileList.all { it.isSelect })
}
......
......@@ -4,6 +4,7 @@ import android.content.Context
import android.os.Environment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.zxhy.fastfilemanagerpro.CommonViewModel
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako.Companion.koFileDatako
import com.zxhy.fastfilemanagerpro.kokotools.HelperTraverse.linkedLisTraverseFolder
......@@ -13,7 +14,7 @@ import kotlinx.coroutines.launch
import java.io.File
import kotlin.reflect.KFunction1
class KoListFilekoViewModel : ViewModel() {
class KoListFilekoViewModel : CommonViewModel() {
fun isEmptyFilter(file: File): Boolean {
......@@ -25,23 +26,33 @@ class KoListFilekoViewModel : ViewModel() {
}
fun isAudioFilter(file: File): Boolean {
return file.length() >= 10 * 1024 * 1024L
return file.name.contains(".mp3") or
file.name.contains(".aac") or
file.name.contains(".ogg") or
file.name.contains(".aac")
}
fun isLogFilter(file: File): Boolean {
return file.length() >= 10 * 1024 * 1024L
return file.name.contains("log") or file.name.contains("Log")
}
fun isZipFilter(file: File): Boolean {
return file.length() >= 10 * 1024 * 1024L
return file.name.contains(".zip") or file.name.contains(".7z")
}
fun isApkFilter(file: File): Boolean {
return file.length() >= 10 * 1024 * 1024L
return file.name.contains(".apk")
}
fun isDocumentsFilter(file: File): Boolean {
return file.length() >= 10 * 1024 * 1024L
return file.name.contains(".doc") or
file.name.contains(".docx") or
file.name.contains(".ppt") or
file.name.contains(".pptx") or
file.name.contains(".xls") or
file.name.contains(".xlsx") or
file.name.contains(".txt") or
file.name.contains(".pdf")
}
fun loadEmptyFile(
......@@ -150,45 +161,4 @@ class KoListFilekoViewModel : ViewModel() {
)
}
private fun loadFile(
context: Context,
filter: (file: File) -> Boolean,
onDo: (list: List<KoFileDatako>) -> Unit,
onFinish: (list: List<KoFileDatako>) -> Unit
) {
viewModelScope.launch(Dispatchers.IO) {
val root = Environment.getExternalStorageDirectory()
val resultList = arrayListOf<KoFileDatako>()
var firstSend = false
linkedLisTraverseFolder(root) { file ->
if (filter(file)) {
resultList.add(file.koFileDatako(context))
if (resultList.size == 20 && !firstSend) {
onDo.invoke(resultList)
resultList.clear()
firstSend = true
}
}
}
onFinish.invoke(resultList)
}
}
fun deleteFiles(files: List<File>, finishAction: () -> Unit) =
viewModelScope.launch(Dispatchers.IO) {
runCatching {
files.forEach {
if (it.exists()) {
it.delete()
}
}
}
finishAction.invoke()
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokomanager
import android.content.Context
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.zxhy.fastfilemanagerpro.R
import com.zxhy.fastfilemanagerpro.databinding.FragmentKoManagerkoBinding
import com.zxhy.fastfilemanagerpro.kokogridfile.KoGridFilekoActivity.Companion.IMAGE_FILE
import com.zxhy.fastfilemanagerpro.kokogridfile.KoGridFilekoActivity.Companion.VIDEO_FILE
import com.zxhy.fastfilemanagerpro.kokolistfile.KoListFilekoActivity.Companion.APK_FILE
import com.zxhy.fastfilemanagerpro.kokolistfile.KoListFilekoActivity.Companion.AUDIO_FILE
import com.zxhy.fastfilemanagerpro.kokolistfile.KoListFilekoActivity.Companion.DOCUMENTS_FILE
import com.zxhy.fastfilemanagerpro.kokolistfile.KoListFilekoActivity.Companion.LOG_FILE
import com.zxhy.fastfilemanagerpro.kokolistfile.KoListFilekoActivity.Companion.ZIP_FILE
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class KoManagerkoFragment : Fragment() {
private lateinit var binding: FragmentKoManagerkoBinding
private val viewModel: KoManagerkoViewModel by viewModels()
private lateinit var context: Context
private lateinit var adapter: KoRecentkoAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
......@@ -27,10 +43,57 @@ class KoManagerkoFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
companion object{
context = requireContext()
binding.llImage.setOnClickListener {
val bundle = Bundle().apply {
putString("Tittle", IMAGE_FILE)
}
findNavController().navigate(R.id.koGridFilekoActivity, bundle)
}
binding.llVideo.setOnClickListener {
val bundle = Bundle().apply {
putString("Tittle", VIDEO_FILE)
}
findNavController().navigate(R.id.koGridFilekoActivity, bundle)
}
binding.llAudio.setOnClickListener {
val bundle = Bundle().apply {
putString("Tittle", AUDIO_FILE)
}
findNavController().navigate(R.id.koListFilekoActivity, bundle)
}
binding.llLogFile.setOnClickListener {
val bundle = Bundle().apply {
putString("Tittle", LOG_FILE)
}
findNavController().navigate(R.id.koListFilekoActivity, bundle)
}
binding.llZip.setOnClickListener {
val bundle = Bundle().apply {
putString("Tittle", ZIP_FILE)
}
findNavController().navigate(R.id.koListFilekoActivity, bundle)
}
binding.llApk.setOnClickListener {
val bundle = Bundle().apply {
putString("Tittle", APK_FILE)
}
findNavController().navigate(R.id.koListFilekoActivity, bundle)
}
binding.llDocuments.setOnClickListener {
val bundle = Bundle().apply {
putString("Tittle", DOCUMENTS_FILE)
}
findNavController().navigate(R.id.koListFilekoActivity, bundle)
}
adapter = KoRecentkoAdapter()
binding.rvRecent.adapter = adapter
viewModel.loadRecentImageVideo(context) {
lifecycleScope.launch(Dispatchers.Main) {
adapter.setData(it)
}
}
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokomanager
import android.content.Context
import androidx.lifecycle.viewModelScope
import com.zxhy.fastfilemanagerpro.CommonViewModel
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako
import com.zxhy.fastfilemanagerpro.kokotools.MediaStoreEx.recentImage
import com.zxhy.fastfilemanagerpro.kokotools.MediaStoreEx.recentVideo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class KoManagerkoViewModel : CommonViewModel() {
fun loadRecentImageVideo(
context: Context,
result: (list: ArrayList<KoFileDatako>) -> Unit
) = viewModelScope.launch(Dispatchers.IO) {
val imageList = recentImage(context).map { KoFileDatako(uri = it) }
val videoList = recentVideo(context).map { KoFileDatako(uri = it) }
val list= arrayListOf<KoFileDatako>()
list.addAll(imageList)
list.addAll(videoList)
result.invoke(list)
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokomanager
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.zxhy.fastfilemanagerpro.R
import com.zxhy.fastfilemanagerpro.databinding.ItemKokoImageBinding
import com.zxhy.fastfilemanagerpro.kokoadapter.CommonAdapter
import com.zxhy.fastfilemanagerpro.kokotools.GlideHelper.loadImageView
import com.zxhy.fastfilemanagerpro.kokotools.XmlEx.inflate
class KoRecentkoAdapter : CommonAdapter<KoRecentkoAdapter.KoRecentkoViewHolder>() {
inner class KoRecentkoViewHolder(view: View) : ViewHolder(view) {
val binding = ItemKokoImageBinding.bind(view)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): KoRecentkoViewHolder {
return KoRecentkoViewHolder(R.layout.item_koko_image.inflate(parent))
}
override fun onBindViewHolder(holder: KoRecentkoViewHolder, position: Int) {
val context = holder.binding.root.context
val data = fileList[position]
holder.binding.apply {
iv.loadImageView(context, data.uri)
}
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokotools
import android.content.Context
import android.net.Uri
import android.widget.ImageView
import com.bumptech.glide.Glide
import java.io.File
object GlideHelper {
fun ImageView.loadImageView(context: Context, file: File) {
Glide.with(context).load(file).centerCrop().into(this)
}
fun ImageView.loadImageView(context: Context, uri: Uri) {
Glide.with(context).load(uri).centerCrop().into(this)
}
}
\ No newline at end of file
package com.zxhy.fastfilemanagerpro.kokotools
import android.util.Log
import java.io.File
import java.nio.channels.FileChannel
import java.security.MessageDigest
//生成、查看文件的MD5、SHA1、SHA2、SHA3值
//https://blog.csdn.net/COCO56/article/details/106161207
object Md5Ex {
fun File.digestMd5(): ByteArray {
if (length() > Integer.MAX_VALUE) {
return "${name.length} $name".toByteArray()
}
val byteBuffer = inputStream().channel.map(FileChannel.MapMode.READ_ONLY, 0, length())
val digest = MessageDigest.getInstance("MD5")
digest.update(byteBuffer)
return digest.digest()
}
private const val HEXES = "0123456789ABCDEF"
/**
* ByteArray转Hex码
*/
fun ByteArray.byteArrayToHexString(): String {
val hex = StringBuilder(2 * this.size)
for (element in this) {
val high = element.toInt().and(0xFF).shr(4)
val low = element.toInt().and(0x0F)
hex.append(HEXES[high]).append(HEXES[low])
}
return hex.toString()
}
}
package com.zxhy.fastfilemanagerpro.kokotools
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.provider.MediaStore
import com.zxhy.fastfilemanagerpro.kokodata.KoFileDatako
object MediaStoreEx {
fun recentImage(context: Context): ArrayList<Uri> {
val list = arrayListOf<Uri>()
var cursor: Cursor? = null
// 查询照片的Uri和字段
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val projection = arrayOf(MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME)
//DESC 降列
//ASC 升序
val sortOrder = MediaStore.Images.ImageColumns._ID + " DESC"
try {
// 执行查询
cursor = context.contentResolver.query(uri, projection, null, null, sortOrder)
// 遍历结果
if (cursor != null && cursor.moveToFirst()) {
do {
val id =
cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID))
list.add(ContentUris.withAppendedId(uri, id))
if (list.size == 10) {
break
}
} while (cursor.moveToNext())
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
cursor?.close()
}
return list
}
fun recentVideo(context: Context): ArrayList<Uri> {
val list = arrayListOf<Uri>()
var cursor: Cursor? = null
// 查询照片的Uri和字段
val uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
val projection = arrayOf(MediaStore.Video.Media._ID, MediaStore.Video.Media.DISPLAY_NAME)
//DESC 降列
//ASC 升序
val sortOrder = MediaStore.Video.VideoColumns._ID + " DESC"
try {
// 执行查询
cursor = context.contentResolver.query(uri, projection, null, null, sortOrder)
// 遍历结果
if (cursor != null && cursor.moveToFirst()) {
do {
val id =
cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID))
list.add(ContentUris.withAppendedId(uri, id))
if (list.size == 10) {
break
}
} while (cursor.moveToNext())
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
cursor?.close()
}
return list
}
}
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/dda_026336" android:state_selected="false" />
<item android:drawable="@mipmap/d_998989" android:state_selected="true" />
</selector>
\ No newline at end of file
......@@ -99,6 +99,7 @@
tools:ignore="HardcodedText" />
<LinearLayout
android:visibility="gone"
android:id="@+id/ll_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
......@@ -118,16 +119,19 @@
tools:ignore="HardcodedText" />
<ImageView
android:id="@+id/iv_all_selector"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="5dp"
android:layout_marginEnd="12dp"
android:src="@drawable/bg_file_selector"
tools:ignore="ContentDescription" />
tools:ignore="ContentDescription,ImageContrastCheck" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="0dp"
android:overScrollMode="never"
android:layout_height="0dp"
android:layout_marginVertical="8dp"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
......@@ -136,6 +140,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_items" />
<TextView
android:id="@+id/tv_delete"
android:layout_width="278dp"
......@@ -149,14 +154,17 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/rv"
tools:ignore="HardcodedText" />
<LinearLayout
android:id="@+id/ll_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_000000_corners"
android:orientation="horizontal"
android:paddingVertical="8dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
......@@ -222,6 +230,7 @@
app:layout_constraintTop_toBottomOf="@id/iv_lock" />
<TextView
android:id="@+id/tv_set"
android:layout_width="270dp"
android:layout_height="40dp"
android:layout_marginTop="20dp"
......
......@@ -5,7 +5,7 @@
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".gridfile.KoGridFilekoActivity">
tools:context=".kokogridfile.KoGridFilekoActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_action_bar"
......@@ -22,6 +22,7 @@
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/iv_back"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
......@@ -82,8 +83,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_show_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_items"
......@@ -103,6 +103,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="20dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/tv_items"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_items"
......@@ -118,6 +119,7 @@
tools:ignore="HardcodedText" />
<ImageView
android:id="@+id/iv_all_selector"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
......@@ -127,14 +129,19 @@
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="0dp"
android:id="@+id/rv"
android:overScrollMode="never"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginVertical="8dp"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintBottom_toTopOf="@id/tv_delete"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_items" />
app:layout_constraintTop_toBottomOf="@id/tv_items"
app:layout_constraintVertical_bias="0.0"
app:spanCount="4" />
<TextView
android:id="@+id/tv_delete"
......@@ -151,6 +158,41 @@
app:layout_constraintRight_toRightOf="parent"
tools:ignore="HardcodedText" />
<LinearLayout
android:id="@+id/ll_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_000000_corners"
android:orientation="horizontal"
android:paddingVertical="8dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="8dp"
android:src="@mipmap/dd_899900"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tv_operation_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:singleLine="true"
android:text="Delete successful!"
android:textColor="#FFFFFF"
android:textSize="14sp"
tools:ignore="HardcodedText" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
......@@ -188,6 +230,7 @@
app:layout_constraintTop_toBottomOf="@id/iv_lock" />
<TextView
android:id="@+id/tv_set"
android:layout_width="270dp"
android:layout_height="40dp"
android:layout_marginTop="20dp"
......
......@@ -35,7 +35,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="5dp"
android:text="Tittle List Files"
android:text="Internal storage"
android:textColor="#FF333333"
android:textSize="17sp"
android:textStyle="bold"
......@@ -48,7 +48,6 @@
android:id="@+id/cl_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/cl_action_bar">
......@@ -99,7 +98,7 @@
tools:ignore="HardcodedText" />
<LinearLayout
android:id="@+id/ll_all"
android:id="@+id/ll_edit_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="20dp"
......@@ -109,21 +108,36 @@
tools:ignore="UseCompoundDrawables">
<TextView
android:id="@+id/tv_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="All"
android:textColor="#FF666666"
android:textSize="15sp"
android:visibility="gone"
tools:ignore="HardcodedText" />
<ImageView
android:id="@+id/iv_all_selector"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="5dp"
android:src="@drawable/bg_file_selector"
android:visibility="gone"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tv_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="Edit"
android:textColor="#FF666666"
android:textSize="15sp"
tools:ignore="HardcodedText" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
......@@ -131,6 +145,7 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginVertical="8dp"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toTopOf="@id/cl_operation"
app:layout_constraintEnd_toEndOf="parent"
......@@ -176,11 +191,11 @@
android:id="@+id/cl_operation"
android:layout_width="match_parent"
android:layout_height="83dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/rv">
<LinearLayout
android:id="@+id/ll_operation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
......@@ -192,6 +207,7 @@
tools:ignore="DisableBaselineAlignment">
<LinearLayout
android:id="@+id/ll_share"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
......@@ -218,6 +234,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/ll_rename"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
......@@ -244,6 +261,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/ll_delete"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
......@@ -270,6 +288,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/ll_copy"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
......@@ -296,6 +315,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/ll_move"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
......@@ -323,6 +343,70 @@
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_operation_confirm"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<ImageView
android:id="@+id/iv_selected_icon"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="20dp"
android:src="@mipmap/dzd_87897891231"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tv_confirm_items"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:text="0 items"
android:textColor="#FF666666"
android:textSize="13dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/iv_selected_icon"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText,SpUsage" />
<TextView
android:id="@+id/tv_confirm"
android:layout_width="77dp"
android:layout_height="28dp"
android:layout_marginEnd="20dp"
android:background="@drawable/bg_ffff6767_corners"
android:gravity="center"
android:text="Move"
android:textColor="@color/white"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tv_cancel"
android:layout_width="77dp"
android:layout_height="28dp"
android:layout_marginEnd="24dp"
android:background="@drawable/bg_fff4f4f4_corners"
android:gravity="center"
android:text="Cancel"
android:textColor="#FF999999"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/tv_confirm"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
......@@ -334,7 +418,8 @@
android:id="@+id/cl_permission_set"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#B3000000">
android:background="#B3000000"
android:visibility="gone">
<ImageView
android:id="@+id/iv_lock"
......
......@@ -131,6 +131,7 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="0dp"
android:overScrollMode="never"
android:layout_height="0dp"
android:layout_marginVertical="8dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
......@@ -187,6 +188,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/rv"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
......
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
app:cardBackgroundColor="@color/white"
app:cardCornerRadius="8dp">
<ImageView
android:layout_width="270dp"
android:layout_height="176dp"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tv_tittle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
android:text="Rename"
android:textColor="#FF333333"
android:textSize="17sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<ImageView
android:id="@+id/iv_delete"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="end"
android:layout_margin="6dp"
android:src="@mipmap/dd_0203060"
tools:ignore="ContentDescription" />
<EditText
android:id="@+id/edit"
android:layout_width="222dp"
android:layout_height="50dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="55dp"
android:backgroundTint="#FFE6E6E6"
android:gravity="center"
android:hint="Please enter"
android:textColor="#FF999999"
android:textColorHint="#FF999999"
android:textSize="14sp"
tools:ignore="Autofill,HardcodedText,TextFields" />
<TextView
android:id="@+id/tv_sure"
android:layout_width="238dp"
android:layout_height="40dp"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="16dp"
android:background="@drawable/bg_494949_corners"
android:gravity="center"
android:text="Sure"
android:textColor="#FFFAF6E9"
android:textSize="15sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
</androidx.cardview.widget.CardView>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
app:cardBackgroundColor="#323232"
app:cardCornerRadius="10dp">
<ImageView
android:layout_width="250dp"
android:layout_height="180dp"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/iv_loading"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:src="@drawable/loading"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
</androidx.cardview.widget.CardView>
\ No newline at end of file
......@@ -35,8 +35,12 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_recent"
android:layout_width="0dp"
android:layout_height="80dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp"
android:layout_marginTop="12dp"
android:orientation="horizontal"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_recent" />
......@@ -64,6 +68,7 @@
app:layout_constraintTop_toBottomOf="@id/tv_Folder">
<LinearLayout
android:id="@+id/ll_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
......@@ -89,6 +94,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/ll_video"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
......@@ -114,6 +120,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/ll_audio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
......@@ -150,6 +157,7 @@
app:layout_constraintTop_toBottomOf="@id/fl_1">
<LinearLayout
android:id="@+id/ll_log_file"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
......@@ -175,6 +183,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/ll_zip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
......@@ -200,6 +209,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/ll_apk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
......@@ -230,18 +240,18 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_marginTop="20dp"
android:layout_marginStart="-10dp"
android:layout_marginTop="20dp"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="@id/fl_2"
app:layout_constraintTop_toBottomOf="@id/fl_2"
tools:ignore="UseCompoundDrawables">
<ImageView
android:src="@mipmap/qwe_889989"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_gravity="center_horizontal"
android:src="@mipmap/qwe_889989"
tools:ignore="ContentDescription" />
<TextView
......
......@@ -3,7 +3,11 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:layout_marginVertical="10dp"
app:cardCornerRadius="8dp"
app:cardElevation="5dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
......@@ -14,7 +18,8 @@
android:id="@+id/tv_items"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="12dp"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:text="2 items"
android:textColor="#666666"
android:textSize="15sp"
......@@ -24,10 +29,11 @@
tools:ignore="HardcodedText" />
<ImageView
android:src="@drawable/bg_file_selector"
android:layout_width="16dp"
android:layout_height="16dp"
android:id="@+id/iv_selector"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="12dp"
android:src="@drawable/bg_file_selector"
app:layout_constraintBottom_toBottomOf="@id/tv_items"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_items"
......@@ -37,6 +43,7 @@
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_items" />
......
......@@ -3,7 +3,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:layout_margin="12dp">
<ImageView
android:id="@+id/iv"
......@@ -48,10 +49,12 @@
<ImageView
android:id="@+id/iv_selector"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/bg_file_selector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/ll"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
......
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="70dp"
android:layout_margin="8dp"
android:layout_height="70dp"
app:cardCornerRadius="8dp">
<ImageView
android:id="@+id/iv_icon"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/iv_camera"
android:layout_width="20dp"
android:layout_height="16dp"
android:layout_gravity="center"
android:src="@mipmap/cc_87897"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/iv_selector"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="end|bottom"
android:layout_margin="4dp"
android:src="@drawable/bg_grid_file_selector"
tools:ignore="ContentDescription" />
</androidx.cardview.widget.CardView>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_margin="5dp"
app:cardCornerRadius="8dp">
<ImageView
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="ContentDescription" />
</androidx.cardview.widget.CardView>
\ No newline at end of file
......@@ -13,6 +13,9 @@
<action
android:id="@+id/action_koManagerkoFragment_to_koHomekoFragment"
app:destination="@id/koHomekoFragment" />
<action
android:id="@+id/action_koManagerkoFragment_to_koGridFilekoActivity"
app:destination="@id/koGridFilekoActivity" />
</fragment>
<fragment
android:id="@+id/koHomekoFragment"
......@@ -25,10 +28,23 @@
<action
android:id="@+id/action_koHomekoFragment_to_koListFilekoActivity"
app:destination="@id/koListFilekoActivity" />
<action
android:id="@+id/action_koHomekoFragment_to_koDupFilekoActivity"
app:destination="@id/koDupFilekoActivity" />
</fragment>
<activity
android:id="@+id/koListFilekoActivity"
android:name="com.zxhy.fastfilemanagerpro.kokolistfile.KoListFilekoActivity"
android:label="activity_ko_list_fileko"
tools:layout="@layout/activity_ko_list_fileko" />
<activity
android:id="@+id/koGridFilekoActivity"
android:name="com.zxhy.fastfilemanagerpro.kokogridfile.KoGridFilekoActivity"
android:label="activity_ko_grid_fileko"
tools:layout="@layout/activity_ko_grid_fileko" />
<activity
android:id="@+id/koDupFilekoActivity"
android:name="com.zxhy.fastfilemanagerpro.kokodup.KoDupFilekoActivity"
android:label="activity_ko_dup_fileko"
tools:layout="@layout/activity_ko_dup_fileko" />
</navigation>
\ No newline at end of file
......@@ -3,4 +3,8 @@
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="color_999999">#999999</color>
<color name="color_fff4f4f4">#FFF4F4F4</color>
<color name="color_ffffff">#FFFFFF</color>
<color name="color_606060">#606060</color>
<color name="color_b3000000">#B3000000</color>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="dp_24">24dp</dimen>
<dimen name="dp_250">250dp</dimen>
<dimen name="dp_180">180dp</dimen>
<dimen name="dp_260">260dp</dimen>
<dimen name="dp_190">190dp</dimen>
</resources>
\ No newline at end of file
......@@ -13,6 +13,7 @@ activityKtx = "1.6.2"
fragmentKtx = "1.6.2"
navigationFragmentKtx = "2.7.7"
navigationUiKtx = "2.7.7"
glide = "4.16.0"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
......@@ -27,6 +28,7 @@ androidx-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", ve
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtx" }
androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" }
glide = { group = "com.github.bumptech.glide", name = "glide", version.ref = "glide" }
[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
......
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