auth to server-V102
This commit is contained in:
parent
4b3ccf1107
commit
6ecae41571
4 changed files with 148 additions and 97 deletions
|
|
@ -62,5 +62,3 @@ data class Reaction(
|
|||
@Json(name = "count") val count: Int,
|
||||
@Json(name = "me_reacted") val meReacted: Boolean
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import androidx.compose.animation.core.tween
|
|||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
|
|
@ -14,6 +15,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
|
|
@ -25,6 +27,7 @@ import androidx.compose.material.icons.filled.Person
|
|||
import androidx.compose.material.icons.filled.QrCode
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
|
|
@ -37,6 +40,7 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -51,15 +55,20 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.draw.blur
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import coil.compose.AsyncImage
|
||||
import com.example.login_v3.data.api.api_class.ChatRoom
|
||||
import com.example.login_v3.home.Message.UI.Detail.Message_add_contact
|
||||
import com.example.login_v3.home.Message.UI.Detail.Message_contact_list
|
||||
import com.example.login_v3.home.Message.UI.Detail.Scan_QRcode
|
||||
import com.example.login_v3.home.Message.ViewModel.MessageViewModel
|
||||
import com.example.login_v3.home.Message.ViewModel.ChatRoomsViewModel
|
||||
import com.example.login_v3.navigation.BottomBarViewModel
|
||||
|
||||
|
||||
|
|
@ -133,15 +142,25 @@ fun Tg_Message(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Loaded_Tg_Message(
|
||||
navController: NavController
|
||||
navController: NavController,
|
||||
viewModel: ChatRoomsViewModel = hiltViewModel(),
|
||||
onRoomClick: (String) -> Unit = {}
|
||||
) {
|
||||
val viewModel: MessageViewModel = viewModel()
|
||||
val contacts by viewModel.contacts.collectAsState()
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
|
||||
// 觀察 ViewModel 的 StateFlow
|
||||
val rooms by viewModel.roomsState.collectAsState()
|
||||
|
||||
// 進入頁面時主動讀取一次
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.loadRooms()
|
||||
}
|
||||
|
||||
|
||||
Scaffold(
|
||||
containerColor = Color.Transparent,
|
||||
modifier = Modifier
|
||||
|
|
@ -230,77 +249,116 @@ fun Loaded_Tg_Message(
|
|||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
LazyColumn(
|
||||
contentPadding = innerPadding
|
||||
) {
|
||||
items(contacts) { contact ->
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.padding(6.dp),
|
||||
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = Color.Transparent // ✅ 透明背景
|
||||
if (rooms.isEmpty()) {
|
||||
// 顯示空狀態或 Loading (這部分可根據需求擴充)
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize().padding(innerPadding),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text("目前沒有聊天室")
|
||||
}
|
||||
} else {
|
||||
LazyColumn(modifier = Modifier.padding(innerPadding)) {
|
||||
items(
|
||||
items = rooms,
|
||||
key = { it.roomId } // 增加效能,防止列表閃爍
|
||||
) { room ->
|
||||
RoomItem(
|
||||
room = room,
|
||||
onClick = onRoomClick
|
||||
)
|
||||
Divider(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
thickness = 0.5.dp,
|
||||
color = Color.LightGray.copy(alpha = 0.5f)
|
||||
)
|
||||
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
) {
|
||||
|
||||
//glass effect
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.blur(10.dp)
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.background(
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
RoundedCornerShape(16.dp)
|
||||
)
|
||||
.border(
|
||||
1.dp,
|
||||
Color.White.copy(alpha = 0.3f),
|
||||
RoundedCornerShape(16.dp)
|
||||
)
|
||||
)
|
||||
|
||||
// 前景層:文字 + 圖片,不會被模糊
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(12.dp),
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = contact.avatarResId),
|
||||
contentDescription = "${contact.name}'s avatar",
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.clip(CircleShape)
|
||||
.border(2.dp, Color.White, CircleShape)
|
||||
)
|
||||
Column(modifier = Modifier.padding(start = 12.dp)) {
|
||||
Text(
|
||||
text = contact.name,
|
||||
style = MaterialTheme.typography.titleMedium
|
||||
)
|
||||
Text(
|
||||
text = "Online",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = Color.Green
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Composable
|
||||
fun RoomItem(
|
||||
room: ChatRoom,
|
||||
onClick: (String) -> Unit
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { onClick(room.roomId) }
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// 1. 頭像處理
|
||||
val imageUrl = room.roomIconUrl ?: room.partner?.avatarUrl
|
||||
AsyncImage(
|
||||
model = imageUrl,
|
||||
contentDescription = "Avatar",
|
||||
modifier = Modifier
|
||||
.size(50.dp)
|
||||
.clip(CircleShape)
|
||||
.background(Color.LightGray) // 載入前的底色
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
|
||||
// 2. 中間內容:名稱與最後訊息
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = room.roomName.ifEmpty { room.partner?.displayName ?: "Unknown" },
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
fontWeight = FontWeight.Bold,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
|
||||
val lastMsgText = when {
|
||||
room.lastMessage?.isDeleted == true -> "訊息已刪除"
|
||||
room.lastMessage?.content != null -> room.lastMessage.content
|
||||
room.lastMessage?.attachment != null -> "[檔案] ${room.lastMessage.attachment.filename}"
|
||||
else -> "尚未有訊息"
|
||||
}
|
||||
|
||||
Text(
|
||||
text = lastMsgText,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = Color.Gray,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
|
||||
// 3. 右側:時間與未讀計數
|
||||
Column(horizontalAlignment = Alignment.End) {
|
||||
// 這裡簡單截取時間字串,實際建議用 DateTimeFormatter 轉格式
|
||||
val time = room.lastMessage?.createdAt?.take(10) ?: ""
|
||||
Text(
|
||||
text = time,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = Color.Gray
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
|
||||
if (room.unreadCount > 0) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(20.dp)
|
||||
.clip(CircleShape)
|
||||
.background(MaterialTheme.colorScheme.primary),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = if (room.unreadCount > 99) "99+" else room.unreadCount.toString(),
|
||||
color = Color.White,
|
||||
fontSize = 10.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,32 +4,31 @@ package com.example.login_v3.home.Message.ViewModel
|
|||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.login_v3.R
|
||||
import com.example.login_v3.data.api.api_class.ChatRoom
|
||||
import com.example.login_v3.data.repository.dm.ChatRoomsRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
data class Contact(
|
||||
val name: String,
|
||||
val avatarResId: Int // 或者用 String 存圖片 URL
|
||||
)
|
||||
@HiltViewModel
|
||||
class ChatRoomsViewModel @Inject constructor(
|
||||
private val repository: ChatRoomsRepository
|
||||
) : ViewModel() {
|
||||
|
||||
class MessageViewModel : ViewModel() {
|
||||
private val _roomsState = MutableStateFlow<List<ChatRoom>>(emptyList())
|
||||
val roomsState: StateFlow<List<ChatRoom>> = _roomsState
|
||||
|
||||
private val _contacts = MutableStateFlow<List<Contact>>(emptyList())
|
||||
val contacts: StateFlow<List<Contact>> = _contacts
|
||||
|
||||
init {
|
||||
fun loadRooms() {
|
||||
viewModelScope.launch {
|
||||
_contacts.value = listOf(
|
||||
Contact("Alice", R.drawable.avatar_v1),
|
||||
Contact("Bob", R.drawable.avatar_v1),
|
||||
Contact("Charlie", R.drawable.avatar_v1),
|
||||
Contact("David", R.drawable.avatar_v1),
|
||||
Contact("nigga", R.drawable.avatar_v1),
|
||||
Contact("gbl", R.drawable.avatar_v1),
|
||||
Contact("威威夢夢", R.drawable.avatar_v1)
|
||||
)
|
||||
val result = repository.fetchRooms()
|
||||
result.onSuccess { response ->
|
||||
_roomsState.value = response.rooms
|
||||
}.onFailure {
|
||||
// 處理錯誤,例如更新一個 error state
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.login_v3.home.Message.ViewModel.MessageViewModel
|
||||
import com.example.login_v3.home.Tg_MarketPlace
|
||||
import com.example.login_v3.home.Message.UI.Tg_Message
|
||||
import com.example.login_v3.home.Tg_Server
|
||||
|
|
@ -108,12 +107,9 @@ fun Screens_NavGraph(
|
|||
paddingValues: PaddingValues,
|
||||
screensViewModel: ScreensViewModel,
|
||||
bottomBarViewModel: BottomBarViewModel,
|
||||
messageViewModel: MessageViewModel = androidx.lifecycle.viewmodel.compose.viewModel()
|
||||
) {
|
||||
//nav_wheel_selecting tab
|
||||
val selectedScreen by screensViewModel.selected.collectAsState()
|
||||
//message_contact_list_import
|
||||
val contacts by messageViewModel.contacts.collectAsState()
|
||||
|
||||
|
||||
when (selectedScreen) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue