新增图片发送

This commit is contained in:
2024-10-09 23:49:20 +08:00
parent ce606e090b
commit ea26d67b90
6 changed files with 270 additions and 52 deletions

View File

@@ -1,5 +1,10 @@
package com.aiosman.riderpro.ui.chat package com.aiosman.riderpro.ui.chat
import android.app.Activity
import android.content.Intent
import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.Crossfade import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
@@ -29,6 +34,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Icon
import androidx.compose.material.Scaffold import androidx.compose.material.Scaffold
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -66,6 +72,7 @@ import com.aiosman.riderpro.exp.formatChatTime
import com.aiosman.riderpro.ui.composables.CustomAsyncImage import com.aiosman.riderpro.ui.composables.CustomAsyncImage
import com.aiosman.riderpro.ui.composables.StatusBarSpacer import com.aiosman.riderpro.ui.composables.StatusBarSpacer
import com.aiosman.riderpro.ui.modifiers.noRippleClickable import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import com.tencent.imsdk.v2.V2TIMMessage
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -158,7 +165,13 @@ fun ChatScreen(userId: String) {
.background(Color(0xfff7f7f7)) .background(Color(0xfff7f7f7))
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
ChatInput() { ChatInput(
onSendImage = {
it?.let {
viewModel.sendImageMessage(it, context)
}
},
) {
viewModel.sendMessage(it, context) viewModel.sendMessage(it, context)
} }
} }
@@ -230,17 +243,35 @@ fun ChatSelfItem(item: ChatItem) {
.padding(vertical = 8.dp, horizontal = 16.dp) .padding(vertical = 8.dp, horizontal = 16.dp)
.padding(bottom = 3.dp) .padding(bottom = 3.dp)
) { ) {
when (item.messageType) {
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
Text( Text(
text = item.message, text = item.message,
style = TextStyle( style = TextStyle(
color = Color.White, color = Color.White,
fontSize = 16.sp, fontSize = 16.sp,
), ),
textAlign = TextAlign.Start, textAlign = TextAlign.Start
) )
} }
V2TIMMessage.V2TIM_ELEM_TYPE_IMAGE -> {
CustomAsyncImage(
imageUrl = item.imageList[1].url,
modifier = Modifier.fillMaxSize(),
contentDescription = "image"
)
}
else -> {
Text(
text = "Unsupported message type",
style = TextStyle(
color = Color.White,
fontSize = 16.sp,
)
)
}
}
}
} }
Spacer(modifier = Modifier.width(12.dp)) Spacer(modifier = Modifier.width(12.dp))
Box( Box(
@@ -308,14 +339,35 @@ fun ChatOtherItem(item: ChatItem) {
.padding(vertical = 8.dp, horizontal = 16.dp) .padding(vertical = 8.dp, horizontal = 16.dp)
.padding(bottom = 3.dp) .padding(bottom = 3.dp)
) { ) {
when (item.messageType) {
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
Text( Text(
text = item.message, text = item.message,
style = TextStyle( style = TextStyle(
color = Color.Black, color = Color.Black,
fontSize = 16.sp fontSize = 16.sp,
),
textAlign = TextAlign.Start
)
}
V2TIMMessage.V2TIM_ELEM_TYPE_IMAGE -> {
CustomAsyncImage(
imageUrl = item.imageList[1].url,
modifier = Modifier.fillMaxSize(),
contentDescription = "image"
)
}
else -> {
Text(
text = "Unsupported message type",
style = TextStyle(
color = Color.White,
fontSize = 16.sp,
) )
) )
} }
}
}
} }
} }
@@ -335,7 +387,8 @@ fun ChatItem(item: ChatItem, currentUserId: String) {
@Composable @Composable
fun ChatInput( fun ChatInput(
onSend: (String) -> Unit = {} onSendImage: (Uri?) -> Unit = {},
onSend: (String) -> Unit = {},
) { ) {
val navigationBarHeight = with(LocalDensity.current) { val navigationBarHeight = with(LocalDensity.current) {
WindowInsets.navigationBars.getBottom(this).toDp() WindowInsets.navigationBars.getBottom(this).toDp()
@@ -367,6 +420,15 @@ fun ChatInput(
} }
} }
val imagePickUpLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
) {
if (it.resultCode == Activity.RESULT_OK) {
val uri = it.data?.data
onSendImage(uri)
}
}
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -413,6 +475,24 @@ fun ChatInput(
) )
} }
Spacer(modifier = Modifier.width(16.dp)) Spacer(modifier = Modifier.width(16.dp))
Icon(
painter = painterResource(id = R.drawable.rider_pro_images),
contentDescription = "Emoji",
modifier = Modifier
.size(32.dp)
.noRippleClickable {
imagePickUpLauncher.launch(
Intent.createChooser(
Intent(Intent.ACTION_GET_CONTENT).apply {
type = "image/*"
},
"Select Image"
)
)
},
tint = Color(0xff000000)
)
Spacer(modifier = Modifier.width(8.dp))
Crossfade(targetState = text.isNotEmpty(), animationSpec = tween(500)) { isNotEmpty -> Crossfade(targetState = text.isNotEmpty(), animationSpec = tween(500)) { isNotEmpty ->
Image( Image(
painter = rememberUpdatedState( painter = rememberUpdatedState(

View File

@@ -2,7 +2,10 @@ package com.aiosman.riderpro.ui.chat
import android.content.Context import android.content.Context
import android.icu.util.Calendar import android.icu.util.Calendar
import android.net.Uri
import android.provider.MediaStore
import android.util.Log import android.util.Log
import android.webkit.MimeTypeMap
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
@@ -16,11 +19,15 @@ import com.aiosman.riderpro.entity.AccountProfileEntity
import com.aiosman.riderpro.exp.formatChatTime import com.aiosman.riderpro.exp.formatChatTime
import com.tencent.imsdk.v2.V2TIMAdvancedMsgListener import com.tencent.imsdk.v2.V2TIMAdvancedMsgListener
import com.tencent.imsdk.v2.V2TIMCallback import com.tencent.imsdk.v2.V2TIMCallback
import com.tencent.imsdk.v2.V2TIMImageElem
import com.tencent.imsdk.v2.V2TIMManager import com.tencent.imsdk.v2.V2TIMManager
import com.tencent.imsdk.v2.V2TIMMessage import com.tencent.imsdk.v2.V2TIMMessage
import com.tencent.imsdk.v2.V2TIMSendCallback import com.tencent.imsdk.v2.V2TIMSendCallback
import com.tencent.imsdk.v2.V2TIMValueCallback import com.tencent.imsdk.v2.V2TIMValueCallback
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
data class ChatItem( data class ChatItem(
@@ -30,7 +37,10 @@ data class ChatItem(
val userId: String, val userId: String,
val nickname: String, val nickname: String,
val timeCategory: String = "", val timeCategory: String = "",
val timestamp: Long = 0 val timestamp: Long = 0,
val imageList: MutableList<V2TIMImageElem.V2TIMImage> = emptyList<V2TIMImageElem.V2TIMImage>().toMutableList(),
val messageType : Int = 0,
val textDisplay : String = ""
) )
class ChatViewModel( class ChatViewModel(
@@ -61,7 +71,12 @@ class ChatViewModel(
textMessageListener = object : V2TIMAdvancedMsgListener() { textMessageListener = object : V2TIMAdvancedMsgListener() {
override fun onRecvNewMessage(msg: V2TIMMessage?) { override fun onRecvNewMessage(msg: V2TIMMessage?) {
super.onRecvNewMessage(msg) super.onRecvNewMessage(msg)
chatData = listOf(convertToChatItem(msg!!, context)) + chatData msg?.let {
val chatItem = convertToChatItem(msg, context)
chatItem?.let {
chatData = listOf(it) + chatData
}
}
} }
} }
V2TIMManager.getMessageManager().addAdvancedMsgListener(textMessageListener); V2TIMManager.getMessageManager().addAdvancedMsgListener(textMessageListener);
@@ -70,6 +85,7 @@ class ChatViewModel(
fun UnRegistListener() { fun UnRegistListener() {
V2TIMManager.getMessageManager().removeAdvancedMsgListener(textMessageListener); V2TIMManager.getMessageManager().removeAdvancedMsgListener(textMessageListener);
} }
fun clearUnRead() { fun clearUnRead() {
val conversationID = "c2c_${userProfile?.trtcUserId}" val conversationID = "c2c_${userProfile?.trtcUserId}"
V2TIMManager.getConversationManager() V2TIMManager.getConversationManager()
@@ -83,7 +99,8 @@ class ChatViewModel(
} }
}) })
} }
fun convertToChatItem(message: V2TIMMessage, context: Context): ChatItem {
fun convertToChatItem(message: V2TIMMessage, context: Context): ChatItem? {
val avatar = if (message.sender == userProfile?.trtcUserId) { val avatar = if (message.sender == userProfile?.trtcUserId) {
userProfile?.avatar ?: "" userProfile?.avatar ?: ""
} else { } else {
@@ -97,16 +114,51 @@ class ChatViewModel(
val timestamp = message.timestamp val timestamp = message.timestamp
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
calendar.timeInMillis = timestamp * 1000 calendar.timeInMillis = timestamp * 1000
val imageElm = message.imageElem?.imageList
when (message.elemType) {
V2TIMMessage.V2TIM_ELEM_TYPE_IMAGE -> {
val imageElm = message.imageElem?.imageList?.all {
it.size == 0
}
if (imageElm != true) {
return ChatItem( return ChatItem(
message = message.textElem.text, message = "Image",
avatar = avatar, avatar = avatar,
time = calendar.time.formatChatTime(context), time = calendar.time.formatChatTime(context),
userId = message.sender, userId = message.sender,
nickname = nickname, nickname = nickname,
timestamp = timestamp * 1000 timestamp = timestamp * 1000,
imageList = message.imageElem?.imageList
?: emptyList<V2TIMImageElem.V2TIMImage>().toMutableList(),
messageType = V2TIMMessage.V2TIM_ELEM_TYPE_IMAGE,
textDisplay = "Image"
) )
} }
return null
}
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
return ChatItem(
message = message.textElem?.text ?: "Unsupported message type",
avatar = avatar,
time = calendar.time.formatChatTime(context),
userId = message.sender,
nickname = nickname,
timestamp = timestamp * 1000,
imageList = imageElm?.toMutableList()
?: emptyList<V2TIMImageElem.V2TIMImage>().toMutableList(),
messageType = V2TIMMessage.V2TIM_ELEM_TYPE_TEXT,
textDisplay = message.textElem?.text ?: "Unsupported message type"
)
}
else -> {
return null
}
}
}
fun onLoadMore(context: Context) { fun onLoadMore(context: Context) {
if (!hasMore || isLoading) { if (!hasMore || isLoading) {
@@ -122,7 +174,7 @@ class ChatViewModel(
override fun onSuccess(p0: List<V2TIMMessage>?) { override fun onSuccess(p0: List<V2TIMMessage>?) {
chatData = chatData + (p0 ?: emptyList()).map { chatData = chatData + (p0 ?: emptyList()).map {
convertToChatItem(it, context) convertToChatItem(it, context)
} }.filterNotNull()
if ((p0?.size ?: 0) < 20) { if ((p0?.size ?: 0) < 20) {
hasMore = false hasMore = false
} }
@@ -130,6 +182,7 @@ class ChatViewModel(
isLoading = false isLoading = false
Log.d("ChatViewModel", "fetch history message success") Log.d("ChatViewModel", "fetch history message success")
} }
override fun onError(p0: Int, p1: String?) { override fun onError(p0: Int, p1: String?) {
Log.e("ChatViewModel", "fetch history message error: $p1") Log.e("ChatViewModel", "fetch history message error: $p1")
isLoading = false isLoading = false
@@ -147,18 +200,85 @@ class ChatViewModel(
override fun onProgress(p0: Int) { override fun onProgress(p0: Int) {
} }
override fun onError(p0: Int, p1: String?) { override fun onError(p0: Int, p1: String?) {
Log.e("ChatViewModel", "send message error: $p1") Log.e("ChatViewModel", "send message error: $p1")
} }
override fun onSuccess(p0: V2TIMMessage?) { override fun onSuccess(p0: V2TIMMessage?) {
Log.d("ChatViewModel", "send message success") Log.d("ChatViewModel", "send message success")
chatData = listOf(convertToChatItem(p0!!, context)) + chatData val chatItem = convertToChatItem(p0!!, context)
chatItem?.let {
chatData = listOf(it) + chatData
}
} }
} }
) )
} }
fun sendImageMessage(imageUri:Uri, context: Context) {
val tempFile = createTempFile(context, imageUri)
val imagePath = tempFile?.path
if (imagePath != null) {
val v2TIMMessage = V2TIMManager.getMessageManager().createImageMessage(imagePath)
V2TIMManager.getMessageManager().sendMessage(
v2TIMMessage,
userProfile?.trtcUserId!!,
null,
V2TIMMessage.V2TIM_PRIORITY_NORMAL,
false,
null,
object : V2TIMSendCallback<V2TIMMessage> {
override fun onProgress(p0: Int) {
Log.d("ChatViewModel", "send image message progress: $p0")
}
override fun onError(p0: Int, p1: String?) {
Log.e("ChatViewModel", "send image message error: $p1")
}
override fun onSuccess(p0: V2TIMMessage?) {
Log.d("ChatViewModel", "send image message success")
val chatItem = convertToChatItem(p0!!, context)
chatItem?.let {
chatData = listOf(it) + chatData
}
}
}
)
}
}
fun createTempFile(context: Context, uri: Uri): File? {
return try {
val projection = arrayOf(MediaStore.Images.Media.DATA)
val cursor = context.contentResolver.query(uri, projection, null, null, null)
cursor?.use {
if (it.moveToFirst()) {
val columnIndex = it.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
val filePath = it.getString(columnIndex)
val inputStream: InputStream? = context.contentResolver.openInputStream(uri)
val mimeType = context.contentResolver.getType(uri)
val extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType)
val tempFile = File.createTempFile("temp_image", ".$extension", context.cacheDir)
val outputStream = FileOutputStream(tempFile)
inputStream?.use { input ->
outputStream.use { output ->
input.copyTo(output)
}
}
tempFile
} else {
null
}
}
} catch (e: Exception) {
e.printStackTrace()
null
}
}
fun fetchHistoryMessage(context: Context) { fun fetchHistoryMessage(context: Context) {
V2TIMManager.getMessageManager().getC2CHistoryMessageList( V2TIMManager.getMessageManager().getC2CHistoryMessageList(
userProfile?.trtcUserId!!, userProfile?.trtcUserId!!,
@@ -168,7 +288,7 @@ class ChatViewModel(
override fun onSuccess(p0: List<V2TIMMessage>?) { override fun onSuccess(p0: List<V2TIMMessage>?) {
chatData = (p0 ?: emptyList()).map { chatData = (p0 ?: emptyList()).map {
convertToChatItem(it, context) convertToChatItem(it, context)
} }.filterNotNull()
if ((p0?.size ?: 0) < 20) { if ((p0?.size ?: 0) < 20) {
hasMore = false hasMore = false
} }
@@ -182,6 +302,7 @@ class ChatViewModel(
} }
) )
} }
fun getDisplayChatList(): List<ChatItem> { fun getDisplayChatList(): List<ChatItem> {
return chatData return chatData
} }

View File

@@ -1,4 +1,3 @@
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@@ -21,7 +20,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.Icon import androidx.compose.material.Icon
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -46,7 +44,7 @@ import com.aiosman.riderpro.ui.composables.CustomAsyncImage
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
import com.aiosman.riderpro.ui.imageviewer.ImageViewerViewModel import com.aiosman.riderpro.ui.imageviewer.ImageViewerViewModel
import com.aiosman.riderpro.ui.modifiers.noRippleClickable import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import com.aiosman.riderpro.utils.File.saveImageToGallery import com.aiosman.riderpro.utils.FileUtil.saveImageToGallery
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.engawapg.lib.zoomable.rememberZoomState import net.engawapg.lib.zoomable.rememberZoomState
import net.engawapg.lib.zoomable.zoomable import net.engawapg.lib.zoomable.zoomable

View File

@@ -304,7 +304,7 @@ fun ChatMessageList(
Spacer(modifier = Modifier.height(6.dp)) Spacer(modifier = Modifier.height(6.dp))
Row { Row {
Text( Text(
text = item.lastMessage, text = "${if (item.isSelf) "Me: " else ""}${item.displayText}",
fontSize = 14.sp, fontSize = 14.sp,
maxLines = 1, maxLines = 1,
color = Color(0x99000000), color = Color(0x99000000),

View File

@@ -9,32 +9,25 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData import androidx.paging.PagingData
import androidx.paging.cachedIn
import androidx.paging.map import androidx.paging.map
import com.aiosman.riderpro.data.AccountNotice import com.aiosman.riderpro.data.AccountNotice
import com.aiosman.riderpro.data.AccountService import com.aiosman.riderpro.data.AccountService
import com.aiosman.riderpro.entity.CommentEntity import com.aiosman.riderpro.entity.CommentEntity
import com.aiosman.riderpro.entity.CommentPagingSource
import com.aiosman.riderpro.data.CommentRemoteDataSource
import com.aiosman.riderpro.data.CommentService
import com.aiosman.riderpro.data.AccountServiceImpl import com.aiosman.riderpro.data.AccountServiceImpl
import com.aiosman.riderpro.data.CommentServiceImpl
import com.aiosman.riderpro.data.UserService import com.aiosman.riderpro.data.UserService
import com.aiosman.riderpro.data.UserServiceImpl import com.aiosman.riderpro.data.UserServiceImpl
import com.aiosman.riderpro.exp.formatChatTime import com.aiosman.riderpro.exp.formatChatTime
import com.aiosman.riderpro.ui.NavigationRoute import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.index.tabs.profile.MyProfileViewModel
import com.aiosman.riderpro.ui.navigateToChat import com.aiosman.riderpro.ui.navigateToChat
import com.aiosman.riderpro.utils.TrtcHelper import com.aiosman.riderpro.utils.TrtcHelper
import com.tencent.imsdk.v2.V2TIMConversation import com.tencent.imsdk.v2.V2TIMConversation
import com.tencent.imsdk.v2.V2TIMConversationResult import com.tencent.imsdk.v2.V2TIMConversationResult
import com.tencent.imsdk.v2.V2TIMManager import com.tencent.imsdk.v2.V2TIMManager
import com.tencent.imsdk.v2.V2TIMMessage
import com.tencent.imsdk.v2.V2TIMValueCallback import com.tencent.imsdk.v2.V2TIMValueCallback
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.coroutines.suspendCoroutine import kotlin.coroutines.suspendCoroutine
@@ -44,7 +37,9 @@ data class Conversation(
val lastMessage: String, val lastMessage: String,
val lastMessageTime: String, val lastMessageTime: String,
val avatar: String = "", val avatar: String = "",
val unreadCount: Int = 0 val unreadCount: Int = 0,
val displayText: String,
val isSelf: Boolean
) )
object MessageListViewModel : ViewModel() { object MessageListViewModel : ViewModel() {
@@ -142,13 +137,24 @@ object MessageListViewModel : ViewModel() {
timeInMillis = msg.lastMessage?.timestamp ?: 0 timeInMillis = msg.lastMessage?.timestamp ?: 0
timeInMillis *= 1000 timeInMillis *= 1000
} }
var displayText = ""
when (msg.lastMessage?.elemType) {
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
displayText = msg.lastMessage?.textElem?.text ?: ""
}
V2TIMMessage.V2TIM_ELEM_TYPE_IMAGE -> {
displayText = "[图片]"
}
}
Conversation( Conversation(
nickname = msg.showName, nickname = msg.showName,
lastMessage = msg.lastMessage?.textElem?.text ?: "", lastMessage = msg.lastMessage?.textElem?.text ?: "",
lastMessageTime = lastMessage.time.formatChatTime(context), lastMessageTime = lastMessage.time.formatChatTime(context),
avatar = msg.faceUrl, avatar = msg.faceUrl,
unreadCount = msg.unreadCount, unreadCount = msg.unreadCount,
trtcUserId = msg.userID trtcUserId = msg.userID,
displayText = displayText,
isSelf = msg.lastMessage.sender == MyProfileViewModel.profile?.trtcUserId
) )
} ?: emptyList() } ?: emptyList()
} }

View File

@@ -2,6 +2,7 @@ package com.aiosman.riderpro.utils
import android.content.ContentValues import android.content.ContentValues
import android.content.Context import android.content.Context
import android.database.Cursor
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
import android.net.Uri import android.net.Uri
@@ -9,7 +10,6 @@ import android.os.Build
import android.os.Environment import android.os.Environment
import android.provider.MediaStore import android.provider.MediaStore
import android.widget.Toast import android.widget.Toast
import coil.ImageLoader
import coil.request.ImageRequest import coil.request.ImageRequest
import coil.request.SuccessResult import coil.request.SuccessResult
import com.aiosman.riderpro.utils.Utils.getImageLoader import com.aiosman.riderpro.utils.Utils.getImageLoader
@@ -18,7 +18,7 @@ import kotlinx.coroutines.withContext
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.io.OutputStream import java.io.OutputStream
object File { object FileUtil {
suspend fun saveImageToGallery(context: Context, url: String) { suspend fun saveImageToGallery(context: Context, url: String) {
val loader = getImageLoader(context) val loader = getImageLoader(context)
@@ -89,4 +89,17 @@ object File {
} }
} }
fun getRealPathFromUri(context: Context, uri: Uri): String? {
var realPath: String? = null
val projection = arrayOf(MediaStore.Images.Media.DATA)
val cursor: Cursor? = context.contentResolver.query(uri, projection, null, null, null)
cursor?.use {
if (it.moveToFirst()) {
val columnIndex = it.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
realPath = it.getString(columnIndex)
}
}
return realPath
}
} }