This commit is contained in:
Eric85710 2026-06-08 10:52:49 +08:00
parent 0bafc1c04c
commit a50881a3e0
6 changed files with 40 additions and 47 deletions

View file

@ -2,10 +2,12 @@ package com.example.login_v3.data.di
import androidx.room.Database import androidx.room.Database
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.example.login_v3.home.Message.ViewModel.Detail.MessageDao import com.example.login_v3.home.Message.ViewModel.Detail.MessageDao
import com.example.login_v3.home.Message.ViewModel.Detail.MessageEntity import com.example.login_v3.home.Message.ViewModel.Detail.MessageEntity
@Database(entities = [MessageEntity::class], version = 1, exportSchema = false) @Database(entities = [MessageEntity::class], version = 1, exportSchema = false)
@TypeConverters(RoomConverters::class)
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
abstract fun messageDao(): MessageDao abstract fun messageDao(): MessageDao
} }

View file

@ -0,0 +1,27 @@
package com.example.login_v3.data.di
import androidx.room.TypeConverter
import com.example.login_v3.data.api.api_class.Reaction
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
class RoomConverters {
private val moshi = Moshi.Builder().build()
private val reactionListType = Types.newParameterizedType(List::class.java, Reaction::class.java)
private val adapter = moshi.adapter<List<Reaction>>(reactionListType)
@TypeConverter
fun fromReactionList(reactions: List<Reaction>?): String? {
return adapter.toJson(reactions ?: emptyList())
}
@TypeConverter
fun toReactionList(json: String?): List<Reaction>? {
if (json.isNullOrBlank()) return emptyList()
return try {
adapter.fromJson(json)
} catch (e: Exception) {
emptyList()
}
}
}

View file

