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 5966afc..5895d71 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 @@ -45,10 +45,7 @@ interface TecnologiaApi { @Part file: MultipartBody.Part ): Response - // 發送好友請求 - @POST("api/friends/request") - suspend fun sendFriendRequest( - @Header("Authorization") token: String, - @Body body: FriendRequest - ): Response + // contact + @GET("api/friends") + suspend fun getFriends(): FriendListResponse } \ 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 0b187a1..67de4c7 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 @@ -1,13 +1,27 @@ package com.example.login_v3.data.api.api_class +import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class FriendRequest( - val friendId: String +data class FriendListResponse( + val friends: List ) @JsonClass(generateAdapter = true) -data class ApiResponse( - val success: Boolean, - val message: String +data class Friend( + @Json(name = "friend_id") + val friendId: String, + + val username: String, + + @Json(name = "display_name") + val displayName: String, + + @Json(name = "avatar_url") + val avatarUrl: String?, // 建議給可空性,避免後端沒傳頭像時崩潰 + + val status: String, + + @Json(name = "accepted_at") + val acceptedAt: String ) \ No newline at end of file diff --git a/app/src/main/java/com/example/login_v3/data/repository/basic/Auth_Repository.kt b/app/src/main/java/com/example/login_v3/data/repository/basic/Auth_Repository.kt index 7592bb3..af3412d 100644 --- a/app/src/main/java/com/example/login_v3/data/repository/basic/Auth_Repository.kt +++ b/app/src/main/java/com/example/login_v3/data/repository/basic/Auth_Repository.kt @@ -1,7 +1,6 @@ package com.example.login_v3.data.repository.basic import com.example.login_v3.data.api.TecnologiaApi -import com.example.login_v3.data.api.api_class.ApiResponse import com.example.login_v3.data.api.api_class.LoginRequest import com.example.login_v3.data.api.api_class.LoginResponse import com.example.login_v3.data.api.api_class.RegisterRequest @@ -12,10 +11,6 @@ import javax.inject.Inject class AuthRepository @Inject constructor( private val api: TecnologiaApi ) { - /** - * 處理用戶註冊 - * 回傳 Response,讓 ViewModel 可以根據 isSuccessful 判斷結果 - */ suspend fun register(request: RegisterRequest): Response { return api.register(request) } 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 new file mode 100644 index 0000000..9795736 --- /dev/null +++ b/app/src/main/java/com/example/login_v3/data/repository/basic/Friends_Repository.kt @@ -0,0 +1,20 @@ +package com.example.login_v3.data.repository.basic + +import com.example.login_v3.data.api.TecnologiaApi +import com.example.login_v3.data.api.api_class.Friend +import javax.inject.Inject + +class FriendsRepository @Inject constructor + (private val apiService: TecnologiaApi) { + + suspend fun getFriendList(): Result> { + return try { + val response = apiService.getFriends() + // 回傳成功,並直接提取裡面的 List + Result.success(response.friends) + } catch (e: Exception) { + // 處理連線超時、404、500 等各種錯誤 + Result.failure(e) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_contact_list.kt b/app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_contact_list.kt index 257396b..6f70c3c 100644 --- a/app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_contact_list.kt +++ b/app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_contact_list.kt @@ -1,23 +1,93 @@ package com.example.login_v3.home.Message.UI.Detail +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.ListItem +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavController +import coil.compose.AsyncImage +import com.example.login_v3.R +import com.example.login_v3.data.api.api_class.Friend +import com.example.login_v3.home.Message.ViewModel.Detail.ContactListViewModel @Composable fun Message_contact_list( - navController: NavController + navController: NavController, + viewModel: ContactListViewModel = hiltViewModel() ){ + val friends by viewModel.friends.collectAsStateWithLifecycle() + Column( modifier = Modifier .fillMaxSize() , horizontalAlignment = Alignment.CenterHorizontally ) { - Text(text = "contact list") + if (friends.isEmpty()) { + // 如果列表是空的,顯示提示(或載入指示器) + Box( + modifier = Modifier.fillMaxSize().padding(6.dp), + contentAlignment = Alignment.Center + ) { + Text("目前沒有好友") + } + } else { + // 顯示好友列表 + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(6.dp) + ) { + items(friends) { friend -> + FriendRow(friend) + } + } + } } +} + + +@Composable +fun FriendRow(friend: Friend) { + ListItem( + headlineContent = { Text(friend.displayName) }, + supportingContent = { Text("@${friend.username}") }, + leadingContent = { + // 使用 Coil 載入頭像 + AsyncImage( + model = friend.avatarUrl, + contentDescription = "Avatar", + modifier = Modifier + .size(48.dp) + .clip(CircleShape), + placeholder = painterResource(id = R.drawable.avatar_v1), + error = painterResource(id = R.drawable.avatar_v1) + ) + }, + trailingContent = { + // 簡單顯示狀態 + Text( + text = friend.status, + style = MaterialTheme.typography.labelSmall, + color = if (friend.status == "online") Color.Green else Color.Gray + ) + } + ) } \ 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 new file mode 100644 index 0000000..b256abc --- /dev/null +++ b/app/src/main/java/com/example/login_v3/home/Message/ViewModel/Detail/Contact_list_ViewModel.kt @@ -0,0 +1,38 @@ +package com.example.login_v3.home.Message.ViewModel.Detail + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.login_v3.data.api.api_class.Friend +import com.example.login_v3.data.repository.basic.FriendsRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class ContactListViewModel @Inject constructor + ( + private val repository: FriendsRepository + ) : ViewModel() { + + private val _friends = MutableStateFlow>(emptyList()) + val friends: StateFlow> = _friends + + init { + // 畫面一建立就自動抓取資料 + fetchFriends() + } + + fun fetchFriends() { + viewModelScope.launch { + repository.getFriendList() + .onSuccess { list -> + _friends.value = list + } + .onFailure { + // 這裡可以處理錯誤訊息,例如顯示 Toast + } + } + } +} \ No newline at end of file