This commit is contained in:
Eric85710 2026-06-09 15:56:32 +08:00
parent 6d9c94b12e
commit aee829876f
2 changed files with 40 additions and 8 deletions

View file

@ -374,18 +374,41 @@ class ChatRoomsRepository @Inject constructor(
} }
} }
// 刪除訊息
// 刪除訊息(樂觀更新版本)
suspend fun deleteMessage(roomId: String, messageId: String): Result<Unit> { suspend fun deleteMessage(roomId: String, messageId: String): Result<Unit> {
// 1. 先從本地資料庫撈出原本的訊息作為備份
val backupEntity = try {
messageDao.getMessageById(messageId)
} catch (e: Exception) {
null // 如果本地查詢就失敗,雖然機率極低,但我們還是設為 null 防呆
}
// 2. 樂觀更新:立刻從本地砍掉,UI 的 Flow 會在「一瞬間」同步消失,體驗極佳
try {
messageDao.deleteById(messageId)
} catch (e: Exception) {
// 如果本地 Room 刪除指令本身就失敗,直接回傳錯誤,不繼續往下戳 API
return Result.failure(e)
}
// 3. 呼叫後端 API 進行實際刪除
return try { return try {
val response = api.deleteMessage(roomId, messageId) val response = api.deleteMessage(roomId, messageId)
if (response.isSuccessful) { if (response.isSuccessful) {
// 💡 既然刪除了,本地也一併砍掉,UI 就會立刻同步消失 // 真正成功了!因為本地已經提早刪除了,所以什麼都不用做,直接回傳 Unit
messageDao.deleteById(messageId)
Result.success(Unit) Result.success(Unit)
} else { } else {
Result.failure(Exception("Delete failed")) // 後端回報失敗(例如:沒權限、訊息已被他人刪除):把剛才備份的資料塞回去
backupEntity?.let { messageDao.insertOrUpdate(it) }
val errorMsg = response.errorBody()?.string() ?: "未知錯誤"
Result.failure(Exception("刪除失敗,錯誤碼: ${response.code()}, 訊息: $errorMsg"))
} }
} catch (e: Exception) { } catch (e: Exception) {
// 網路斷線、Timeout 或伺服器崩潰:一樣把備份資料塞回去,讓 UI 訊息彈回來
backupEntity?.let { messageDao.insertOrUpdate(it) }
Result.failure(e) Result.failure(e)
} }
} }

View file

@ -182,21 +182,30 @@ class ChatViewModel @Inject constructor(
// ===================================================================== // =====================================================================
// 💡 核心改造三:刪除訊息 // 💡 核心改造三:刪除訊息
// ===================================================================== // =====================================================================
// =====================================================================
// 💡 核心改造三:刪除訊息(配合樂觀更新優化)
// =====================================================================
fun deleteMessage(roomId: String, messageId: String) { fun deleteMessage(roomId: String, messageId: String) {
// 1. 🌟 樂觀更新的核心精神:立刻關閉長按選單(Action Menu)
// 因為訊息在下一行就會從資料庫消失,選單如果還開著會點不到東西或出錯
clearActionMessage()
viewModelScope.launch { viewModelScope.launch {
// 2. 💡 注意:這裡「不要」在 UI 顯示阻擋式的 Loading 轉圈圈。
// 這裡的 Loading 狀態只留在背景,或者用於特定的微小 UI 提示(例如標題列小藍點)。
_deleteMessageState.value = DeleteMessageState.Loading _deleteMessageState.value = DeleteMessageState.Loading
val result = repository.deleteMessage(roomId, messageId) val result = repository.deleteMessage(roomId, messageId)
result.onSuccess { result.onSuccess {
_deleteMessageState.value = DeleteMessageState.Success _deleteMessageState.value = DeleteMessageState.Success
clearActionMessage() // 🌟 刪除成功!本地早就不見了,Flow 也早已更新,這裡乾淨俐落。
// 🌟 刪除成功!Repository 已經把本地 Room 的資料刪除
// Flow 會自動發送全新的列表給 UI,這裡「完全不需要」再手動 map 改 content 了!
}.onFailure { error -> }.onFailure { error ->
Log.e("ChatViewModel", "Delete message failed", error) Log.e("ChatViewModel", "Delete message failed", error)
_deleteMessageState.value = DeleteMessageState.Error(error.message ?: "刪除訊息失敗") _deleteMessageState.value = DeleteMessageState.Error(error.message ?: "刪除訊息失敗")
// 3. 🌟 失敗處理:因為 Repository 把訊息彈回來了,我們可以讓 UI 知道
// 這裡可以透過監聽 deleteMessageState 的 Error,在 Activity/Fragment/Compose 彈出 Toast 提示:「刪除失敗,請檢查網路」
} }
} }
} }