Commit 37870549 authored by wanglei's avatar wanglei

内部储存文件结构目录

parent edd06204
...@@ -5,6 +5,14 @@ ...@@ -5,6 +5,14 @@
<uses-permission <uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE" android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" /> android:maxSdkVersion="32" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32"
tools:ignore="ScopedStorage" />
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<!-- https://developer.android.com/about/versions/14/changes/partial-photo-video-access?hl=zh-cn --> <!-- https://developer.android.com/about/versions/14/changes/partial-photo-video-access?hl=zh-cn -->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" /> <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
...@@ -25,6 +33,9 @@ ...@@ -25,6 +33,9 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.HFileManagerMaster" android:theme="@style/Theme.HFileManagerMaster"
tools:targetApi="31"> tools:targetApi="31">
<activity
android:name="com.zxhy.hfilemanagermaster.internalstorage.InternalStorageActivity"
android:exported="false" />
<activity <activity
android:name="com.zxhy.hfilemanagermaster.video.VideoActivity" android:name="com.zxhy.hfilemanagermaster.video.VideoActivity"
android:exported="false" /> android:exported="false" />
......
...@@ -41,13 +41,13 @@ class OverviewActivity : AppCompatActivity() { ...@@ -41,13 +41,13 @@ class OverviewActivity : AppCompatActivity() {
binding.ivManager.isSelected = true binding.ivManager.isSelected = true
binding.ivManager.setOnClickListener {
binding.flManager.setOnClickListener {
binding.fragmentContainerView.findNavController().navigate(R.id.managerFragment) binding.fragmentContainerView.findNavController().navigate(R.id.managerFragment)
showManager() showManager()
} }
binding.flTools.setOnClickListener {
binding.ivTools.setOnClickListener { binding.fragmentContainerView.findNavController().navigate(R.id.filesFragment)
binding.fragmentContainerView.findNavController().navigate(R.id.toolsFragment)
showTools() showTools()
} }
} }
......
...@@ -8,7 +8,6 @@ import android.net.Uri ...@@ -8,7 +8,6 @@ import android.net.Uri
* 重复图片数据 * 重复图片数据
*/ */
data class DupImageData( data class DupImageData(
val name: String = "Image", val dupList: List<MediaDataC>,
val path: String = "", var select: Boolean = false,
val Uri: Uri = android.net.Uri.EMPTY,
) )
\ No newline at end of file
package com.zxhy.hfilemanagermaster.duplicate package com.zxhy.hfilemanagermaster.duplicate
import android.annotation.SuppressLint
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.example.hfilemanagermaster.R
import com.example.hfilemanagermaster.databinding.ItemDupImageSelectBinding
import com.example.hfilemanagermaster.databinding.ItemImageSelect2Binding
import com.zxhy.hfilemanagermaster.data.DupImageData
import com.zxhy.hfilemanagermaster.data.MediaDataC
import com.zxhy.hfilemanagermaster.glide.loadIntoImageView
import com.zxhy.hfilemanagermaster.knife.inflate
class DupImageAdapter : RecyclerView.Adapter<DupImageAdapter.DupImageVideHolder>() { class DupImageAdapter(
class DupImageVideHolder(view: View) : RecyclerView.ViewHolder(view) {} private val selectAction: ((flag: Boolean) -> Unit)? = null
) : RecyclerView.Adapter<DupImageAdapter.DupImageVideHolder>() {
private val dupImageList = arrayListOf<DupImageData>()
class DupImageVideHolder(view: View) : RecyclerView.ViewHolder(view) {
val binding = ItemDupImageSelectBinding.bind(view)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DupImageVideHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DupImageVideHolder {
TODO("Not yet implemented") val root = R.layout.item_dup_image_select.inflate(parent)
return DupImageVideHolder(root)
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
TODO("Not yet implemented") return dupImageList.size
} }
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: DupImageVideHolder, position: Int) { override fun onBindViewHolder(holder: DupImageVideHolder, position: Int) {
TODO("Not yet implemented") val context = holder.binding.root.context
val data = dupImageList[position]
holder.binding.apply {
ivSelector.isSelected = data.select
tvNum.text = "${data.dupList.size} items"
val itemAdapter = DupImageItemAdapter {
ivSelector.isSelected = it
//当条被选
data.select = it
//影响外部全选
selectAction?.invoke(allSelectCheck())
}
rvDup.adapter = itemAdapter
itemAdapter.setData(data.dupList)
ivSelector.setOnClickListener {
//影响子列表
ivSelector.isSelected = itemAdapter.setToggleSelect()
//影响外部全选
selectAction?.invoke(ivSelector.isSelected)
//当调条数据被改
data.select = !data.select
notifyItemChanged(position, "单条刷新")
}
if (data == dupImageList.last()) {
selectAction?.invoke(dupImageList.all { it.select })
}
}
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(
holder: DupImageVideHolder,
position: Int,
payloads: MutableList<Any>
) {
val context = holder.binding.root.context
val data = dupImageList[position]
//判断是做局部刷新还是单条刷新
if (payloads.isEmpty()) {//局部刷新
holder.binding.apply {
ivSelector.isSelected = data.select
tvNum.text = "${data.dupList.size} items"
val itemAdapter = DupImageItemAdapter {
ivSelector.isSelected = it
//当条被选
data.select = it
//影响外部全选
selectAction?.invoke(allSelectCheck())
}
rvDup.adapter = itemAdapter
itemAdapter.setData(data.dupList)
ivSelector.setOnClickListener {
//影响子列表
ivSelector.isSelected = itemAdapter.setToggleSelect()
//影响外部全选
selectAction?.invoke(ivSelector.isSelected)
//当条数据被改
data.select = !data.select
notifyItemChanged(position, "单条刷新")
}
if (data == dupImageList.last()) {
selectAction?.invoke(dupImageList.all { it.select })
}
}
} else {
holder.binding.apply {
ivSelector.isSelected = data.select
}
super.onBindViewHolder(holder, position, payloads)
selectAction?.invoke(dupImageList.all { it.select })
}
}
@SuppressLint("NotifyDataSetChanged")
fun setData(data: List<DupImageData>) {
dupImageList.clear()
dupImageList.addAll(data)
notifyDataSetChanged()
}
@SuppressLint("NotifyDataSetChanged")
fun setToggleSelect(): Boolean {
val flag = dupImageList.all { it.select }
dupImageList.forEach {
it.select = !flag
it.dupList.forEach { mediaDataC -> mediaDataC.select = !flag }
}
notifyDataSetChanged()
return !flag
}
private fun allSelectCheck(): Boolean {
return dupImageList.all { it.select }
}
fun getSelectNum(): Int {
var i = 0
dupImageList.forEach {
it.dupList.forEach { mediaDataC ->
if (mediaDataC.select) i++
} }
}
return i
}
}
private class DupImageItemAdapter(
private val selectAction: ((flag: Boolean) -> Unit)? = null
) : RecyclerView.Adapter<DupImageItemAdapter.DupImageItemViewHolder>() {
private val mediaList = arrayListOf<MediaDataC>()
class DupImageItemViewHolder(view: View) : ViewHolder(view) {
val binding = ItemImageSelect2Binding.bind(view)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DupImageItemViewHolder {
val root = R.layout.item_image_select_2.inflate(parent)
return DupImageItemViewHolder(root)
}
override fun getItemCount(): Int {
return mediaList.size
}
override fun onBindViewHolder(holder: DupImageItemViewHolder, position: Int) {
val context = holder.binding.root.context
val data = mediaList[position]
holder.binding.apply {
loadIntoImageView(context, data.uri, ivImage)
ivSelector.isSelected = data.select
ivSelector.setOnClickListener {
data.select = !data.select
notifyItemChanged(position, "单条刷新")
}
if (data == mediaList.last()) {
selectAction?.invoke(mediaList.all { it.select })
}
}
}
override fun onBindViewHolder(
holder: DupImageItemViewHolder,
position: Int,
payloads: MutableList<Any>
) {
val context = holder.binding.root.context
val data = mediaList[position]
//判断是做局部刷新还是单条刷新
if (payloads.isEmpty()) {//局部刷新
holder.binding.apply {
loadIntoImageView(context, data.uri, ivImage)
ivSelector.isSelected = data.select
ivSelector.setOnClickListener {
data.select = !data.select
notifyItemChanged(position, "单条刷新")
}
if (data == mediaList.last()) {
selectAction?.invoke(mediaList.all { it.select })
}
}
} else { // 单条刷新
holder.binding.apply {
ivSelector.isSelected = data.select
}
super.onBindViewHolder(holder, position, payloads)
selectAction?.invoke(mediaList.all { it.select })
}
}
@SuppressLint("NotifyDataSetChanged")
fun setData(data: List<MediaDataC>) {
mediaList.clear()
mediaList.addAll(data)
notifyDataSetChanged()
}
@SuppressLint("NotifyDataSetChanged")
fun setToggleSelect(): Boolean {
val flag = mediaList.all { it.select }
mediaList.forEach { it.select = !flag }
notifyDataSetChanged()
return !flag
}
} }
\ No newline at end of file
...@@ -9,12 +9,16 @@ import androidx.core.view.WindowInsetsCompat ...@@ -9,12 +9,16 @@ import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.example.hfilemanagermaster.R import com.example.hfilemanagermaster.R
import com.example.hfilemanagermaster.databinding.ActivityDupPictureBinding import com.example.hfilemanagermaster.databinding.ActivityDupPictureBinding
import com.zxhy.hfilemanagermaster.data.DupImageData
import com.zxhy.hfilemanagermaster.knife.dupImage import com.zxhy.hfilemanagermaster.knife.dupImage
import com.zxhy.hfilemanagermaster.knife.getDupImageList
import com.zxhy.hfilemanagermaster.permission.alert
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class DupPictureActivity : AppCompatActivity() { class DupPictureActivity : AppCompatActivity() {
private lateinit var binding: ActivityDupPictureBinding private lateinit var binding: ActivityDupPictureBinding
private lateinit var adapter: DupImageAdapter
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
...@@ -29,13 +33,42 @@ class DupPictureActivity : AppCompatActivity() { ...@@ -29,13 +33,42 @@ class DupPictureActivity : AppCompatActivity() {
binding.ivArrow.setOnClickListener { binding.ivArrow.setOnClickListener {
finish() finish()
} }
adapter = DupImageAdapter {
binding.ivAll.isSelected = it
}
binding.rv.adapter = adapter
binding.ivAll.setOnClickListener {
it.isSelected = adapter.setToggleSelect()
}
binding.tvDelete.setOnClickListener { binding.tvDelete.setOnClickListener {
val num = adapter.getSelectNum()
if (num == 0) return@setOnClickListener
this.alert("当前选中${num}项,是否确认删除", "删除确认") {
positiveButton("确定") { dialog ->
dialog.dismiss()
}
negativeButton("取消") { dialog ->
dialog.dismiss()
}
//禁止取消
isCancel(false)
}
}
loadData()
}
private fun loadData() {
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
val list = dupImage() val list = dupImage()
println(list) val dupDataList = arrayListOf<DupImageData>()
lifecycleScope.launch(Dispatchers.Main) { val dupList = getDupImageList(list)
dupList.forEach {
dupDataList.add(DupImageData(dupList = it))
} }
lifecycleScope.launch(Dispatchers.Main) {
adapter.setData(dupDataList)
} }
} }
} }
......
...@@ -8,6 +8,7 @@ import android.view.ViewGroup ...@@ -8,6 +8,7 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.hfilemanagermaster.R import com.example.hfilemanagermaster.R
import com.example.hfilemanagermaster.databinding.ItemImageBinding import com.example.hfilemanagermaster.databinding.ItemImageBinding
import com.zxhy.hfilemanagermaster.knife.inflate
class ImageAdapter : RecyclerView.Adapter<ImageAdapter.ImageViewHolder>() { class ImageAdapter : RecyclerView.Adapter<ImageAdapter.ImageViewHolder>() {
...@@ -32,15 +33,7 @@ class ImageAdapter : RecyclerView.Adapter<ImageAdapter.ImageViewHolder>() { ...@@ -32,15 +33,7 @@ class ImageAdapter : RecyclerView.Adapter<ImageAdapter.ImageViewHolder>() {
holder.binding.iv.setImageURI(data) holder.binding.iv.setImageURI(data)
} }
/**
* 解析xml布局
*
* @param parent 父布局
* @param attachToRoot 是否依附到父布局
*/
fun Int.inflate(parent: ViewGroup, attachToRoot: Boolean = false): View {
return LayoutInflater.from(parent.context).inflate(this, parent, attachToRoot)
}
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
fun setData(data: List<Uri>) { fun setData(data: List<Uri>) {
......
...@@ -4,6 +4,7 @@ import android.content.Context ...@@ -4,6 +4,7 @@ import android.content.Context
import android.net.Uri import android.net.Uri
import android.widget.ImageView import android.widget.ImageView
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import java.io.File
import java.net.URI import java.net.URI
fun loadIntoImageView(context: Context, uri: String, imageView: ImageView) { fun loadIntoImageView(context: Context, uri: String, imageView: ImageView) {
...@@ -12,6 +13,13 @@ fun loadIntoImageView(context: Context, uri: String, imageView: ImageView) { ...@@ -12,6 +13,13 @@ fun loadIntoImageView(context: Context, uri: String, imageView: ImageView) {
.into(imageView) .into(imageView)
} }
fun loadIntoImageView(context: Context, file: File, imageView: ImageView) {
Glide.with(context)
.load(file)
.into(imageView)
}
fun loadIntoImageView(context: Context, uri: Uri, imageView: ImageView) { fun loadIntoImageView(context: Context, uri: Uri, imageView: ImageView) {
Glide.with(context) Glide.with(context)
.load(uri) .load(uri)
......
package com.zxhy.hfilemanagermaster.image
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.hfilemanagermaster.databinding.ItemImageBinding
class ImageSelectAdapter: RecyclerView.Adapter<ImageSelectAdapter.ImageSelectHolder>() {
class ImageSelectHolder(view: View) : RecyclerView.ViewHolder(view) {
val binding = ItemImageBinding.bind(view)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageSelectHolder {
TODO("Not yet implemented")
}
override fun getItemCount(): Int {
TODO("Not yet implemented")
}
override fun onBindViewHolder(holder: ImageSelectHolder, position: Int) {
TODO("Not yet implemented")
}
}
\ No newline at end of file
package com.zxhy.hfilemanagermaster.internalstorage
import android.annotation.SuppressLint
import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.hfilemanagermaster.R
import com.example.hfilemanagermaster.databinding.ItemFileSelectBinding
import com.zxhy.hfilemanagermaster.data.MediaDataC
import com.zxhy.hfilemanagermaster.glide.loadIntoImageView
import com.zxhy.hfilemanagermaster.knife.file2MediaDataC
import com.zxhy.hfilemanagermaster.knife.inflate
import java.io.File
class FileAdapter(
private val selectAction: ((flag: Boolean) -> Unit)? = null
) : RecyclerView.Adapter<FileAdapter.FileSelectViewHolder>() {
private val mediaList = arrayListOf<MediaDataC>()
private var isSelect = false
class FileSelectViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val binding = ItemFileSelectBinding.bind(view)
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): FileSelectViewHolder {
val root = R.layout.item_file_select.inflate(parent)
return FileSelectViewHolder(root)
}
override fun getItemCount(): Int {
return mediaList.size
}
override fun onBindViewHolder(holder: FileSelectViewHolder, position: Int) {
val context = holder.binding.root.context
val data = mediaList[position]
holder.binding.apply {
if (data.path.contains(".jpg")
or
data.path.contains(".mp4")
or
data.path.contains(".png")
) {
loadIntoImageView(context, File(data.path), iv)
} else if (data.path.contains(".txt")) {
iv.setImageResource(R.mipmap.io_002)
} else if (data.path.contains(".xlsx") or data.path.contains(".xls")) {
iv.setImageResource(R.mipmap.as_85230)
} else if (data.path.contains(".pdf")) {
iv.setImageResource(R.mipmap.io_0012)
} else if (data.path.contains(".ppt") or data.path.contains(".pptx")) {
iv.setImageResource(R.mipmap.io_002223)
} else {
iv.setImageResource(R.mipmap.tt_695)
}
tvName.text = data.name
tvSize.text = data.size
ivSelector.isSelected = data.select
flSelector.setOnClickListener {
data.select = !data.select
notifyItemChanged(position, "单条刷新")
}
ivSelector.visibility = if (isSelect) View.VISIBLE else View.GONE
if (data == mediaList.last()) {
selectAction?.invoke(mediaList.all { it.select })
}
root.setOnClickListener {
nextPage(data, context)
}
}
}
override fun onBindViewHolder(
holder: FileSelectViewHolder,
position: Int,
payloads: MutableList<Any>
) {
val context = holder.binding.root.context
val data = mediaList[position]
//判断是做局部刷新还是单条刷新
if (payloads.isEmpty()) {//局部刷新
holder.binding.apply {
if (data.path.contains(".jpg")
or
data.path.contains(".mp4")
or
data.path.contains(".png")
) {
loadIntoImageView(context, File(data.path), iv)
} else if (data.path.contains(".txt")) {
iv.setImageResource(R.mipmap.io_002)
} else if (data.path.contains(".xlsx") or data.path.contains(".xls")) {
iv.setImageResource(R.mipmap.as_85230)
} else if (data.path.contains(".pdf")) {
iv.setImageResource(R.mipmap.io_0012)
} else if (data.path.contains(".ppt") or data.path.contains(".pptx")) {
iv.setImageResource(R.mipmap.io_002223)
} else {
iv.setImageResource(R.mipmap.tt_695)
}
tvName.text = data.name
tvSize.text = data.size
ivSelector.isSelected = data.select
flSelector.setOnClickListener {
data.select = !data.select
notifyItemChanged(position, "单条刷新")
}
if (data == mediaList.last()) {
selectAction?.invoke(mediaList.all { it.select })
}
root.setOnClickListener {
nextPage(data, context)
}
ivSelector.visibility = if (isSelect) View.VISIBLE else View.GONE
}
} else {// 单条刷新
holder.binding.apply {
ivSelector.isSelected = data.select
}
super.onBindViewHolder(holder, position, payloads)
selectAction?.invoke(mediaList.all { it.select })
}
}
@SuppressLint("NotifyDataSetChanged")
fun setData(data: List<MediaDataC>) {
mediaList.clear()
mediaList.addAll(data)
notifyDataSetChanged()
}
@SuppressLint("NotifyDataSetChanged")
fun setToggleSelect(): Boolean {
val flag = mediaList.all { it.select }
mediaList.forEach { it.select = !flag }
notifyDataSetChanged()
return !flag
}
fun getSelectSize(): Int {
return mediaList.count { it.select }
}
private fun nextPage(data: MediaDataC, context: Context) {
val file = File(data.path)
if (file.isDirectory) {
val subList = file.listFiles()
val subData = subList?.map { it.file2MediaDataC(context) } ?: listOf()
setData(subData)
}
}
fun beforePage(context: Context): Boolean {
val file = File(mediaList.first().path).parentFile?.parentFile
if (file != null && file.exists()) {
if (file.isDirectory) {
val subList = file.listFiles()
if (subList.isNullOrEmpty()) return false
val subData = subList.map { it.file2MediaDataC(context) }
setData(subData)
}
return true
} else {
return false
}
}
@SuppressLint("NotifyDataSetChanged")
fun showSelect() {
isSelect = true
notifyDataSetChanged()
}
@SuppressLint("NotifyDataSetChanged")
fun showNoSelect() {
isSelect = false
notifyDataSetChanged()
}
}
\ No newline at end of file
package com.zxhy.hfilemanagermaster.internalstorage
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.view.KeyEvent
import android.view.KeyEvent.ACTION_UP
import android.view.View
import androidx.activity.enableEdgeToEdge
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 androidx.navigation.fragment.findNavController
import com.example.hfilemanagermaster.R
import com.example.hfilemanagermaster.databinding.ActivityInternalStorageBinding
import com.zxhy.hfilemanagermaster.OverviewActivity
import com.zxhy.hfilemanagermaster.knife.Saf
import com.zxhy.hfilemanagermaster.knife.file2MediaDataC
import com.zxhy.hfilemanagermaster.knife.getPublicMedia
import com.zxhy.hfilemanagermaster.permission.IntentLauncher
import com.zxhy.hfilemanagermaster.permission.PermissionLauncher
import com.zxhy.hfilemanagermaster.permission.requestStoreFollow
import com.zxhy.hfilemanagermaster.permission.settingManageExternalStorage
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
// 额外储存管理权限,读几个图片和视频
class InternalStorageActivity : AppCompatActivity() {
private lateinit var binding: ActivityInternalStorageBinding
private lateinit var saf: Saf
private lateinit var intentLauncher: IntentLauncher
private lateinit var permissionLauncher: PermissionLauncher
private lateinit var fileAdapter: FileAdapter
private var currentMode = 0 //0非可选模式 1可选模式
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
saf = Saf(this)
intentLauncher = IntentLauncher(this)
binding = ActivityInternalStorageBinding.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
}
window.statusBarColor = ContextCompat.getColor(this, R.color.color_C2F300)
binding.ivArrow.setOnClickListener {
finish()
}
binding.tvSet.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (!Environment.isExternalStorageManager()) {
val uri = Uri.parse("package:$packageName")
val intent = settingManageExternalStorage(uri)
intentLauncher.launch(intent) {
val flag = Environment.isExternalStorageManager()
if (flag) {
fileMode()
// toast("已设置额外储存管理")
} else {
// toast("未设置额外储存管理")
lockMode()
}
}
} else {
// toast("已设置额外储存管理")
fileMode()
}
} else {
requestStoreFollow(permissionLauncher, intentLauncher) { fileMode() }
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (Environment.isExternalStorageManager()) {
fileMode()
} else {
lockMode()
}
} else {
fileMode()
}
}
private fun fileMode() {
binding.clLock.visibility = View.GONE
binding.clShow.visibility = View.VISIBLE
fileAdapter = FileAdapter {
binding.ivAll.isSelected = it
}
binding.ivAll.setOnClickListener {
it.isSelected = fileAdapter.setToggleSelect()
}
binding.rv.adapter = fileAdapter
File("").renameTo(File(""))
loadFile()
noSelectMode()
}
private fun loadFile() {
lifecycleScope.launch(Dispatchers.IO) {
val rootList = Environment.getExternalStorageDirectory().listFiles()
val list = rootList?.map {
it.file2MediaDataC(this@InternalStorageActivity)
} ?: listOf()
lifecycleScope.launch(Dispatchers.Main) {
fileAdapter.setData(list)
}
}
}
private fun lockMode() {
binding.clLock.visibility = View.VISIBLE
binding.clShow.visibility = View.GONE
}
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
if (currentMode == 1) {
noSelectMode()
fileAdapter.showNoSelect()
return false
}
var flag = false
if (event.keyCode == KeyEvent.KEYCODE_BACK && event.action == ACTION_UP) {
flag = fileAdapter.beforePage(this)
}
return if (flag) {
false
} else {
super.dispatchKeyEvent(event)
}
}
private fun selectMode() {
currentMode = 1
binding.ivWrite.visibility = View.GONE
binding.ivNewFolder.visibility = View.VISIBLE
binding.ivAll.visibility = View.VISIBLE
binding.tvAll.visibility = View.VISIBLE
}
private fun noSelectMode() {
currentMode = 0
binding.ivWrite.visibility = View.VISIBLE
binding.ivNewFolder.visibility = View.VISIBLE
binding.ivAll.visibility = View.GONE
binding.tvAll.visibility = View.GONE
binding.ivWrite.setOnClickListener {
fileAdapter.showSelect()
selectMode()
}
}
}
\ No newline at end of file
...@@ -7,6 +7,8 @@ import android.database.Cursor ...@@ -7,6 +7,8 @@ import android.database.Cursor
import android.provider.MediaStore import android.provider.MediaStore
import com.zxhy.hfilemanagermaster.data.MediaDataC import com.zxhy.hfilemanagermaster.data.MediaDataC
import java.io.File import java.io.File
import java.text.SimpleDateFormat
import java.util.Locale
fun Context.dupImage(): ArrayList<MediaDataC> { fun Context.dupImage(): ArrayList<MediaDataC> {
val list = arrayListOf<MediaDataC>() val list = arrayListOf<MediaDataC>()
...@@ -14,10 +16,13 @@ fun Context.dupImage(): ArrayList<MediaDataC> { ...@@ -14,10 +16,13 @@ fun Context.dupImage(): ArrayList<MediaDataC> {
// 查询照片的Uri和字段 // 查询照片的Uri和字段
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val projection = arrayOf(MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME) val projection = arrayOf(MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME)
//DESC 降列
//ASC 升序
val sortOrder = MediaStore.Images.ImageColumns._ID + " DESC"
try { try {
// 执行查询 // 执行查询
val contentResolver: ContentResolver = contentResolver val contentResolver: ContentResolver = contentResolver
cursor = contentResolver.query(uri, projection, null, null, null) cursor = contentResolver.query(uri, projection, null, null, sortOrder)
// 遍历结果 // 遍历结果
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
...@@ -31,11 +36,13 @@ fun Context.dupImage(): ArrayList<MediaDataC> { ...@@ -31,11 +36,13 @@ fun Context.dupImage(): ArrayList<MediaDataC> {
val photoUri = ContentUris.withAppendedId(uri, id) val photoUri = ContentUris.withAppendedId(uri, id)
val filePath = getFilePathByUri(this, photoUri) ?: "" val filePath = getFilePathByUri(this, photoUri) ?: ""
val md5 = File(filePath).digestMd5().byteArrayToHexString() val md5 = File(filePath).digestMd5().byteArrayToHexString()
val time = File(filePath).lastModified()
val timeE = SimpleDateFormat("MMM dd, yyyy", Locale.ENGLISH).format(time)
// println(photoUri) // println(photoUri)
list.add(MediaDataC(uri = photoUri, path = filePath, md5 = md5)) list.add(MediaDataC(uri = photoUri, path = filePath, time = timeE, md5 = md5))
// 在此处进行照片的操作,例如显示、复制、删除等 // 在此处进行照片的操作,例如显示、复制、删除等
// ... // ...
// if (list.size == 10) { // if (list.size == 20) {
// break // break
// } // }
} while (cursor.moveToNext()) } while (cursor.moveToNext())
...@@ -49,3 +56,19 @@ fun Context.dupImage(): ArrayList<MediaDataC> { ...@@ -49,3 +56,19 @@ fun Context.dupImage(): ArrayList<MediaDataC> {
} }
return list return list
} }
//获取重复图片
fun getDupImageList(list: List<MediaDataC>): List<List<MediaDataC>> {
val dupList = arrayListOf<List<MediaDataC>>()
val origList = list.toMutableList()
list.forEach { data ->
val dup = origList.filter { it.md5 == data.md5 }
if (dup.size > 1) {
dupList.add(dup)
origList.removeAll(dup)
}
}
return dupList
}
\ No newline at end of file
package com.zxhy.hfilemanagermaster.knife
import java.io.File
fun traverseFolder(folder: File): ArrayList<File> {
val fileList = arrayListOf<File>()
folder.listFiles()?.forEach {
if (it.isDirectory) {
fileList.addAll(traverseFolder(it))
} else {
fileList.add(it)
}
}
return fileList
}
\ No newline at end of file
package com.zxhy.hfilemanagermaster.knife
import android.content.Context
import android.os.Build
import android.os.Environment
import android.text.format.Formatter
import com.zxhy.hfilemanagermaster.data.MediaDataC
import java.io.File
import java.text.SimpleDateFormat
import java.util.Locale
fun Context.getPublicMedia(): ArrayList<MediaDataC> {
val downloads = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
val dcim = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
val movies = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
val music = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)
val documents = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
val picture = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
val screenshots = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_SCREENSHOTS)
} else {
File("")
}
val list = arrayListOf<MediaDataC>()
if (downloads.exists()) {
traverseFolder(downloads).forEach {
if (it.isFile) list.add(it.file2MediaDataC(this))
}
}
if (dcim.exists()) {
traverseFolder(dcim).forEach {
if (it.isFile) list.add(it.file2MediaDataC(this))
}
}
if (movies.exists()) {
traverseFolder(movies).forEach {
if (it.isFile) list.add(it.file2MediaDataC(this))
}
}
if (music.exists()) {
traverseFolder(music).forEach {
if (it.isFile) list.add(it.file2MediaDataC(this))
}
}
if (documents.exists()) {
traverseFolder(documents).forEach {
if (it.isFile) list.add(it.file2MediaDataC(this))
}
}
if (picture.exists()) {
traverseFolder(picture).forEach {
if (it.isFile) list.add(it.file2MediaDataC(this))
}
}
if (screenshots.exists()) {
traverseFolder(screenshots).forEach {
if (it.isFile) list.add(it.file2MediaDataC(this))
}
}
return list
}
fun File.file2MediaDataC(context: Context): MediaDataC {
return try {
val sizeS = Formatter.formatFileSize(context, length())
val timeE = SimpleDateFormat("MMM dd, yyyy", Locale.ENGLISH).format(lastModified())
MediaDataC(
name = name,
size = sizeS,
time = timeE,
path = absolutePath
)
} catch (e: Exception) {
MediaDataC()
}
}
\ No newline at end of file
...@@ -26,10 +26,13 @@ fun Context.testPhoto(): ArrayList<Uri> { ...@@ -26,10 +26,13 @@ fun Context.testPhoto(): ArrayList<Uri> {
// 查询照片的Uri和字段 // 查询照片的Uri和字段
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val projection = arrayOf(MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME) val projection = arrayOf(MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME)
//DESC 降列
//ASC 升序
val sortOrder = MediaStore.Images.ImageColumns._ID + " DESC"
try { try {
// 执行查询 // 执行查询
val contentResolver: ContentResolver = contentResolver val contentResolver: ContentResolver = contentResolver
cursor = contentResolver.query(uri, projection, null, null, null) cursor = contentResolver.query(uri, projection, null, null, sortOrder)
// 遍历结果 // 遍历结果
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
......
package com.zxhy.hfilemanagermaster.knife
import android.app.Activity.RESULT_OK
import android.content.Context
import android.content.Intent
import android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION
import android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION
import android.net.Uri
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultCaller
import androidx.activity.result.contract.ActivityResultContracts
import androidx.documentfile.provider.DocumentFile
import com.shiki.koko.datafile.saf.safIntent
class Saf(activityResultCaller: ActivityResultCaller) {
private var resultIntentAction: ((ActivityResult) -> Unit)? = null
private val safLauncher =
activityResultCaller.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
resultIntentAction?.invoke(it)
}
private fun safLaunch(
safIntent: Intent,
resultAction: (ActivityResult) -> Unit
) {
this.resultIntentAction = resultAction
safLauncher.launch(safIntent)
}
//是否持久化
private fun isGrantUri(context: Context, uri: Uri?): Boolean {
if (uri != null) {
for (persistedUriPermission in context.contentResolver.persistedUriPermissions) {
if (persistedUriPermission.uri.toString() == uri.toString()) {
return true
}
}
}
return false
}
/**
*请求saf授权,方法用于固定的 请求uri和与之对应的持久化uri
*/
fun requestSaf(
context: Context,
safUri: Uri,
uriAction: (DocumentFile?) -> Unit
) {
val persistableUri = when (safUri) {
androidDataUri -> persistableAndroidDataUri
else -> null
}
if (isGrantUri(context, persistableUri)) {
// context.toast("已经持久化")
uriAction.invoke(persistableUri?.let { DocumentFile.fromTreeUri(context, it) })
return
}
safLaunch(safIntent(safUri)) {
var dstFile: DocumentFile? = null
if (it.resultCode == RESULT_OK) {
//这种方式可以避免编码问题
val uri = Uri.parse(it.data?.dataString)
val writReadFlag = FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION
//持久化权限
context.contentResolver.takePersistableUriPermission(
uri, writReadFlag
)
dstFile = DocumentFile.fromTreeUri(context, uri)
}
uriAction.invoke(dstFile)
}
}
/**
*请求saf授权,该方法根据 请求Uri的生成规则 和 持久化Uri的构建规则
* @param path 目前只测试过 :Android/data/包名
*/
fun requestSaf(
context: Context,
path: String,
uriAction: (DocumentFile?) -> Unit
) {
// val safUri =
// Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata")
val safUri = createSafUri(path)
val persistableUri = createSafPersistableUri(path)
if (isGrantUri(context, persistableUri)) {
// context.toast("已经持久化")
uriAction.invoke(persistableUri.let { DocumentFile.fromTreeUri(context, it) })
return
}
safLaunch(safIntent(safUri)) {
var dstFile: DocumentFile? = null
if (it.resultCode == RESULT_OK) {
//这种方式可以避免编码问题
//content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata%2Fcom.tencent.mtt
val uri = Uri.parse(it.data?.dataString)
val writReadFlag = FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION
//持久化权限
context.contentResolver.takePersistableUriPermission(
uri, writReadFlag
)
//这里给定的uri(用于持久化)和创建的DocumentFile的uri之间的值是不一样的
//content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata%2Fcom.tencent.mtt/document/primary%3AAndroid%2Fdata%2Fcom.tencent.mtt
dstFile = DocumentFile.fromTreeUri(context, uri)
}
uriAction.invoke(dstFile)
}
}
companion object {
//未编码路径: "content://com.android.externalstorage.documents/document/primary:Android/data"
//编码后路径: "content://com.android.externalstorage.documents/document/primary%3AAndroid%2Fdata"
//用于打开指定saf
private const val documentRoot =
"content://com.android.externalstorage.documents/document/primary"
val androidDataUri = Uri.parse("$documentRoot${Uri.encode(":Android/data")}")
/**
* 创建授权uri
* @param path :Android/data/XXX 样例
*/
fun createSafUri(path: String): Uri {
return Uri.parse("$documentRoot${Uri.encode(path)}")
}
//用于saf授权持久化
private const val documentTreeRoot =
"content://com.android.externalstorage.documents/tree/primary"
private val persistableAndroidDataUri =
Uri.parse("$documentTreeRoot${Uri.encode(":Android/data")}")
/**
* 创建持久化uri
* content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata%2Fcom.tencent.mtt
*/
fun createSafPersistableUri(path: String): Uri {
return Uri.parse("$documentTreeRoot${Uri.encode(path)}")
}
}
}
\ No newline at end of file
package com.shiki.koko.datafile.saf
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.DocumentsContract
import java.net.URI
/**
* saf文件权限请求,用于兼容androidR无法访问android/data、android/obb目录
*
* ACTION_CREATE_DOCUMENT 操作支持用户将文件保存在特定位置。
* ACTION_OPEN_DOCUMENT 操作支持用户选择要打开的特定文档或文件
* ACTION_OPEN_DOCUMENT_TREE Android 5.0(API 级别 21)及更高版本中提供,支持用户选择特定目录,授予应用对该目录中所有文件和子目录的访问权限。
*
*/
fun safIntent(uri:Uri): Intent {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
//在是个容错机制,即使URI不准确也可以定位到相应的目录
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, uri)
}
return intent
}
package com.zxhy.hfilemanagermaster.knife
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
/**
* 解析xml布局
*
* @param parent 父布局
* @param attachToRoot 是否依附到父布局
*/
fun Int.inflate(parent: ViewGroup, attachToRoot: Boolean = false): View {
return LayoutInflater.from(parent.context).inflate(this, parent, attachToRoot)
}
...@@ -9,6 +9,7 @@ import com.example.hfilemanagermaster.R ...@@ -9,6 +9,7 @@ import com.example.hfilemanagermaster.R
import com.example.hfilemanagermaster.databinding.ItemMediaSelectBinding import com.example.hfilemanagermaster.databinding.ItemMediaSelectBinding
import com.zxhy.hfilemanagermaster.data.MediaDataC import com.zxhy.hfilemanagermaster.data.MediaDataC
import com.zxhy.hfilemanagermaster.glide.loadIntoImageView import com.zxhy.hfilemanagermaster.glide.loadIntoImageView
import com.zxhy.hfilemanagermaster.knife.inflate
class LagerFileSelectorAdapter( class LagerFileSelectorAdapter(
private val selectAction: ((flag: Boolean) -> Unit)? = null private val selectAction: ((flag: Boolean) -> Unit)? = null
...@@ -90,15 +91,6 @@ class LagerFileSelectorAdapter( ...@@ -90,15 +91,6 @@ class LagerFileSelectorAdapter(
notifyDataSetChanged() notifyDataSetChanged()
} }
/**
* 解析xml布局
*
* @param parent 父布局
* @param attachToRoot 是否依附到父布局
*/
fun Int.inflate(parent: ViewGroup, attachToRoot: Boolean = false): View {
return LayoutInflater.from(parent.context).inflate(this, parent, attachToRoot)
}
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
fun setToggleSelect(): Boolean { fun setToggleSelect(): Boolean {
......
...@@ -40,12 +40,14 @@ class LargeFileActivity : AppCompatActivity() { ...@@ -40,12 +40,14 @@ class LargeFileActivity : AppCompatActivity() {
} }
binding.tvDelete.setOnClickListener { binding.tvDelete.setOnClickListener {
val num = when (currentMode) { val num = when (currentMode) {
0 -> mediaSelectAdapter.getSelectSize() 0 -> mediaSelectAdapter.getSelectSize()
1 -> imageSelectorAdapter.getSelectSize() 1 -> imageSelectorAdapter.getSelectSize()
2 -> videoSelectorAdapter.getSelectSize() 2 -> videoSelectorAdapter.getSelectSize()
else -> 0 else -> 0
} }
if (num == 0) return@setOnClickListener
this.alert("当前选中${num}项,是否确认删除", "删除确认") { this.alert("当前选中${num}项,是否确认删除", "删除确认") {
positiveButton("确定") { dialog -> positiveButton("确定") { dialog ->
dialog.dismiss() dialog.dismiss()
......
...@@ -9,6 +9,7 @@ import com.example.hfilemanagermaster.R ...@@ -9,6 +9,7 @@ import com.example.hfilemanagermaster.R
import com.example.hfilemanagermaster.databinding.ItemImageSelectBinding import com.example.hfilemanagermaster.databinding.ItemImageSelectBinding
import com.zxhy.hfilemanagermaster.data.MediaDataC import com.zxhy.hfilemanagermaster.data.MediaDataC
import com.zxhy.hfilemanagermaster.glide.loadIntoImageView import com.zxhy.hfilemanagermaster.glide.loadIntoImageView
import com.zxhy.hfilemanagermaster.knife.inflate
class LargeImageSelectorAdapter( class LargeImageSelectorAdapter(
private val selectAction: ((flag: Boolean) -> Unit)? = null private val selectAction: ((flag: Boolean) -> Unit)? = null
...@@ -75,15 +76,6 @@ class LargeImageSelectorAdapter( ...@@ -75,15 +76,6 @@ class LargeImageSelectorAdapter(
} }
} }
/**
* 解析xml布局
*
* @param parent 父布局
* @param attachToRoot 是否依附到父布局
*/
fun Int.inflate(parent: ViewGroup, attachToRoot: Boolean = false): View {
return LayoutInflater.from(parent.context).inflate(this, parent, attachToRoot)
}
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
fun setData(data: List<MediaDataC>) { fun setData(data: List<MediaDataC>) {
......
...@@ -9,6 +9,7 @@ import com.example.hfilemanagermaster.R ...@@ -9,6 +9,7 @@ import com.example.hfilemanagermaster.R
import com.example.hfilemanagermaster.databinding.ItemVideoSelectBinding import com.example.hfilemanagermaster.databinding.ItemVideoSelectBinding
import com.zxhy.hfilemanagermaster.data.MediaDataC import com.zxhy.hfilemanagermaster.data.MediaDataC
import com.zxhy.hfilemanagermaster.glide.loadIntoImageView import com.zxhy.hfilemanagermaster.glide.loadIntoImageView
import com.zxhy.hfilemanagermaster.knife.inflate
class LargeVideoSelectorAdapter( class LargeVideoSelectorAdapter(
private val selectAction: ((flag: Boolean) -> Unit)? = null private val selectAction: ((flag: Boolean) -> Unit)? = null
...@@ -71,15 +72,6 @@ class LargeVideoSelectorAdapter( ...@@ -71,15 +72,6 @@ class LargeVideoSelectorAdapter(
} }
/**
* 解析xml布局
*
* @param parent 父布局
* @param attachToRoot 是否依附到父布局
*/
fun Int.inflate(parent: ViewGroup, attachToRoot: Boolean = false): View {
return LayoutInflater.from(parent.context).inflate(this, parent, attachToRoot)
}
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
fun setData(data: List<MediaDataC>) { fun setData(data: List<MediaDataC>) {
......
...@@ -13,8 +13,7 @@ import com.example.hfilemanagermaster.R ...@@ -13,8 +13,7 @@ import com.example.hfilemanagermaster.R
import com.example.hfilemanagermaster.databinding.FragmentManagerBinding import com.example.hfilemanagermaster.databinding.FragmentManagerBinding
import com.zxhy.hfilemanagermaster.OverviewActivity import com.zxhy.hfilemanagermaster.OverviewActivity
import com.zxhy.hfilemanagermaster.knife.getMountInfoList import com.zxhy.hfilemanagermaster.knife.getMountInfoList
import com.zxhy.hfilemanagermaster.permission.IntentLauncher import com.zxhy.hfilemanagermaster.permission.requestStoreFollow
import com.zxhy.hfilemanagermaster.permission.PermissionLauncher
import com.zxhy.hfilemanagermaster.permission.requestPermission import com.zxhy.hfilemanagermaster.permission.requestPermission
import java.math.BigDecimal import java.math.BigDecimal
...@@ -57,46 +56,48 @@ class ManagerFragment : Fragment() { ...@@ -57,46 +56,48 @@ class ManagerFragment : Fragment() {
binding.ivFile.setOnClickListener { binding.ivFile.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { requireContext().requestStoreFollow(
val flag = requestPermission(
requireContext(),
(requireActivity() as OverviewActivity).permissionLauncher, (requireActivity() as OverviewActivity).permissionLauncher,
(requireActivity() as OverviewActivity).intentLauncher, (requireActivity() as OverviewActivity).intentLauncher
arrayOf(Manifest.permission.READ_MEDIA_IMAGES), "设置允许访问媒体图片权限"
) { ) {
findNavController().navigate(R.id.filesFragment) findNavController().navigate(R.id.filesFragment)
} }
if (flag) findNavController().navigate(R.id.filesFragment)
}
} }
binding.ivWord.setOnClickListener { } binding.ivWord.setOnClickListener { }
binding.ivExcel.setOnClickListener { } binding.ivExcel.setOnClickListener { }
binding.ivPdf.setOnClickListener { } binding.ivPdf.setOnClickListener { }
binding.ivPpt.setOnClickListener { } binding.ivPpt.setOnClickListener { }
binding.cardView1.setOnClickListener { binding.cardView1.setOnClickListener {
requireContext().requestStoreFollow(
(requireActivity() as OverviewActivity).permissionLauncher,
(requireActivity() as OverviewActivity).intentLauncher
) {
findNavController().navigate(R.id.dupPictureActivity) findNavController().navigate(R.id.dupPictureActivity)
} }
}
binding.cardView2.setOnClickListener { binding.cardView2.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { requireContext().requestStoreFollow(
val flag = requestPermission(
requireContext(),
(requireActivity() as OverviewActivity).permissionLauncher, (requireActivity() as OverviewActivity).permissionLauncher,
(requireActivity() as OverviewActivity).intentLauncher, (requireActivity() as OverviewActivity).intentLauncher
arrayOf(
Manifest.permission.READ_MEDIA_IMAGES,
Manifest.permission.READ_MEDIA_VIDEO
), "设置允许访问媒体图片视频权限"
) { ) {
findNavController().navigate(R.id.largeFileActivity) findNavController().navigate(R.id.largeFileActivity)
} }
if (flag) findNavController().navigate(R.id.largeFileActivity)
}
} }
binding.cardView3.setOnClickListener { binding.cardView3.setOnClickListener {
// findNavController().navigate(R.id.emptyFileActivity) requireContext().requestStoreFollow(
(requireActivity() as OverviewActivity).permissionLauncher,
(requireActivity() as OverviewActivity).intentLauncher
) {
findNavController().navigate(R.id.emptyFileActivity)
}
} }
binding.tvManage.setOnClickListener {
findNavController().navigate(R.id.internalStorageActivity)
}
} }
companion object { companion object {
......
...@@ -8,6 +8,7 @@ import android.net.Uri ...@@ -8,6 +8,7 @@ import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Environment import android.os.Environment
import android.provider.Settings import android.provider.Settings
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
/** /**
...@@ -35,11 +36,11 @@ fun requestPermission( ...@@ -35,11 +36,11 @@ fun requestPermission(
val isGrantAll = callback.values.all { it } val isGrantAll = callback.values.all { it }
if (!isGrantAll) { if (!isGrantAll) {
context.alert(tip) { context.alert(tip) {
positiveButton("跳转") { dialog -> positiveButton("Jump") { dialog ->
goToPermissionSettings(context, intentLauncher) goToPermissionSettings(context, intentLauncher)
dialog.dismiss() dialog.dismiss()
} }
negativeButton("取消") { dialog -> negativeButton("Cancel") { dialog ->
dialog.dismiss() dialog.dismiss()
} }
//禁止取消 //禁止取消
...@@ -86,4 +87,44 @@ fun appSettingsIntent(packageName: String): Intent { ...@@ -86,4 +87,44 @@ fun appSettingsIntent(packageName: String): Intent {
.setData(Uri.fromParts("package", packageName, null)) .setData(Uri.fromParts("package", packageName, null))
} }
fun Context.requestStoreFollow(
permissionLauncher: PermissionLauncher,
intentLauncher: IntentLauncher,
agreeAction: (() -> Unit)? = null
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val flag = requestPermission(
this, permissionLauncher, intentLauncher,
arrayOf(
Manifest.permission.READ_MEDIA_IMAGES,
Manifest.permission.READ_MEDIA_VIDEO
), "Set permission to access media images and videos"
) {
agreeAction?.invoke()
}
if (flag) agreeAction?.invoke()
} else {
val flag = requestPermission(
this, permissionLauncher, intentLauncher,
arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
), "Set permission to access external storage"
) {
agreeAction?.invoke()
}
if (flag) agreeAction?.invoke()
}
}
/**
* 访问所有文件权限设置界面
* https://blog.csdn.net/qq_17766199/article/details/115351949
*/
@RequiresApi(Build.VERSION_CODES.R)
fun settingManageExternalStorage(uri: Uri? = null): Intent {
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri)
// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
return intent
}
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#333333" />
<corners
android:bottomLeftRadius="20dp"
android:bottomRightRadius="20dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp" />
</shape>
\ No newline at end of file
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:ignore="RtlHardcoded" /> tools:ignore="ContentDescription,RtlHardcoded" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
...@@ -56,19 +56,20 @@ ...@@ -56,19 +56,20 @@
android:layout_width="24dp" android:layout_width="24dp"
android:layout_height="24dp" android:layout_height="24dp"
android:layout_marginRight="5dp" android:layout_marginRight="5dp"
android:src="@mipmap/dd_78652" android:src="@drawable/bg_media_selector"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toLeftOf="@id/tv_all" app:layout_constraintRight_toLeftOf="@id/tv_all"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:ignore="RtlHardcoded" /> tools:ignore="ContentDescription,RtlHardcoded" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv" android:id="@+id/rv"
tools:listitem="@layout/item_dup_image_select"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginHorizontal="20dp" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:layout_marginVertical="16dp" android:layout_marginVertical="16dp"
app:layout_constraintBottom_toTopOf="@id/tv_delete" app:layout_constraintBottom_toTopOf="@id/tv_delete"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
......
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.zxhy.hfilemanagermaster.internalstorage.InternalStorageActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_top"
android:layout_width="match_parent"
android:layout_height="37dp"
android:background="@color/color_C2F300"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/iv_arrow"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginLeft="8dp"
android:src="@mipmap/rfg_9878985"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription,RtlHardcoded" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Internal Storage"
android:textSize="17sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@id/iv_arrow"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
<ImageView
android:id="@+id/iv_write"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_margin="16dp"
android:src="@mipmap/dad_89875"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tv_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="14dp"
android:text="All"
android:textSize="17sp"
app:layout_constraintRight_toLeftOf="@id/iv_write"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText,RtlHardcoded" />
<ImageView
android:id="@+id/iv_all"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginRight="5dp"
android:src="@drawable/bg_media_selector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toLeftOf="@id/tv_all"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription,RtlHardcoded" />
<ImageView
android:id="@+id/iv_new_folder"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_margin="10dp"
android:src="@mipmap/fdfg_87965"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toLeftOf="@id/iv_all"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_lock"
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/cl_top">
<ImageView
android:id="@+id/iv_lock"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginTop="82dp"
android:src="@mipmap/ewq_989752"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tv_tip"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="66dp"
android:layout_marginTop="20dp"
android:text="There are no permissions We need to get permission to read all files."
android:textColor="#999999"
android:textSize="17sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/iv_lock"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tv_set"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginHorizontal="55dp"
android:layout_marginTop="20dp"
android:background="@drawable/bg_rectangle_333333"
android:gravity="center"
android:text="Set"
android:textColor="#FFFFFF"
android:textSize="17sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_tip"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_show"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/cl_top">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="@layout/item_file_select" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
...@@ -28,6 +28,15 @@ ...@@ -28,6 +28,15 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" /> app:layout_constraintLeft_toLeftOf="parent" />
<FrameLayout
android:id="@+id/fl_manager"
android:layout_width="36dp"
android:layout_height="36dp"
app:layout_constraintBottom_toBottomOf="@id/iv_manager"
app:layout_constraintLeft_toLeftOf="@id/iv_manager"
app:layout_constraintRight_toRightOf="@id/iv_manager"
app:layout_constraintTop_toTopOf="@id/iv_manager" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
...@@ -52,6 +61,15 @@ ...@@ -52,6 +61,15 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" /> app:layout_constraintRight_toRightOf="parent" />
<FrameLayout
android:id="@+id/fl_tools"
android:layout_width="36dp"
android:layout_height="36dp"
app:layout_constraintBottom_toBottomOf="@id/iv_tools"
app:layout_constraintLeft_toLeftOf="@id/iv_tools"
app:layout_constraintRight_toRightOf="@id/iv_tools"
app:layout_constraintTop_toTopOf="@id/iv_tools" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
......
...@@ -66,27 +66,43 @@ ...@@ -66,27 +66,43 @@
android:id="@+id/indicatorView" android:id="@+id/indicatorView"
android:layout_width="350dp" android:layout_width="350dp"
android:layout_height="159dp" android:layout_height="159dp"
android:background="@mipmap/ee_98985"
android:layout_marginHorizontal="20dp" android:layout_marginHorizontal="20dp"
android:background="@mipmap/ee_98985"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" /> app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/tv_manage"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginHorizontal="52dp"
android:layout_marginTop="28dp"
android:background="@mipmap/lopp_89956"
android:gravity="center"
android:text="Manage"
android:textColor="#FFFFFF"
android:textSize="17sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/cl_top"
tools:ignore="HardcodedText" />
<TextView <TextView
android:id="@+id/tv_tool" android:id="@+id/tv_tool"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginLeft="16dp"
android:layout_marginTop="24dp" android:layout_marginTop="19dp"
android:text="Tool" android:text="Tool"
android:textColor="#333333" android:textColor="#333333"
android:textSize="17sp" android:textSize="17sp"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/cl_top" app:layout_constraintTop_toBottomOf="@id/tv_manage"
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText,RtlHardcoded" />
<androidx.cardview.widget.CardView <androidx.cardview.widget.CardView
android:id="@+id/cardView1" android:id="@+id/cardView1"
......
<?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="match_parent"
android:layout_height="115dp"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:layout_marginTop="8dp"
android:text="2 items"
android:textColor="#333333"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText,RtlHardcoded" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_dup"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="2dp"
android:orientation="horizontal"
android:paddingHorizontal="6dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_num"
tools:listitem="@layout/item_image_select_2" />
<ImageView
android:id="@+id/iv_selector"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_margin="8dp"
android:src="@drawable/bg_media_selector"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:layout_marginVertical="8dp">
<ImageView
android:id="@+id/iv"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription,RtlHardcoded" />
<TextView
android:id="@+id/tv_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:paddingEnd="5dp"
android:text="File name"
android:textColor="#333333"
android:textSize="14sp"
app:layout_constraintBottom_toTopOf="@id/tv_size"
app:layout_constraintLeft_toRightOf="@id/iv"
app:layout_constraintRight_toLeftOf="@id/fl_selector"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText,MissingConstraints,RtlHardcoded,RtlSymmetry" />
<TextView
android:id="@+id/tv_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="20MB"
android:textColor="#999999"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="@id/tv_name"
app:layout_constraintTop_toBottomOf="@id/tv_name"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:text="January 5, 2024"
android:textColor="#999999"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@id/tv_size"
app:layout_constraintTop_toBottomOf="@id/tv_name"
tools:ignore="HardcodedText,RtlHardcoded" />
<FrameLayout
android:id="@+id/fl_selector"
android:layout_width="36dp"
android:layout_height="36dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/iv_selector"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_gravity="center"
android:src="@drawable/bg_media_selector"
android:visibility="gone"
tools:ignore="ContentDescription,RtlHardcoded" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ 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="6dp"
app:cardCornerRadius="8dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="ContentDescription" />
<ImageView
android:src="@drawable/bg_circle_selector_c2f300"
android:id="@+id/iv_selector"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_marginHorizontal="2dp"
android:layout_marginVertical="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
tools:ignore="ContentDescription" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
\ No newline at end of file
...@@ -10,9 +10,6 @@ ...@@ -10,9 +10,6 @@
android:name="com.zxhy.hfilemanagermaster.manager.ManagerFragment" android:name="com.zxhy.hfilemanagermaster.manager.ManagerFragment"
android:label="fragment_manager" android:label="fragment_manager"
tools:layout="@layout/fragment_manager" > tools:layout="@layout/fragment_manager" >
<action
android:id="@+id/action_managerFragment_to_toolsFragment"
app:destination="@id/toolsFragment" />
<action <action
android:id="@+id/action_managerFragment_to_largeFileActivity" android:id="@+id/action_managerFragment_to_largeFileActivity"
app:destination="@id/largeFileActivity" /> app:destination="@id/largeFileActivity" />
...@@ -22,18 +19,12 @@ ...@@ -22,18 +19,12 @@
<action <action
android:id="@+id/action_managerFragment_to_dupPictureActivity" android:id="@+id/action_managerFragment_to_dupPictureActivity"
app:destination="@id/dupPictureActivity" /> app:destination="@id/dupPictureActivity" />
</fragment>
<fragment
android:id="@+id/toolsFragment"
android:name="com.zxhy.hfilemanagermaster.ToolsFragment"
android:label="fragment_tools"
tools:layout="@layout/fragment_tools" >
<action <action
android:id="@+id/action_toolsFragment_to_managerFragment" android:id="@+id/action_managerFragment_to_filesFragment"
app:destination="@id/managerFragment" />
<action
android:id="@+id/action_toolsFragment_to_filesFragment"
app:destination="@id/filesFragment" /> app:destination="@id/filesFragment" />
<action
android:id="@+id/action_managerFragment_to_internalStorageActivity"
app:destination="@id/internalStorageActivity" />
</fragment> </fragment>
<fragment <fragment
android:id="@+id/filesFragment" android:id="@+id/filesFragment"
...@@ -72,4 +63,9 @@ ...@@ -72,4 +63,9 @@
android:name="com.zxhy.hfilemanagermaster.video.VideoActivity" android:name="com.zxhy.hfilemanagermaster.video.VideoActivity"
android:label="activity_video" android:label="activity_video"
tools:layout="@layout/activity_video" /> tools:layout="@layout/activity_video" />
<activity
android:id="@+id/internalStorageActivity"
android:name="com.zxhy.hfilemanagermaster.internalstorage.InternalStorageActivity"
android:label="activity_internal_storage"
tools:layout="@layout/activity_internal_storage" />
</navigation> </navigation>
\ 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