From 2ec5028b3e7ae2a537f3b4a45d743a9fae5d09f9 Mon Sep 17 00:00:00 2001 From: Eric85710 Date: Mon, 11 May 2026 15:22:56 +0800 Subject: [PATCH] auth to server-V80 --- .../login_v3/data/api/Main_API_Service.kt | 2 +- .../data/api/api_class/FriendRequest.kt | 19 +++++-- .../repository/basic/Friends_Repository.kt | 46 +++++++++------ .../Detail/Contact_list_ViewModel.kt | 56 ++++++++++--------- 4 files changed, 75 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/com/example/login_v3/data/api/Main_API_Service.kt b/app/src/main/java/com/example/login_v3/data/api/Main_API_Service.kt index 053d9f4..df8ef38 100644 --- a/app/src/main/java/com/example/login_v3/data/api/Main_API_Service.kt +++ b/app/src/main/java/com/example/login_v3/data/api/Main_API_Service.kt @@ -77,6 +77,6 @@ interface TecnologiaApi { @GET("api/users/search") suspend fun searchUsers( @Query("q") query: String - ): UserSearchResponse + ): Response } \ No newline at end of file diff --git a/app/src/main/java/com/example/login_v3/data/api/api_class/FriendRequest.kt b/app/src/main/java/com/example/login_v3/data/api/api_class/FriendRequest.kt index 79dff61..6adaf64 100644 --- a/app/src/main/java/com/example/login_v3/data/api/api_class/FriendRequest.kt +++ b/app/src/main/java/com/example/login_v3/data/api/api_class/FriendRequest.kt @@ -85,18 +85,29 @@ data class AddFriendRequest( ) //user search +@JsonClass(generateAdapter = true) data class UserSearchResponse( val count: Int, val users: List ) +@JsonClass(generateAdapter = true) // 內部類別也一定要加! data class UserDetail( val id: String, val username: String, - val display_name: String, - val avatar_url: String?, // 考慮到可能是 null,建議加上 ? - val banner_url: String?, + + @Json(name = "display_name") // 這樣你的 Kotlin 代碼可以用漂亮的 displayName + val displayName: String, + + @Json(name = "avatar_url") + val avatarUrl: String?, + + @Json(name = "banner_url") + val bannerUrl: String?, + val bio: String?, val status: String?, - val created_at: String + + @Json(name = "created_at") + val createdAt: String ) \ No newline at end of file diff --git a/app/src/main/java/com/example/login_v3/data/repository/basic/Friends_Repository.kt b/app/src/main/java/com/example/login_v3/data/repository/basic/Friends_Repository.kt index 2bf5321..9252d1e 100644 --- a/app/src/main/java/com/example/login_v3/data/repository/basic/Friends_Repository.kt +++ b/app/src/main/java/com/example/login_v3/data/repository/basic/Friends_Repository.kt @@ -6,6 +6,7 @@ import com.example.login_v3.data.api.api_class.AddFriendRequest import com.example.login_v3.data.api.api_class.Friend import com.example.login_v3.data.api.api_class.PendingFriendApiModel import com.example.login_v3.data.api.api_class.UserDetail +import com.example.login_v3.data.api.api_class.UserSearchResponse import retrofit2.Response import javax.inject.Inject @@ -58,6 +59,34 @@ class FriendsRepository @Inject constructor( return result } + + //search user + suspend fun searchUsers(query: String): Result { + return safeApiCallWithData { + apiService.searchUsers(query) // 1. 使用 apiService 2. 確保 apiService 定義回傳 Response + } + } + + // 支援「回傳資料」的通用封裝 for search user + private suspend fun safeApiCallWithData(call: suspend () -> Response): Result { + return try { + val response = call() + if (response.isSuccessful) { + val body = response.body() + if (body != null) { + Result.success(body) + } else { + Result.failure(Exception("回傳資料為空")) + } + } else { + val errorMsg = "API 錯誤 ${response.code()}: ${response.errorBody()?.string()}" + Result.failure(Exception(errorMsg)) + } + } catch (e: Exception) { + Result.failure(e) + } + } + // 2. 確保「全類別」只有這一個 safeApiCall 函式 private suspend fun safeApiCall(call: suspend () -> Response): Result { return try { @@ -78,21 +107,4 @@ class FriendsRepository @Inject constructor( } } - // 搜尋使用者 - suspend fun searchUsers(keyword: String): Result> { - return try { - val response = apiService.searchUsers(keyword) - - // 這裡做一個「結構轉換」 - // 假設 additionalProp1 裡面裝的是我們想要的資料 - // 如果 response.additionalProp1 是 Map,我們可以取其 Values 轉成 List - val userList = response.additionalProp1.values.toList() - - Result.success(userList) - } catch (e: Exception) { - Log.e("API_DEBUG", "搜尋失敗: ${e.message}") - Result.failure(e) - } - } - } \ No newline at end of file diff --git a/app/src/main/java/com/example/login_v3/home/Message/ViewModel/Detail/Contact_list_ViewModel.kt b/app/src/main/java/com/example/login_v3/home/Message/ViewModel/Detail/Contact_list_ViewModel.kt index b5ae73c..df92af2 100644 --- a/app/src/main/java/com/example/login_v3/home/Message/ViewModel/Detail/Contact_list_ViewModel.kt +++ b/app/src/main/java/com/example/login_v3/home/Message/ViewModel/Detail/Contact_list_ViewModel.kt @@ -119,42 +119,46 @@ class ContactListViewModel @Inject constructor( } } - private var searchJob: Job? = null + + //search user fun onSearchQueryChanged(newQuery: String) { - // 更新 UI 上的輸入文字 + // 1. 即時更新文字輸入,確保 UI TextField 顯示順暢 _uiState.update { it.copy(searchQuery = newQuery) } + } - // 如果關鍵字為空,清空搜尋結果並返回 - if (newQuery.isBlank()) { + fun performSearch() { + val query = _uiState.value.searchQuery + if (query.isBlank()) { + // 如果關鍵字為空,清空搜尋結果 _uiState.update { it.copy(searchResults = emptyList()) } return } - // --- 防抖處理 (Debounce) --- - searchJob?.cancel() // 取消前一個還在跑的搜尋 - searchJob = viewModelScope.launch { - delay(500) // 使用者停頓 0.5 秒後才真正發出請求 - performSearch(newQuery) - } - } + viewModelScope.launch { + // 2. 顯示 Loading + _uiState.update { it.copy(isLoading = true, error = null) } - private suspend fun performSearch(query: String) { - _uiState.update { it.copy(isLoading = true) } + // 3. 呼叫 Repository + val result = repository.searchUsers(query) - val result = repository.searchUsers(query) - - result.onSuccess { users -> - _uiState.update { it.copy( - isLoading = false, - searchResults = users, - error = null - )} - }.onFailure { error -> - _uiState.update { it.copy( - isLoading = false, - error = "搜尋失敗: ${error.message}" - )} + // 4. 處理結果 + result.onSuccess { response -> + _uiState.update { + it.copy( + isLoading = false, + searchResults = response.users // UserSearchResponse 裡的列表 + ) + } + }.onFailure { error -> + _uiState.update { + it.copy( + isLoading = false, + error = "搜尋失敗:${error.message}", + searchResults = emptyList() // 失敗時清空列表 + ) + } + } } } } \ No newline at end of file