优化代码
修改我的-群聊UI将群聊列表样改为网格样式
This commit is contained in:
@@ -279,43 +279,4 @@ fun FriendChatItem(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Composable
|
|
||||||
fun ReloadButton(
|
|
||||||
onClick: () -> Unit
|
|
||||||
) {
|
|
||||||
val gradientBrush = Brush.linearGradient(
|
|
||||||
colors = listOf(
|
|
||||||
Color(0xFF7c45ed),
|
|
||||||
Color(0xFF7c68ef),
|
|
||||||
Color(0xFF7bd8f8)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
Button(
|
|
||||||
onClick = onClick,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 120.dp)
|
|
||||||
.height(48.dp),
|
|
||||||
shape = RoundedCornerShape(30.dp),
|
|
||||||
colors = ButtonDefaults.buttonColors(
|
|
||||||
backgroundColor = Color.Transparent
|
|
||||||
),
|
|
||||||
contentPadding = PaddingValues(0.dp)
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.background(gradientBrush),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.Reload),
|
|
||||||
fontSize = 16.sp,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
color = Color.White,
|
|
||||||
textAlign = TextAlign.Center
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -155,7 +155,8 @@ fun GalleryGrid(
|
|||||||
modifier = baseModifier
|
modifier = baseModifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
.padding(vertical = 60.dp),
|
.padding(vertical = 60.dp)
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Image(
|
Image(
|
||||||
|
|||||||
@@ -16,15 +16,16 @@ import androidx.compose.foundation.layout.size
|
|||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.ExperimentalMaterialApi
|
import androidx.compose.material.ExperimentalMaterialApi
|
||||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||||
import androidx.compose.material.pullrefresh.pullRefresh
|
import androidx.compose.material.pullrefresh.pullRefresh
|
||||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.HorizontalDivider
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
import com.airbnb.lottie.compose.LottieAnimation
|
import com.airbnb.lottie.compose.LottieAnimation
|
||||||
import com.airbnb.lottie.compose.LottieCompositionSpec
|
import com.airbnb.lottie.compose.LottieCompositionSpec
|
||||||
import com.airbnb.lottie.compose.LottieConstants
|
import com.airbnb.lottie.compose.LottieConstants
|
||||||
@@ -63,6 +64,8 @@ import com.aiosman.ravenow.ui.navigateToGroupChat
|
|||||||
import com.aiosman.ravenow.AppStore
|
import com.aiosman.ravenow.AppStore
|
||||||
import com.aiosman.ravenow.data.api.ApiClient
|
import com.aiosman.ravenow.data.api.ApiClient
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
|
import com.aiosman.ravenow.ui.network.ReloadButton
|
||||||
|
import com.aiosman.ravenow.utils.NetworkUtils.isNetworkAvailable
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -78,6 +81,7 @@ fun GroupChatEmptyContent(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
val viewModel = MyProfileViewModel
|
val viewModel = MyProfileViewModel
|
||||||
|
val networkAvailable = isNetworkAvailable(context)
|
||||||
|
|
||||||
// 如果查看其他用户的房间,固定使用全部类型(filterType = 0)
|
// 如果查看其他用户的房间,固定使用全部类型(filterType = 0)
|
||||||
val filterType = if (showSegments) selectedSegment else 0
|
val filterType = if (showSegments) selectedSegment else 0
|
||||||
@@ -133,48 +137,64 @@ fun GroupChatEmptyContent(
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
// 空状态插图
|
// 空状态插图
|
||||||
EmptyStateIllustration()
|
EmptyStateIllustration(
|
||||||
|
isNetworkAvailable = networkAvailable,
|
||||||
|
onReload = {
|
||||||
|
MyProfileViewModel.ResetModel()
|
||||||
|
MyProfileViewModel.loadProfile(pullRefresh = true)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(9.dp))
|
Spacer(modifier = Modifier.height(9.dp))
|
||||||
|
|
||||||
// 空状态文本
|
// 网络可用时才展示空状态文本
|
||||||
Text(
|
if (networkAvailable) {
|
||||||
text = stringResource(R.string.cosmos_awaits),
|
Text(
|
||||||
fontSize = 16.sp,
|
text = stringResource(R.string.cosmos_awaits),
|
||||||
fontWeight = FontWeight.SemiBold,
|
fontSize = 16.sp,
|
||||||
color = AppColors.text,
|
fontWeight = FontWeight.SemiBold,
|
||||||
textAlign = TextAlign.Center,
|
color = AppColors.text,
|
||||||
modifier = Modifier.padding(horizontal = 24.dp),
|
textAlign = TextAlign.Center,
|
||||||
maxLines = 2,
|
modifier = Modifier.padding(horizontal = 24.dp),
|
||||||
overflow = TextOverflow.Ellipsis
|
maxLines = 2,
|
||||||
)
|
overflow = TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = listState,
|
state = listState,
|
||||||
modifier = nestedScrollModifier.fillMaxSize()
|
modifier = nestedScrollModifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
itemsIndexed(
|
// 网格布局:每行显示2个房间卡片
|
||||||
items = viewModel.rooms,
|
items(
|
||||||
key = { _, item -> item.id }
|
items = viewModel.rooms.chunked(2),
|
||||||
) { index, room ->
|
key = { rowRooms -> rowRooms.firstOrNull()?.id?.toString() ?: "" }
|
||||||
RoomItem(
|
) { rowRooms ->
|
||||||
room = room,
|
Row(
|
||||||
onRoomClick = { roomEntity ->
|
modifier = Modifier
|
||||||
// 导航到群聊聊天界面
|
.fillMaxWidth()
|
||||||
navController.navigateToGroupChat(
|
.padding(bottom = 12.dp),
|
||||||
id = roomEntity.trtcRoomId,
|
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
name = roomEntity.name,
|
) {
|
||||||
avatar = roomEntity.avatar
|
rowRooms.forEach { room ->
|
||||||
|
RoomCard(
|
||||||
|
room = room,
|
||||||
|
onRoomClick = { roomEntity ->
|
||||||
|
// 导航到群聊聊天界面
|
||||||
|
navController.navigateToGroupChat(
|
||||||
|
id = roomEntity.trtcRoomId,
|
||||||
|
name = roomEntity.name,
|
||||||
|
avatar = roomEntity.avatar
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
// 如果这一行只有一个房间,添加一个空的占位符
|
||||||
|
if (rowRooms.size == 1) {
|
||||||
if (index < viewModel.rooms.size - 1) {
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
HorizontalDivider(
|
}
|
||||||
modifier = Modifier.padding(horizontal = 24.dp),
|
|
||||||
color = AppColors.divider
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,13 +237,15 @@ fun GroupChatEmptyContent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RoomItem(
|
fun RoomCard(
|
||||||
room: RoomEntity,
|
room: RoomEntity,
|
||||||
onRoomClick: (RoomEntity) -> Unit = {}
|
onRoomClick: (RoomEntity) -> Unit = {},
|
||||||
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val AppColors = LocalAppTheme.current
|
val AppColors = LocalAppTheme.current
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val roomDebouncer = rememberDebouncer()
|
val roomDebouncer = rememberDebouncer()
|
||||||
|
val cardSize = 180.dp
|
||||||
|
|
||||||
// 构建头像URL
|
// 构建头像URL
|
||||||
val avatarUrl = if (room.avatar.isNotEmpty()) {
|
val avatarUrl = if (room.avatar.isNotEmpty()) {
|
||||||
@@ -237,6 +259,117 @@ fun RoomItem(
|
|||||||
"${ApiClient.RETROFIT_URL}group/avatar?groupIdBase64=${groupIdBase64}&token=${AppStore.token}"
|
"${ApiClient.RETROFIT_URL}group/avatar?groupIdBase64=${groupIdBase64}&token=${AppStore.token}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 优先显示cover,如果没有cover则显示recommendBanner,最后显示avatar
|
||||||
|
val imageUrl = when {
|
||||||
|
room.cover.isNotEmpty() -> "${ConstVars.BASE_SERVER}/api/v1/outside/${room.cover}?token=${AppStore.token}"
|
||||||
|
room.recommendBanner.isNotEmpty() -> "${ConstVars.BASE_SERVER}/api/v1/outside/${room.recommendBanner}?token=${AppStore.token}"
|
||||||
|
else -> avatarUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
// 正方形卡片,文字重叠在底部
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.size(cardSize)
|
||||||
|
.background(AppColors.tabUnselectedBackground, RoundedCornerShape(12.dp))
|
||||||
|
.noRippleClickable {
|
||||||
|
roomDebouncer {
|
||||||
|
onRoomClick(room)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
CustomAsyncImage(
|
||||||
|
context = context,
|
||||||
|
imageUrl = imageUrl,
|
||||||
|
contentDescription = room.name,
|
||||||
|
modifier = Modifier
|
||||||
|
.width(cardSize)
|
||||||
|
.height(120.dp)
|
||||||
|
.clip(RoundedCornerShape(
|
||||||
|
topStart = 12.dp,
|
||||||
|
topEnd = 12.dp,
|
||||||
|
bottomStart = 0.dp,
|
||||||
|
bottomEnd = 0.dp)),
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
defaultRes = R.mipmap.rider_pro_agent
|
||||||
|
)
|
||||||
|
|
||||||
|
// 房间名称,重叠在底部
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 32.dp, start = 10.dp, end = 10.dp)
|
||||||
|
.clip(RoundedCornerShape(12.dp))
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = room.name,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
fontWeight = FontWeight.W900,
|
||||||
|
color = AppColors.text,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
textAlign = TextAlign.Left
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示人数
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 10.dp, start = 10.dp, end = 10.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.rider_pro_nav_profile),
|
||||||
|
contentDescription = "chat",
|
||||||
|
modifier = Modifier.size(16.dp),
|
||||||
|
colorFilter = ColorFilter.tint(AppColors.secondaryText)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
Text(
|
||||||
|
text = "${room.userCount} ${stringResource(R.string.chatting_now)}",
|
||||||
|
fontSize = 12.sp,
|
||||||
|
modifier = Modifier
|
||||||
|
.alpha(0.6f)
|
||||||
|
.weight(1f),
|
||||||
|
color = AppColors.text,
|
||||||
|
fontWeight = FontWeight.W500,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表样式的房间项,供搜索等场景复用
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun RoomItem(
|
||||||
|
room: RoomEntity,
|
||||||
|
onRoomClick: (RoomEntity) -> Unit = {}
|
||||||
|
) {
|
||||||
|
val AppColors = LocalAppTheme.current
|
||||||
|
val context = LocalContext.current
|
||||||
|
val roomDebouncer = rememberDebouncer()
|
||||||
|
|
||||||
|
// 构建头像URL
|
||||||
|
val avatarUrl = if (room.avatar.isNotEmpty()) {
|
||||||
|
"${ConstVars.BASE_SERVER}/api/v1/outside/${room.avatar}?token=${AppStore.token}"
|
||||||
|
} else {
|
||||||
|
val groupIdBase64 = Base64.encodeToString(
|
||||||
|
room.trtcType.toByteArray(),
|
||||||
|
Base64.NO_WRAP
|
||||||
|
)
|
||||||
|
"${ApiClient.RETROFIT_URL}group/avatar?groupIdBase64=${groupIdBase64}&token=${AppStore.token}"
|
||||||
|
}
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@@ -257,7 +390,7 @@ fun RoomItem(
|
|||||||
.clip(RoundedCornerShape(12.dp))
|
.clip(RoundedCornerShape(12.dp))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
@@ -277,9 +410,9 @@ fun RoomItem(
|
|||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
@@ -292,9 +425,9 @@ fun RoomItem(
|
|||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "${room.userCount}人",
|
text = "${room.userCount}人",
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
@@ -388,14 +521,46 @@ private fun SegmentButton(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun EmptyStateIllustration() {
|
private fun EmptyStateIllustration(
|
||||||
Image(
|
isNetworkAvailable: Boolean,
|
||||||
painter = painterResource(id = R.mipmap.l_empty_img),
|
onReload: () -> Unit
|
||||||
contentDescription = "空状态",
|
) {
|
||||||
modifier = Modifier
|
val AppColors = LocalAppTheme.current
|
||||||
.width(181.dp)
|
if (isNetworkAvailable) {
|
||||||
.height(153.dp),
|
Image(
|
||||||
contentScale = ContentScale.Fit
|
painter = painterResource(id = R.mipmap.l_empty_img),
|
||||||
)
|
contentDescription = "空状态",
|
||||||
|
modifier = Modifier
|
||||||
|
.width(181.dp)
|
||||||
|
.height(153.dp),
|
||||||
|
contentScale = ContentScale.Fit
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.mipmap.invalid_name_10),
|
||||||
|
contentDescription = "network error",
|
||||||
|
modifier = Modifier.size(181.dp),
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.friend_chat_no_network_title),
|
||||||
|
fontSize = 16.sp,
|
||||||
|
color = AppColors.text,
|
||||||
|
fontWeight = FontWeight.W600
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.friend_chat_no_network_subtitle),
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = AppColors.secondaryText,
|
||||||
|
fontWeight = FontWeight.W400
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
ReloadButton(onClick = onReload)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -786,42 +786,3 @@ fun SearchPlaceholderContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ReloadButton(
|
|
||||||
onClick: () -> Unit
|
|
||||||
) {
|
|
||||||
val gradientBrush = Brush.linearGradient(
|
|
||||||
colors = listOf(
|
|
||||||
Color(0xFF7c45ed),
|
|
||||||
Color(0xFF7c68ef),
|
|
||||||
Color(0xFF7bd8f8)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
Button(
|
|
||||||
onClick = onClick,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 120.dp)
|
|
||||||
.height(48.dp),
|
|
||||||
shape = RoundedCornerShape(30.dp),
|
|
||||||
colors = ButtonDefaults.buttonColors(
|
|
||||||
backgroundColor = Color.Transparent
|
|
||||||
),
|
|
||||||
contentPadding = PaddingValues(0.dp)
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.background(gradientBrush),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.Reload),
|
|
||||||
fontSize = 16.sp,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
color = Color.White,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user