添加注释

This commit is contained in:
zxj
2025-08-22 16:36:17 +08:00
parent 18fbdc9875
commit d48f41e917
16 changed files with 28 additions and 440 deletions
@@ -1,5 +1,8 @@
package com.sw.dualscreen.utils
/**
* 防抖工具
*/
class Debouncer(private val delayMillis: Long = 2000) {
private var lastActionTime = 0L
@@ -1,156 +0,0 @@
package com.sw.dualscreen.utils
import android.content.ContentUris
import android.content.Context
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import androidx.annotation.RequiresApi
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import timber.log.Timber
import java.io.File
object FileUtils {
/**
* 从Uri获取File
* example: file:///data/user/0/com.sw.inbound/cache/IMG_17515262353556856678814444882273.jpg
*/
private fun getFileFromUri(context: Context, uri: Uri): File? {
Timber.d("getFileFromUri uri = ${uri.scheme}")
return when (uri.scheme) {
"file" -> File(uri.path ?: return null)
"content" -> {
try {
val inputStream = context.contentResolver.openInputStream(uri) ?: return null
val cacheDir = context.cacheDir
val file = File.createTempFile(
"upload_${System.currentTimeMillis()}",
".jpg",
cacheDir
)
file.outputStream().use { output ->
inputStream.copyTo(output)
}
file
} catch (e: Exception) {
Timber.e(e)
null
}
}
else -> null
}
}
/**
* 通过uri生成http请求体
*/
fun genRequestPart(context: Context, imageUri: Uri): MultipartBody.Part? {
Timber.d("genRequestPart imageUri = $imageUri")
// 1. 从Uri获取文件
val file = getFileFromUri(context, imageUri)
if (file == null) {
Timber.e("getFileFromUri file is null")
return null
}
// 2. 创建请求体
val requestFile = file
.asRequestBody("application/octet-stream".toMediaTypeOrNull())
val imagePart = MultipartBody.Part.createFormData(
"file",
file.name,
requestFile
)
return imagePart
}
/**
* 通过Uri删除文件
* @param context 上下文
* @param uri 文件Uri
* @return Boolean 是否删除成功
*/
fun deleteFileWithUri(context: Context, uri: Uri): Boolean {
Timber.d("deleteFileWithUri uri = ${uri.scheme}")
return when {
// 1. 处理 content:// 类型的Uri (MediaStore)
uri.scheme.equals("content", ignoreCase = true) -> {
deleteContentUriFile(context, uri)
}
// 2. 处理 file:// 类型的Uri
uri.scheme.equals("file", ignoreCase = true) -> {
deleteFileUriFile(uri)
}
// 3. 其他情况尝试直接解析路径
else -> {
deleteFileFromPath(uri.path ?: return false)
}
}
}
// 删除Content Uri文件
private fun deleteContentUriFile(context: Context, uri: Uri): Boolean {
Timber.d("deleteContentUriFile uri = ${uri.scheme}")
return try {
context.contentResolver.delete(uri, null, null) > 0
} catch (e: SecurityException) {
// Android 10+需要特殊处理
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
deleteMediaStoreFile(context, uri)
} else {
false
}
} catch (e: Exception) {
Timber.e(e)
false
}
}
// Android 10+删除MediaStore文件
@RequiresApi(Build.VERSION_CODES.Q)
private fun deleteMediaStoreFile(context: Context, uri: Uri): Boolean {
Timber.d("deleteMediaStoreFile uri = ${uri.scheme}")
val contentResolver = context.contentResolver
val projection = arrayOf(MediaStore.MediaColumns._ID)
return try {
contentResolver.query(uri, projection, null, null, null)?.use { cursor ->
if (cursor.moveToFirst()) {
val id =
cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID))
val contentUri = ContentUris.withAppendedId(uri, id)
contentResolver.delete(contentUri, null, null) > 0
} else {
false
}
} ?: false
} catch (e: Exception) {
Timber.e(e)
false
}
}
// 删除File Uri文件
private fun deleteFileUriFile(uri: Uri): Boolean {
Timber.d("deleteFileUriFile uri = $uri")
return try {
File(uri.path ?: return false).delete()
} catch (e: Exception) {
Timber.e(e)
false
}
}
// 直接通过路径删除文件
private fun deleteFileFromPath(path: String): Boolean {
Timber.d("deleteFileFromPath path = $path")
return try {
File(path).delete()
} catch (e: Exception) {
Timber.e(e)
false
}
}
}
@@ -1,4 +1,4 @@
package com.sw.inbound.utils
package com.sw.dualscreen.utils
import android.content.Context
import androidx.core.content.edit
@@ -9,6 +9,9 @@ import kotlinx.coroutines.flow.map
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
/**
* 持久化工具
*/
class SPUtil private constructor(context: Context, private val spName: String) {
companion object {
@@ -1,47 +0,0 @@
package com.sw.dualscreen.utils
import android.content.Context
import android.util.DisplayMetrics
import android.view.WindowManager
import timber.log.Timber
import kotlin.math.sqrt
object ScreenUtils {
fun printScreenInfo(context: Context, tag: String) {
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val displayMetrics = DisplayMetrics()
// 方法 1:获取应用可用区域(排除系统装饰,如状态栏)
windowManager.defaultDisplay.getMetrics(displayMetrics)
// 方法 2:获取整个屏幕的物理尺寸(包括状态栏和导航栏)
// windowManager.defaultDisplay.getRealMetrics(displayMetrics)
val screenWidthPx = displayMetrics.widthPixels // 屏幕宽度(像素)
val screenHeightPx = displayMetrics.heightPixels // 屏幕高度(像素)
val density = displayMetrics.density // 逻辑密度(1.0 = mdpi, 2.0 = xhdpi
val densityDpi = displayMetrics.densityDpi // 屏幕 DPI 分类(160 = mdpi, 320 = xhdpi
val xdpi = displayMetrics.xdpi // 物理水平 DPI
val ydpi = displayMetrics.ydpi // 物理垂直 DPI
// 打印信息
Timber.d("$tag 屏幕信息")
Timber.d("屏幕分辨率(像素): ${screenWidthPx}x${screenHeightPx}")
Timber.d("逻辑密度: $density")
Timber.d("DPI 分类: $densityDpi")
Timber.d("物理 DPI (x/y): $xdpi / $ydpi")
// 计算屏幕物理尺寸(英寸)
val screenWidthInches = screenWidthPx / xdpi
val screenHeightInches = screenHeightPx / ydpi
val diagonalInches = sqrt(
(screenWidthInches * screenWidthInches + screenHeightInches * screenHeightInches).toDouble()
)
Timber.d(
"屏幕物理尺寸(英寸): %.1f x %.1f (对角线: %.1f\")".format(
screenWidthInches, screenHeightInches, diagonalInches
)
)
}
}