问题修正

This commit is contained in:
2024-10-23 20:32:32 +08:00
parent 6cb19eb6cf
commit dad032e233
5 changed files with 128 additions and 31 deletions

View File

@@ -0,0 +1,9 @@
package com.aiosman.riderpro.exp
import android.graphics.Bitmap
fun Bitmap.rotate(degree: Int): Bitmap {
val matrix = android.graphics.Matrix()
matrix.postRotate(degree.toFloat())
return Bitmap.createBitmap(this, 0, 0, this.width, this.height, matrix, true)
}

View File

@@ -7,7 +7,6 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@@ -45,7 +44,6 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.PathEffect import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
@@ -232,16 +230,18 @@ fun AddImageGrid() {
val navController = LocalNavController.current val navController = LocalNavController.current
val context = LocalContext.current val context = LocalContext.current
val model = NewPostViewModel val model = NewPostViewModel
val scope = model.viewModelScope
val pickImagesLauncher = rememberLauncherForActivityResult( val pickImagesLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.GetMultipleContents() contract = ActivityResultContracts.GetMultipleContents()
) { uris -> ) { uris ->
if (uris.isNotEmpty()) { if (uris.isNotEmpty()) {
model.imageList += uris.map { scope.launch {
ImageItem( for (uri in uris) {
uri = it.toString(), ImageItem.fromUri(context, uri.toString())?.let {
id = java.util.UUID.randomUUID().toString() model.imageList += it
)
}
}
} }
} }
} }
@@ -250,10 +250,12 @@ fun AddImageGrid() {
contract = ActivityResultContracts.TakePicture() contract = ActivityResultContracts.TakePicture()
) { success -> ) { success ->
if (success) { if (success) {
model.imageList += ImageItem( scope.launch {
uri = model.currentPhotoUri.toString(), ImageItem.fromUri(context, model.currentPhotoUri.toString())?.let {
id = java.util.UUID.randomUUID().toString() model.imageList += it
) }
}
} }
} }
@@ -283,7 +285,7 @@ fun AddImageGrid() {
) { ) {
CustomAsyncImage( CustomAsyncImage(
LocalContext.current, LocalContext.current,
item.uri, item.bitmap,
contentDescription = "Image", contentDescription = "Image",
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -320,7 +322,8 @@ fun AddImageGrid() {
val strokeWidth = 1.dp.toPx() val strokeWidth = 1.dp.toPx()
val dashLength = 10f val dashLength = 10f
val dashGap = 10f val dashGap = 10f
val pathEffect = PathEffect.dashPathEffect(floatArrayOf(dashLength, dashGap)) val pathEffect =
PathEffect.dashPathEffect(floatArrayOf(dashLength, dashGap))
drawRoundRect( drawRoundRect(
color = Color(0xFFD6D6D6), color = Color(0xFFD6D6D6),
style = Stroke(strokeWidth, pathEffect = pathEffect), style = Stroke(strokeWidth, pathEffect = pathEffect),
@@ -351,7 +354,8 @@ fun AddImageGrid() {
val strokeWidth = 1.dp.toPx() val strokeWidth = 1.dp.toPx()
val dashLength = 10f val dashLength = 10f
val dashGap = 10f val dashGap = 10f
val pathEffect = PathEffect.dashPathEffect(floatArrayOf(dashLength, dashGap)) val pathEffect =
PathEffect.dashPathEffect(floatArrayOf(dashLength, dashGap))
drawRoundRect( drawRoundRect(
color = Color(0xFFD6D6D6), color = Color(0xFFD6D6D6),
style = Stroke(strokeWidth, pathEffect = pathEffect), style = Stroke(strokeWidth, pathEffect = pathEffect),

View File

@@ -103,7 +103,7 @@ fun NewPostImageGridScreen() {
) { page -> ) { page ->
val imageUrl = imageList[page] val imageUrl = imageList[page]
Image( Image(
painter = rememberAsyncImagePainter(model = imageUrl), painter = rememberAsyncImagePainter(model = imageUrl.bitmap),
contentDescription = "Image $page", contentDescription = "Image $page",
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) )

View File

@@ -1,6 +1,9 @@
package com.aiosman.riderpro.ui.post package com.aiosman.riderpro.ui.post
import android.content.Context import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.media.ExifInterface
import android.net.Uri import android.net.Uri
import android.util.Log import android.util.Log
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -11,20 +14,70 @@ import com.aiosman.riderpro.data.MomentService
import com.aiosman.riderpro.entity.MomentServiceImpl import com.aiosman.riderpro.entity.MomentServiceImpl
import com.aiosman.riderpro.data.UploadImage import com.aiosman.riderpro.data.UploadImage
import com.aiosman.riderpro.entity.MomentEntity import com.aiosman.riderpro.entity.MomentEntity
import com.aiosman.riderpro.exp.rotate
import com.aiosman.riderpro.ui.index.tabs.moment.MomentViewModel import com.aiosman.riderpro.ui.index.tabs.moment.MomentViewModel
import com.aiosman.riderpro.ui.index.tabs.profile.MyProfileViewModel import com.aiosman.riderpro.ui.index.tabs.profile.MyProfileViewModel
import com.aiosman.riderpro.ui.modification.Modification import com.aiosman.riderpro.ui.modification.Modification
import com.aiosman.riderpro.utils.FileUtil
import com.aiosman.riderpro.utils.Utils
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.util.UUID import java.util.UUID
data class ImageItem( data class ImageItem(
val uri: String, val uri: String,
val id: String val id: String,
) val bitmap: Bitmap,
val file: File
) {
companion object {
suspend fun fromUri(context: Context,uri: String): ImageItem? {
// 保存图片文件到临时文件夹
context.contentResolver.openInputStream(Uri.parse(uri))?.use { inputStream ->
val tempFileName = UUID.randomUUID().toString()
val tempFile = File.createTempFile(tempFileName, null, context.cacheDir)
FileOutputStream(tempFile).use { outputStream ->
inputStream.copyTo(outputStream)
}
// 读取图片文件为 Bitmap
var bitmap = BitmapFactory.decodeFile(tempFile.absolutePath)
// 读取文件exif修正旋转
val exif = ExifInterface(tempFile.absolutePath)
bitmap = when (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)) {
ExifInterface.ORIENTATION_ROTATE_90 -> bitmap.rotate(90)
ExifInterface.ORIENTATION_ROTATE_180 -> bitmap.rotate(180)
ExifInterface.ORIENTATION_ROTATE_270 -> bitmap.rotate(270)
else -> bitmap
}
// 保存 bitmap 到临时文件夹
try {
val savedBitmapFilename = UUID.randomUUID().toString()
val bitmapFile = File.createTempFile(savedBitmapFilename, ".jpg", context.cacheDir)
FileOutputStream(bitmapFile).use { os ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os)
}
// 清理临时文件
tempFile.delete()
return ImageItem(
Uri.fromFile(bitmapFile).toString(),
savedBitmapFilename,
bitmap,
bitmapFile
)
} catch (e: IOException) {
Log.e("NewPost", "Failed to save bitmap to file", e)
null
}
}
return null
}
}
}
object NewPostViewModel : ViewModel() { object NewPostViewModel : ViewModel() {
var momentService: MomentService = MomentServiceImpl() var momentService: MomentService = MomentServiceImpl()
@@ -42,13 +95,14 @@ object NewPostViewModel : ViewModel() {
imageList = listOf() imageList = listOf()
relPostId = null relPostId = null
} }
fun asNewPostWithImageUris(imageUris: List<String>) { fun asNewPostWithImageUris(imageUris: List<String>) {
textContent = "" textContent = ""
searchPlaceAddressResult = null searchPlaceAddressResult = null
modificationList = listOf() modificationList = listOf()
imageList = imageUris.map { // imageList = imageUris.map {
ImageItem(it, UUID.randomUUID().toString()) // ImageItem(it, UUID.randomUUID().toString())
} // }
relPostId = null relPostId = null
} }
@@ -71,22 +125,34 @@ object NewPostViewModel : ViewModel() {
} }
return null return null
} }
suspend fun createMoment(context: Context, onUploadProgress: (Float) -> Unit) { suspend fun createMoment(context: Context, onUploadProgress: (Float) -> Unit) {
val uploadImageList = emptyList<UploadImage>().toMutableList() val uploadImageList = emptyList<UploadImage>().toMutableList()
var index = 0 var index = 0
for (item in imageList) { for (item in imageList) {
val cursor = context.contentResolver.query(Uri.parse(item.uri), null, null, null, null) val cursor = context.contentResolver.query(Uri.parse(item.uri), null, null, null, null)
cursor?.use { // cursor?.use {
if (it.moveToFirst()) { // if (it.moveToFirst()) {
val displayName = it.getString(it.getColumnIndex("_display_name")) // val columnIndex = it.getColumnIndex("_display_name")
val extension = displayName.substringAfterLast(".") // if (columnIndex != -1) {
Log.d("NewPost", "File name: $displayName, extension: $extension") // val displayName = it.getString(columnIndex)
// read as file // val extension = displayName.substringAfterLast(".")
val file = uriToFile(context, Uri.parse(item.uri)) // Log.d("NewPost", "File name: $displayName, extension: $extension")
Log.d("NewPost", "File size: ${file.length()}") // // read as file
uploadImageList += UploadImage(file, displayName, item.uri, extension) // val file = uriToFile(context, Uri.parse(item.uri))
// Log.d("NewPost", "File size: ${file.length()}")
// uploadImageList += UploadImage(file, displayName, item.uri, extension)
// }
// }
// }
// 保存图片到本地
FileUtil.bitmapToJPG(context, item.bitmap, UUID.randomUUID().toString())
?.let { savedImageUri ->
// 读取保存的图片文件
uriToFile(context, savedImageUri).let { file ->
uploadImageList += UploadImage(file, file.name, item.uri, "jpg")
}
} }
}
// 在上传过程中调用 onUploadProgress 更新进度 // 在上传过程中调用 onUploadProgress 更新进度
onUploadProgress(((index / imageList.size).toFloat())) // progressValue 是当前上传进度,例如 0.5 表示 50% onUploadProgress(((index / imageList.size).toFloat())) // progressValue 是当前上传进度,例如 0.5 表示 50%
index += 1 index += 1
@@ -95,6 +161,7 @@ object NewPostViewModel : ViewModel() {
// 刷新个人动态 // 刷新个人动态
MyProfileViewModel.loadProfile(pullRefresh = true) MyProfileViewModel.loadProfile(pullRefresh = true)
MomentViewModel.refreshPager() MomentViewModel.refreshPager()
} }
suspend fun init() { suspend fun init() {
@@ -103,6 +170,7 @@ object NewPostViewModel : ViewModel() {
relMoment = moment relMoment = moment
} }
} }
fun deleteImage(index: Int) { fun deleteImage(index: Int) {
imageList = imageList.toMutableList().apply { imageList = imageList.toMutableList().apply {
removeAt(index) removeAt(index)

View File

@@ -15,7 +15,10 @@ import coil.request.SuccessResult
import com.aiosman.riderpro.utils.Utils.getImageLoader import com.aiosman.riderpro.utils.Utils.getImageLoader
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.IOException
import java.io.OutputStream import java.io.OutputStream
object FileUtil { object FileUtil {
@@ -102,4 +105,17 @@ object FileUtil {
return realPath return realPath
} }
suspend fun bitmapToJPG(context: Context, bitmap: Bitmap, displayName: String): Uri? {
return withContext(Dispatchers.IO) {
try {
val tempFile = File.createTempFile(displayName, ".jpg", context.cacheDir)
FileOutputStream(tempFile).use { os ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os)
}
Uri.fromFile(tempFile)
} catch (e: IOException) {
null
}
}
}
} }