@ -61,7 +61,8 @@ class ChatRoomsRepository @Inject constructor(
isEdited = entity.isEdited, isEdited = entity.isEdited,
isDeleted = entity.isDeleted, isDeleted = entity.isDeleted,
replyToId = entity.replyToId, replyToId = entity.replyToId,
status = entity.status // 👈 把 Room 儲存的狀態倒出來給 UI status = entity.status, // 👈 把 Room 儲存的狀態倒出來給 UI
reactions = entity.reactions
) )
} }
@ -94,7 +95,8 @@ class ChatRoomsRepository @Inject constructor(
isEdited = networkMessage.isEdited, isEdited = networkMessage.isEdited,
isDeleted = networkMessage.isDeleted, isDeleted = networkMessage.isDeleted,
replyToId = networkMessage.replyToId, replyToId = networkMessage.replyToId,
status = MessageStatus.SUCCESS // 後端來的都是真的發送成功的 status = MessageStatus.SUCCESS,
reactions = networkMessage.reactions
) )
messageDao.insertOrUpdate(entity) messageDao.insertOrUpdate(entity)
} }
@ -125,7 +127,8 @@ class ChatRoomsRepository @Inject constructor(
isEdited = false, isEdited = false,
isDeleted = false, isDeleted = false,
replyToId = replyToId, replyToId = replyToId,
status = MessageStatus.SENDING // 👈 畫面馬上呈現半透明淡灰色! status = MessageStatus.SENDING,
reactions = emptyList()
) )
messageDao.insertOrUpdate(tempMessageEntity) messageDao.insertOrUpdate(tempMessageEntity)
@ -150,7 +153,8 @@ class ChatRoomsRepository @Inject constructor(
isEdited = body.isEdited, isEdited = body.isEdited,
isDeleted = body.isDeleted, isDeleted = body.isDeleted,
replyToId = body.replyToId, replyToId = body.replyToId,
status = MessageStatus.SUCCESS status = MessageStatus.SUCCESS,
reactions = body.reactions
) )
messageDao.insertOrUpdate(successEntity) messageDao.insertOrUpdate(successEntity)
Result.success(Unit) Result.success(Unit)
@ -317,33 +321,6 @@ class ChatRoomsRepository @Inject constructor(
} }
} }
// 取得點擊特定訊息中某個 Emoji 的使用者清單
suspend fun getMessageReactionUsers(
roomId: String,
messageId: String,
emoji: String
): Result<MessageReactionUsersResponse> {
return try {
// 呼叫 API
val response = api.getMessageReactionUsers(roomId, messageId, emoji)
if (response.isSuccessful) {
val body = response.body()
if (body != null) {
Result.success(body)
} else {
Result.failure(Exception("回應成功但回應身體為空 (Empty response body)"))
}
} else {
val errorMsg = response.errorBody()?.string() ?: "未知錯誤"
Result.failure(Exception("取得反應使用者失敗,錯誤碼: ${response.code()}, 訊息: $errorMsg"))
}
} catch (e: Exception) {
// 捕捉網路斷線等異常狀況
Result.failure(e)
}
}
// 新增訊息的 Emoji 反應 // 新增訊息的 Emoji 反應
suspend fun addMessageReaction( suspend fun addMessageReaction(
roomId: String, roomId: String,

View file

@ -113,9 +113,6 @@ fun MessageMessaging(
//reply function //reply function
val replyingMessage by viewModel.replyingMessage.collectAsStateWithLifecycle() val replyingMessage by viewModel.replyingMessage.collectAsStateWithLifecycle()
// 💡 1. 取得 ViewModel 裡的 Reaction 狀態
val reactionState by viewModel.reactionUsersState.collectAsStateWithLifecycle()
//message that selected //message that selected
val actionMessage by viewModel.actionMessage.collectAsStateWithLifecycle() val actionMessage by viewModel.actionMessage.collectAsStateWithLifecycle()

View file

@ -7,6 +7,7 @@ import androidx.room.OnConflictStrategy
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import androidx.room.Query import androidx.room.Query
import com.example.login_v3.data.api.api_class.Reaction
enum class MessageStatus { SENDING, SUCCESS, FAILED } enum class MessageStatus { SENDING, SUCCESS, FAILED }
@ -21,7 +22,8 @@ data class MessageEntity(
val isEdited: Boolean, // 👈 新增 val isEdited: Boolean, // 👈 新增
val isDeleted: Boolean, // 👈 新增 val isDeleted: Boolean, // 👈 新增
val replyToId: String?, // 👈 新增 val replyToId: String?, // 👈 新增
val status: MessageStatus // 👈 樂觀更新狀態控制 (SENDING, SUCCESS, FAILED) val status: MessageStatus, // 👈 樂觀更新狀態控制 (SENDING, SUCCESS, FAILED)
val reactions: List<Reaction>?
) )
@Dao @Dao

View file

@ -223,17 +223,6 @@ class ChatViewModel @Inject constructor(
} }
} }
private val _reactionUsersState = MutableStateFlow<ReactionUsersState>(ReactionUsersState.Idle)
val reactionUsersState: StateFlow<ReactionUsersState> = _reactionUsersState.asStateFlow()
fun loadMessageReactionUsers(roomId: String, messageId: String, emoji: String) {
viewModelScope.launch {
_reactionUsersState.value = ReactionUsersState.Loading
repository.getMessageReactionUsers(roomId, messageId, emoji)
.onSuccess { response -> _reactionUsersState.value = ReactionUsersState.Success(response.users) }
.onFailure { error -> _reactionUsersState.value = ReactionUsersState.Error(error.message ?: "無法取得按讚名單") }
}
}
fun addMessageReaction(roomId: String, messageId: String, emoji: String) { fun addMessageReaction(roomId: String, messageId: String, emoji: String) {
viewModelScope.launch { viewModelScope.launch {
@ -255,6 +244,5 @@ class ChatViewModel @Inject constructor(
} }
fun resetDeleteMessageState() { _deleteMessageState.value = DeleteMessageState.Idle } fun resetDeleteMessageState() { _deleteMessageState.value = DeleteMessageState.Idle }
fun resetReactionUsersState() { _reactionUsersState.value = ReactionUsersState.Idle }
fun resetSendMessageState() { _sendMessageState.value = SendMessageState.Idle } fun resetSendMessageState() { _sendMessageState.value = SendMessageState.Idle }
} }