Commit 66562843 authored by wanglei's avatar wanglei

大文件获取功能

parents 37094dd6 d8cf82d1
...@@ -50,4 +50,6 @@ dependencies { ...@@ -50,4 +50,6 @@ dependencies {
testImplementation(libs.junit) testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.androidx.espresso.core)
implementation(libs.glide)
} }
\ No newline at end of file
...@@ -2,6 +2,19 @@ ...@@ -2,6 +2,19 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<!-- 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_IMAGES"
tools:ignore="SelectedPhotoAccess" />
<uses-permission
android:name="android.permission.READ_MEDIA_VIDEO"
tools:ignore="SelectedPhotoAccess" />
<application <application
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
......
...@@ -5,9 +5,8 @@ import androidx.fragment.app.Fragment ...@@ -5,9 +5,8 @@ import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import com.example.hfilemanagermaster.R import com.example.hfilemanagermaster.R
import com.example.hfilemanagermaster.databinding.FragmentFilesBinding import com.example.hfilemanagermaster.databinding.FragmentManagerBinding
// TODO: Rename parameter arguments, choose names that match // TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
...@@ -16,14 +15,13 @@ private const val ARG_PARAM2 = "param2" ...@@ -16,14 +15,13 @@ private const val ARG_PARAM2 = "param2"
/** /**
* A simple [Fragment] subclass. * A simple [Fragment] subclass.
* Use the [FilesFragment.newInstance] factory method to * Use the [ManagerFragment.newInstance] factory method to
* create an instance of this fragment. * create an instance of this fragment.
*/ */
class FilesFragment : Fragment() { class ManagerFragment : Fragment() {
// TODO: Rename and change types of parameters private lateinit var binding: FragmentManagerBinding
private var param1: String? = null private var param1: String? = null
private var param2: String? = null private var param2: String? = null
private lateinit var binding: FragmentFilesBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
...@@ -31,27 +29,31 @@ class FilesFragment : Fragment() { ...@@ -31,27 +29,31 @@ class FilesFragment : Fragment() {
param1 = it.getString(ARG_PARAM1) param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2) param2 = it.getString(ARG_PARAM2)
} }
(activity as OverviewActivity).setStatusBarColor(R.color.white)
} }
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
// Inflate the layout for this fragment val view = inflater.inflate(R.layout.fragment_manager, container, false)
val view = inflater.inflate(R.layout.fragment_files, container, false) binding = FragmentManagerBinding.bind(view.rootView)
binding = FragmentFilesBinding.bind(view)
return view return view
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.ivImage.setOnClickListener {
findNavController().navigate(R.id.imageActivity) binding.tvUse.text = "25%"
} binding.tvFree.text = "75GB"
binding.ivVideo.setOnClickListener { binding.cardView1.setOnClickListener { }
findNavController().navigate(R.id.videoActivity) binding.cardView2.setOnClickListener { }
} binding.cardView3.setOnClickListener { }
binding.ivFile.setOnClickListener { }
binding.ivWord.setOnClickListener { }
binding.ivExcel.setOnClickListener { }
binding.ivPdf.setOnClickListener { }
binding.ivPpt.setOnClickListener { }
} }
companion object { companion object {
...@@ -61,12 +63,12 @@ class FilesFragment : Fragment() { ...@@ -61,12 +63,12 @@ class FilesFragment : Fragment() {
* *
* @param param1 Parameter 1. * @param param1 Parameter 1.
* @param param2 Parameter 2. * @param param2 Parameter 2.
* @return A new instance of fragment FilesFragment. * @return A new instance of fragment ManageFragment.
*/ */
// TODO: Rename and change types and number of parameters // TODO: Rename and change types and number of parameters
@JvmStatic @JvmStatic
fun newInstance(param1: String, param2: String) = fun newInstance(param1: String, param2: String) =
FilesFragment().apply { ManagerFragment().apply {
arguments = Bundle().apply { arguments = Bundle().apply {
putString(ARG_PARAM1, param1) putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2) putString(ARG_PARAM2, param2)
......
...@@ -13,14 +13,22 @@ import androidx.core.view.WindowInsetsCompat ...@@ -13,14 +13,22 @@ import androidx.core.view.WindowInsetsCompat
import androidx.navigation.findNavController import androidx.navigation.findNavController
import com.example.hfilemanagermaster.R import com.example.hfilemanagermaster.R
import com.example.hfilemanagermaster.databinding.ActivityOverviewBinding import com.example.hfilemanagermaster.databinding.ActivityOverviewBinding
import com.zxhy.hfilemanagermaster.permission.IntentLauncher
import com.zxhy.hfilemanagermaster.permission.PermissionLauncher
class OverviewActivity : AppCompatActivity() { class OverviewActivity : AppCompatActivity() {
private lateinit var binding: ActivityOverviewBinding private lateinit var binding: ActivityOverviewBinding
lateinit var permissionLauncher: PermissionLauncher
lateinit var intentLauncher: IntentLauncher
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
permissionLauncher = PermissionLauncher(this)
intentLauncher = IntentLauncher(this)
binding = ActivityOverviewBinding.inflate(layoutInflater) binding = ActivityOverviewBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
......
package com.zxhy.hfilemanagermaster.data
import android.net.Uri
const val MediaDataC_TYPE_IMAGE = 101
const val MediaDataC_TYPE_VIDEO = 102
data class MediaDataC(
val name: String = "File name",
val size: String = "20MB",
val time: String = "January 5, 2024",
val type: Int = MediaDataC_TYPE_IMAGE,
val uri: Uri = Uri.EMPTY,
val path: String = "",
var select: Boolean = false,
)
package com.zxhy.hfilemanagermaster.files
import android.Manifest
import android.os.Bundle
import android.view.Display
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.example.hfilemanagermaster.R
import com.example.hfilemanagermaster.databinding.FragmentFilesBinding
import com.zxhy.hfilemanagermaster.OverviewActivity
import com.zxhy.hfilemanagermaster.knife.getRecentPhoto
import com.zxhy.hfilemanagermaster.knife.testPhoto
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.security.Permission
import java.security.Permissions
/**
* A simple [Fragment] subclass.
* Use the [FilesFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class FilesFragment : Fragment() {
private lateinit var binding: FragmentFilesBinding
private lateinit var imageAdapter: ImageAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
}
(activity as OverviewActivity).setStatusBarColor(R.color.white)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_files, container, false)
binding = FragmentFilesBinding.bind(view)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
imageAdapter = ImageAdapter()
binding.ivImage.setOnClickListener {
findNavController().navigate(R.id.imageActivity)
}
binding.ivVideo.setOnClickListener {
findNavController().navigate(R.id.videoActivity)
}
lifecycleScope.launch(Dispatchers.IO) {
val list = requireContext().testPhoto()
launch(Dispatchers.Main) {
binding.rv.adapter = imageAdapter
imageAdapter.setData(list)
}
}
}
companion object {
@JvmStatic
fun newInstance(param1: String, param2: String) =
FilesFragment().apply {
arguments = Bundle().apply {
}
}
}
}
\ No newline at end of file
package com.zxhy.hfilemanagermaster.files
import android.annotation.SuppressLint
import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.hfilemanagermaster.R
import com.example.hfilemanagermaster.databinding.ItemImageBinding
class ImageAdapter : RecyclerView.Adapter<ImageAdapter.ImageViewHolder>() {
private val imageList = arrayListOf<Uri>()
class ImageViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val binding = ItemImageBinding.bind(view)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder {
val root = R.layout.item_image.inflate(parent)
return ImageViewHolder(root)
}
override fun getItemCount(): Int {
return imageList.size
}
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
// val context = holder.binding.root.context
val data = imageList[position]
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")
fun setData(data: List<Uri>) {
imageList.clear()
imageList.addAll(data)
notifyDataSetChanged()
}
}
package com.zxhy.hfilemanagermaster.glide
import com.bumptech.glide.annotation.GlideModule
import com.bumptech.glide.module.AppGlideModule
/**
* 说明:使用Glide的注解,用于生产出GlideApp,该文件需要处于包的根目录
* Created by code_nil on 2017/12/29.
*/
@GlideModule
class GlideAppModule : AppGlideModule() {}
\ No newline at end of file
package com.zxhy.hfilemanagermaster.glide
import android.content.Context
import android.net.Uri
import android.widget.ImageView
import com.bumptech.glide.Glide
import java.net.URI
fun loadIntoImageView(context: Context, uri: String, imageView: ImageView) {
Glide.with(context)
.load(uri)
.into(imageView)
}
fun loadIntoImageView(context: Context, uri: Uri, imageView: ImageView) {
Glide.with(context)
.load(uri)
.into(imageView)
}
\ No newline at end of file
package com.zxhy.hfilemanagermaster.knife
import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore
/**
* Uri获取File
*/
/**
* 根据Uri获取File路径
*/
fun getFilePathByUri(context: Context, uri: Uri): String? {
var path: String? = null
// 以 file:// 开头的
if (ContentResolver.SCHEME_FILE == uri.scheme) {
path = uri.path
return path
}
// 以 content:// 开头的,比如 content://media/extenral/images/media/17766
if (ContentResolver.SCHEME_CONTENT == uri.scheme) {
val cursor = context.contentResolver.query(
uri,
arrayOf(MediaStore.Images.Media.DATA),
null,
null,
null
)
if (cursor != null) {
if (cursor.moveToFirst()) {
val columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
if (columnIndex > -1) {
path = cursor.getString(columnIndex)
}
}
cursor.close()
}
return path
}
// 4.4及之后的 是以 content:// 开头的,比如 content://com.android.providers.media.documents/document/image%3A235700
if (ContentResolver.SCHEME_CONTENT == uri.scheme) {
if (DocumentsContract.isDocumentUri(context, uri)) {
if (isExternalStorageDocument(uri)) {
// ExternalStorageProvider
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]
if ("primary".equals(type, ignoreCase = true)) {
path = Environment.getExternalStorageDirectory().toString() + "/" + split[1]
return path
}
} else if (isDownloadsDocument(uri)) {
// DownloadsProvider
val id = DocumentsContract.getDocumentId(uri)
val contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id)
)
path = getDataColumn(context, contentUri, null, null)
return path
} else if (isMediaDocument(uri)) {
// MediaProvider
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]
var contentUri: Uri? = null
when (type) {
"image" -> {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
"video" -> {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
}
"audio" -> {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}
}
val selection = "_id=?"
val selectionArgs = arrayOf(split[1])
path = getDataColumn(context, contentUri, selection, selectionArgs)
return path
}
}
}
return null
}
/**
* 通过 MediaStore Uri获取值,或者其他基于 ContentProviders 的 Uri
*/
fun getDataColumn(
context: Context, uri: Uri?, selection: String?, selectionArgs: Array<String>?
): String? {
var cursor: Cursor? = null
val column = "_data"
val projection = arrayOf(column)
try {
cursor = context.contentResolver.query(
uri!!, projection, selection, selectionArgs, null
)
if (cursor != null && cursor.moveToFirst()) {
val columnIndex = cursor.getColumnIndexOrThrow(column)
return cursor.getString(columnIndex)
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
cursor?.close()
}
return null
}
fun isExternalStorageDocument(uri: Uri): Boolean {
return "com.android.externalstorage.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
fun isMediaDocument(uri: Uri): Boolean {
return "com.android.providers.media.documents" == uri.authority
}
// Whether the Uri authority is DownloadsProvider.
fun isDownloadsDocument(uri: Uri): Boolean {
return "com.android.providers.downloads.documents" == uri.authority
}
package com.zxhy.hfilemanagermaster.knife
import android.annotation.SuppressLint
import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.media.MediaMetadataRetriever
import android.net.Uri
import android.provider.MediaStore
import android.text.format.Formatter
import com.zxhy.hfilemanagermaster.data.MediaDataC
import com.zxhy.hfilemanagermaster.data.MediaDataC_TYPE_VIDEO
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
/**
* MediaStore访问最新媒体
*/
fun Context.testPhoto(): 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)
try {
// 执行查询
val contentResolver: ContentResolver = contentResolver
cursor = contentResolver.query(uri, projection, null, null, null)
// 遍历结果
if (cursor != null && cursor.moveToFirst()) {
do {
// 获取照片的ID和名称
val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID))
val name =
cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME))
// 根据ID构建照片的Uri
val photoUri = ContentUris.withAppendedId(uri, id)
// println(photoUri)
list.add(photoUri)
// 在此处进行照片的操作,例如显示、复制、删除等
// ...
if (list.size == 10) {
break
}
} while (cursor.moveToNext())
} else {
println("无数据")
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
cursor?.close()
}
return list
}
@SuppressLint("SimpleDateFormat")
fun Context.largeVideo(): ArrayList<MediaDataC> {
val list = arrayListOf<MediaDataC>()
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,
MediaStore.Video.Media.SIZE,
)
try {
// 执行查询
val contentResolver: ContentResolver = contentResolver
cursor = contentResolver.query(uri, projection, null, null, null)
// 遍历结果
if (cursor != null && cursor.moveToFirst()) {
do {
// 获取视频的ID
val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID))
//名称
val name =
cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME))
//大小
val size =
cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE))
val sizeS = Formatter.formatFileSize(this, size)
// 根据ID构建视频的Uri
val videoUri = ContentUris.withAppendedId(uri, id)
//时间
val filePath = getFilePathByUri(this, videoUri) ?: ""
val time = File(filePath).lastModified()
// val timeS =
// SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(time)
val timeE = SimpleDateFormat("MMM dd, yyyy", Locale.ENGLISH).format(time)
list.add(
MediaDataC(
name = name,
size = sizeS,
time = timeE,
MediaDataC_TYPE_VIDEO,
uri = videoUri,
path = filePath
)
)
// 在此处进行视频的操作,例如显示、复制、删除等
// ...
if (list.size == 10) {
break
}
} while (cursor.moveToNext())
} else {
println("无数据")
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
cursor?.close()
}
return list
}
//无效
fun getMediaCreateTime(videoPath: String) {
val retriever = MediaMetadataRetriever()
try {
retriever.setDataSource(videoPath)
var creationTime =
retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE) ?: "0"
// 如果需要将UNIX时间戳转换为可读的日期格式
val date = Date(creationTime.toLong() * 1000)
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH)
creationTime = sdf.format(date)
// 输出或使用创建时间
println(creationTime)
} catch (e: Exception) {
e.printStackTrace()
} finally {
retriever.release()
}
}
\ No newline at end of file
package com.zxhy.hfilemanagermaster.knife
import android.annotation.SuppressLint
import android.app.Application
import android.database.Cursor
import android.provider.MediaStore
import java.lang.Exception
/**
* 最近图片
* 无效
*/
@SuppressLint("Recycle")
fun Application.getRecentPhoto() {
val list = arrayListOf<String>()
var cursor: Cursor? = null
val currentTime = System.currentTimeMillis() / 1000 - 60
try {
cursor = this.applicationContext.contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
arrayOf(MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA),
MediaStore.Images.Media.DATE_ADDED + " >= ?", arrayOf("$currentTime"),
MediaStore.Images.Media.DATE_ADDED + " DESC"
)
if ((cursor?.count ?: 0) < 1) {
cursor?.close()
}
if (cursor?.moveToFirst() == true) {
val path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA))
list.add(path)
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
cursor?.close()
}
}
...@@ -6,12 +6,17 @@ import androidx.appcompat.app.AppCompatActivity ...@@ -6,12 +6,17 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.navigation.findNavController import androidx.lifecycle.lifecycleScope
import com.example.hfilemanagermaster.R import com.example.hfilemanagermaster.R
import com.example.hfilemanagermaster.databinding.ActivityLargeFileBinding import com.example.hfilemanagermaster.databinding.ActivityLargeFileBinding
import com.zxhy.hfilemanagermaster.knife.largeVideo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class LargeFileActivity : AppCompatActivity() { class LargeFileActivity : AppCompatActivity() {
private lateinit var binding: ActivityLargeFileBinding private lateinit var binding: ActivityLargeFileBinding
private lateinit var mediaSelectAdapter: MediaSelectAdapter
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
...@@ -26,5 +31,25 @@ class LargeFileActivity : AppCompatActivity() { ...@@ -26,5 +31,25 @@ class LargeFileActivity : AppCompatActivity() {
binding.ivArrow.setOnClickListener { binding.ivArrow.setOnClickListener {
finish() finish()
} }
mediaSelectAdapter = MediaSelectAdapter {
binding.ivAll.isSelected = it
}
binding.rv.adapter = mediaSelectAdapter
binding.tvDelete.setOnClickListener {
}
binding.ivAll.setOnClickListener { view ->
view.isSelected = mediaSelectAdapter.setToggleSelect()
}
loadData()
}
private fun loadData() {
lifecycleScope.launch(Dispatchers.IO) {
val list = this@LargeFileActivity.largeVideo()
lifecycleScope.launch(Dispatchers.Main) {
mediaSelectAdapter.setData(list)
}
}
} }
} }
\ No newline at end of file
...@@ -27,22 +27,13 @@ class LargeFileFragment : Fragment() { ...@@ -27,22 +27,13 @@ class LargeFileFragment : Fragment() {
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_large_file, container, false) val view = inflater.inflate(R.layout.fragment_large_file, container, false)
binding = FragmentLargeFileBinding.bind(view) binding = FragmentLargeFileBinding.bind(view)
return view return view
} }
companion object { companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment LargeFileFragment.
*/
// TODO: Rename and change types and number of parameters
@JvmStatic @JvmStatic
fun newInstance(param1: String, param2: String) = fun newInstance(param1: String, param2: String) =
LargeFileFragment().apply { LargeFileFragment().apply {
......
package com.zxhy.hfilemanagermaster.largefile
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.hfilemanagermaster.R
import com.example.hfilemanagermaster.databinding.ItemMediaSelectBinding
import com.zxhy.hfilemanagermaster.data.MediaDataC
import com.zxhy.hfilemanagermaster.glide.loadIntoImageView
class MediaSelectAdapter(
val selectAction: ((flag: Boolean) -> Unit)? = null
) : RecyclerView.Adapter<MediaSelectAdapter.MediaSelectViewHolder>() {
private val mediaList = arrayListOf<MediaDataC>()
class MediaSelectViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val binding = ItemMediaSelectBinding.bind(view)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MediaSelectViewHolder {
val root = R.layout.item_media_select.inflate(parent)
return MediaSelectViewHolder(root)
}
override fun getItemCount(): Int {
return mediaList.size
}
override fun onBindViewHolder(holder: MediaSelectViewHolder, position: Int) {
val context = holder.binding.root.context
val data = mediaList[position]
holder.binding.apply {
loadIntoImageView(context, data.uri, iv)
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 })
}
}
override fun onBindViewHolder(
holder: MediaSelectViewHolder,
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, iv)
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 })
}
}
} 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()
}
/**
* 解析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")
fun setToggleSelect(): Boolean {
val flag = mediaList.all { it.select }
mediaList.forEach { it.select = !flag }
notifyDataSetChanged()
return !flag
}
}
\ No newline at end of file
package com.zxhy.hfilemanagermaster.manager package com.zxhy.hfilemanagermaster.manager
import android.Manifest
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
...@@ -11,6 +13,9 @@ import com.example.hfilemanagermaster.R ...@@ -11,6 +13,9 @@ 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.PermissionLauncher
import com.zxhy.hfilemanagermaster.permission.requestPermission
import java.math.BigDecimal import java.math.BigDecimal
/** /**
...@@ -23,8 +28,7 @@ class ManagerFragment : Fragment() { ...@@ -23,8 +28,7 @@ class ManagerFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
arguments?.let { arguments?.let {}
}
} }
override fun onCreateView( override fun onCreateView(
...@@ -45,32 +49,52 @@ class ManagerFragment : Fragment() { ...@@ -45,32 +49,52 @@ class ManagerFragment : Fragment() {
val percentF = BigDecimal(disk.used) val percentF = BigDecimal(disk.used)
.divide(BigDecimal(disk.total), 2, BigDecimal.ROUND_HALF_UP) .divide(BigDecimal(disk.total), 2, BigDecimal.ROUND_HALF_UP)
// binding.indicatorView.setPercent(percentF.toFloat()) binding.indicatorView.setPercent(percentF.toFloat())
binding.indicatorView.setPercent(0.3f)
val percent = percentF.multiply(BigDecimal(100)).toInt() val percent = percentF.multiply(BigDecimal(100)).toInt()
binding.tvUse.text = "$percent%" binding.tvUse.text = "$percent%"
(requireActivity() as OverviewActivity).showManager() (requireActivity() as OverviewActivity).showManager()
binding.cardView1.setOnClickListener { }
binding.cardView2.setOnClickListener { }
binding.cardView3.setOnClickListener { }
binding.ivFile.setOnClickListener { binding.ivFile.setOnClickListener {
findNavController().navigate(R.id.filesFragment)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val flag = requestPermission(
requireContext(),
(requireActivity() as OverviewActivity).permissionLauncher,
(requireActivity() as OverviewActivity).intentLauncher,
arrayOf(Manifest.permission.READ_MEDIA_IMAGES), "设置允许访问媒体图片权限"
) {
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 {
findNavController().navigate(R.id.dupPictureActivity) // findNavController().navigate(R.id.dupPictureActivity)
} }
binding.cardView2.setOnClickListener { binding.cardView2.setOnClickListener {
findNavController().navigate(R.id.largeFileActivity)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val flag = requestPermission(
requireContext(),
(requireActivity() as OverviewActivity).permissionLauncher,
(requireActivity() as OverviewActivity).intentLauncher,
arrayOf(
Manifest.permission.READ_MEDIA_IMAGES,
Manifest.permission.READ_MEDIA_VIDEO
), "设置允许访问媒体图片视频权限"
) {
findNavController().navigate(R.id.largeFileActivity)
}
if (flag) findNavController().navigate(R.id.largeFileActivity)
}
} }
binding.cardView3.setOnClickListener { binding.cardView3.setOnClickListener {
findNavController().navigate(R.id.emptyFileActivity) // findNavController().navigate(R.id.emptyFileActivity)
} }
} }
...@@ -83,4 +107,5 @@ class ManagerFragment : Fragment() { ...@@ -83,4 +107,5 @@ class ManagerFragment : Fragment() {
} }
} }
} }
} }
\ No newline at end of file
package com.zxhy.hfilemanagermaster.permission
import android.content.Intent
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultCaller
import androidx.activity.result.contract.ActivityResultContracts
/**
* 对应Intent的处理
*/
class IntentLauncher(activityResultCaller: ActivityResultCaller) {
private var activityResultCallback: ActivityResultCallback<ActivityResult>? = null
private val intentLauncher =
activityResultCaller.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult: ActivityResult ->
activityResultCallback?.onActivityResult(activityResult)
}
/**
* it.resultCode == Activity.RESULT_OK
*/
fun launch(
intent: Intent,
activityResultCallback: ActivityResultCallback<ActivityResult>? = null
) {
this.activityResultCallback = activityResultCallback
intentLauncher.launch(intent)
}
}
\ No newline at end of file
package com.zxhy.hfilemanagermaster.permission
import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.Settings
import androidx.core.content.ContextCompat
/**
* 获取媒体图片
*/
fun requestPermission(
context: Context,
permissionLauncher: PermissionLauncher,
intentLauncher: IntentLauncher,
permission: Array<String>,
tip: String,
agreeAction: (() -> Unit)? = null
): Boolean {
var flag = false
val request: () -> Unit = {
val permissionFlag =
permission.all {
ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}
if (permissionFlag) {
flag = true
} else {
permissionLauncher.launch(permission) { callback ->
val isGrantAll = callback.values.all { it }
if (!isGrantAll) {
context.alert(tip) {
positiveButton("跳转") { dialog ->
goToPermissionSettings(context, intentLauncher)
dialog.dismiss()
}
negativeButton("取消") { dialog ->
dialog.dismiss()
}
//禁止取消
isCancel(false)
}
} else {
agreeAction?.invoke()
}
}
}
// Toast.makeText(context, "不会等待回调", Toast.LENGTH_SHORT).show()
}
if (permission.contains(Manifest.permission.WRITE_EXTERNAL_STORAGE)
&& permission.contains(Manifest.permission.READ_EXTERNAL_STORAGE)
) {
val managerFlag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
Environment.isExternalStorageManager()
} else {
false
}
if (managerFlag) {
return true
} else {
request()
}
} else {
request()
}
return flag
}
//权限设置界面
private fun goToPermissionSettings(context: Context, intentLauncher: IntentLauncher) {
val intent = appSettingsIntent(context.packageName)
intentLauncher.launch(intent)
}
/**
* 应用设置页面意图
*/
fun appSettingsIntent(packageName: String): Intent {
return Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
.setData(Uri.fromParts("package", packageName, null))
}
package com.zxhy.hfilemanagermaster.permission
import android.app.ActivityManager
import android.content.Context
import android.content.pm.PackageManager
import androidx.core.content.ContextCompat
//检查是否有所有权限
fun havePermission(context: Context, permissions: Array<String>): Boolean {
var havePermission = true
permissions.forEach {
if (ContextCompat.checkSelfPermission(context, it) != PackageManager.PERMISSION_GRANTED) {
havePermission = false
}
}
return havePermission
}
//检查拒绝的权限
fun denyPermission(context: Context, permissions: Array<String>): ArrayList<String> {
val denys = arrayListOf<String>()
permissions.forEach {
if (ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_DENIED) {
denys.add(it)
}
}
return denys
}
package com.zxhy.hfilemanagermaster.permission
import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultCaller
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.FragmentActivity
/**
* @param activityResultCaller [ComponentActivity] 实现该接口
*
*/
class PermissionLauncher(activityResultCaller: ActivityResultCaller) {
/**
* [ActivityResultContracts.RequestMultiplePermissions] 权限协议回调
* ActivityResultContract<String[], java.util.Map<String, Boolean>>
* String[] 表示输入权限
* Map<String, Boolean> 表示权限回调的结果
* 可以参考范型实现 [ResultLauncher]
*/
private var permissionCallback: ActivityResultCallback<Map<String, Boolean>>? = null
//必须在Activity或者Fragment显示之前注册
//说实话有点傻逼,进过测试,可以直接在Activity的onCreate中初始化
private val permissionLauncher =
activityResultCaller.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result: Map<String, Boolean> ->
permissionCallback?.onActivityResult(result)
}
fun launch(
permissionArray: Array<String>,
permissionCallback: ActivityResultCallback<Map<String, Boolean>>?
) {
this.permissionCallback = permissionCallback
permissionLauncher.launch(permissionArray)
}
}
...@@ -30,7 +30,9 @@ class IndicatorView : View { ...@@ -30,7 +30,9 @@ class IndicatorView : View {
private var scale = 1f//指针图像缩放比例 private var scale = 1f//指针图像缩放比例
private var rotationDegrees = 0f // 旋转的角度 private var rotationDegrees = 0f // 旋转的角度
private var indicatorY = 0.95f//绘制指针画布Y移动的距离
private var indicatorX = 0f//绘制指针画布X移动的修补
private var rotationDegreesOffset = 0f//指针旋转误差修补
// 画原始刻度的画笔 // 画原始刻度的画笔
private var arcPaint: Paint = Paint() private var arcPaint: Paint = Paint()
...@@ -91,29 +93,84 @@ class IndicatorView : View { ...@@ -91,29 +93,84 @@ class IndicatorView : View {
super.onDraw(canvas) super.onDraw(canvas)
Log.e("IndicatorView", "radius=$radius") // Log.e("IndicatorView", "radius=$radius")
val left = hMargin + strokeWidth / 2 val left = hMargin + strokeWidth / 2
val top = topMargin + strokeWidth / 2 val top = topMargin + strokeWidth / 2
val right = radius * 2 + left val right = radius * 2 + left
val bottom = radius * 2 + top val bottom = radius * 2 + top
Log.e("IndicatorView", "left=$left top=$top right=$right bottom=$bottom") // Log.e("IndicatorView", "left=$left top=$top right=$right bottom=$bottom")
//绘制半圆 //绘制半圆
val arcRect = RectF(left, top, right, bottom) val arcRect = RectF(left, top, right, bottom)
canvas.drawArc(arcRect, -180f, sweepAngle, false, arcPaint) canvas.drawArc(arcRect, -180f, sweepAngle, false, arcPaint)
canvas.translate((measuredWidth / 2).toFloat() + 50, measuredHeight - 250f) canvas.translate(
(measuredWidth / 2).toFloat() - (bgBitmap.width / 2) * indicatorX,
measuredHeight.toFloat() * indicatorY
)
// 绘制旋转后的图片 // 绘制旋转后的图片
// val srcRect = Rect(0, 0, 100, 100) // val srcRect = Rect(0, 0, 100, 100)
// val dstRect = Rect(0, 0, 100, 100) // val dstRect = Rect(0, 0, 100, 100)
//绘制指针 //绘制指针
canvas.rotate(rotationDegrees)
canvas.save()
canvas.drawBitmap(bgBitmap, 0f, -bgBitmap.height.toFloat(), Paint())
} }
//绘制百分比 //绘制百分比
fun setPercent(percent: Float) { fun setPercent(percent: Float) {
sweepAngle = 180f * percent sweepAngle = 180f * percent
rotationDegrees = 180f * percent-80f rotationDegrees = 180f * percent - 90f
// sweepAngle = 180f
// rotationDegrees = 180f - 90f
//针对指针角度进行误差调整
when (sweepAngle) {
in 0f..29f -> {
indicatorY = 0.95f
indicatorX = 0f
rotationDegreesOffset = -8f
}
in 30f..59f -> {
indicatorY = 0.98f
indicatorX = 0f
rotationDegreesOffset = -5f
}
in 60f..89f -> {
indicatorY = 0.95f
indicatorX = 1f
rotationDegreesOffset = 0f
rotationDegrees += rotationDegreesOffset
}
in 90f..99f -> {
indicatorY = 0.95f
indicatorX = 1f
rotationDegreesOffset = 0f
}
in 100f..119f->{
indicatorY = 0.95f
indicatorX = 1f
rotationDegreesOffset = 2f
}
in 120f..149f -> {
indicatorY = 0.85f
indicatorX = 1.05f
rotationDegreesOffset = 8f
}
in 150f..180f -> {
indicatorY = 0.85f
indicatorX = 1.08f
rotationDegreesOffset = 8f
}
}
rotationDegrees += rotationDegreesOffset
// Log.e("IndicatorView", "rotationDegrees=$rotationDegrees")
invalidate() invalidate()
} }
} }
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadius="7dp"
android:shape="ring"
android:thickness="1dp"
android:useLevel="false">
<solid android:color="#999999" />
<size
android:width="18dp"
android:height="18dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/dd_7865211111" android:state_selected="true" />
<item android:drawable="@mipmap/dd_78652" android:state_selected="false" />
</selector>
\ No newline at end of file
...@@ -51,16 +51,17 @@ ...@@ -51,16 +51,17 @@
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText,RtlHardcoded" /> tools:ignore="HardcodedText,RtlHardcoded" />
<ImageView <ImageView
android:id="@+id/iv_all" android:id="@+id/iv_all"
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>
...@@ -111,12 +112,14 @@ ...@@ -111,12 +112,14 @@
android:id="@+id/rv" android:id="@+id/rv"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginHorizontal="20dp" android:layout_marginHorizontal="12dp"
android:layout_marginVertical="16dp" android:layout_marginVertical="16dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toTopOf="@id/tv_delete" app:layout_constraintBottom_toTopOf="@id/tv_delete"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_file" /> app:layout_constraintTop_toBottomOf="@id/tv_file"
tools:listitem="@layout/item_media_select" />
<TextView <TextView
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context="com.zxhy.hfilemanagermaster.FilesFragment"> tools:context="com.zxhy.hfilemanagermaster.files.FilesFragment">
<TextView <TextView
...@@ -190,6 +190,17 @@ ...@@ -190,6 +190,17 @@
app:cardCornerRadius="8dp" app:cardCornerRadius="8dp"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_recent" /> app:layout_constraintTop_toBottomOf="@id/tv_recent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_marginHorizontal="6dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_image" />
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout> </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="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="6dp"
android:layout_marginVertical="12dp"
app:cardCornerRadius="8dp">
<ImageView
android:id="@+id/iv"
android:layout_width="80dp"
android:layout_height="80dp"
tools:ignore="ContentDescription" />
</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"
tools:ignore="ContentDescription,RtlHardcoded" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
</fragment> </fragment>
<fragment <fragment
android:id="@+id/filesFragment" android:id="@+id/filesFragment"
android:name="com.zxhy.hfilemanagermaster.FilesFragment" android:name="com.zxhy.hfilemanagermaster.files.FilesFragment"
android:label="fragment_files" android:label="fragment_files"
tools:layout="@layout/fragment_files" > tools:layout="@layout/fragment_files" >
<action <action
......
...@@ -11,6 +11,7 @@ activity = "1.8.0" ...@@ -11,6 +11,7 @@ activity = "1.8.0"
constraintlayout = "2.1.4" constraintlayout = "2.1.4"
navigationFragmentKtx = "2.7.7" navigationFragmentKtx = "2.7.7"
navigationUiKtx = "2.7.7" navigationUiKtx = "2.7.7"
glide = "4.16.0"
[libraries] [libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
...@@ -24,6 +25,9 @@ androidx-constraintlayout = { group = "androidx.constraintlayout", name = "const ...@@ -24,6 +25,9 @@ androidx-constraintlayout = { group = "androidx.constraintlayout", name = "const
androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtx" } 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" } 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] [plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" } androidApplication = { id = "com.android.application", version.ref = "agp" }
jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
......
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