新增网络工具,修改bug
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,8 @@ fun AccountSetting() {
|
|||||||
),
|
),
|
||||||
dragHandle = {},
|
dragHandle = {},
|
||||||
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
|
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
|
||||||
windowInsets = WindowInsets(0)
|
windowInsets = WindowInsets(0),
|
||||||
|
modifier = Modifier.height(600.dp) // 设置固定高度
|
||||||
) {
|
) {
|
||||||
RemoveAccountModal(
|
RemoveAccountModal(
|
||||||
onRemove = {
|
onRemove = {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import androidx.compose.material3.CircularProgressIndicator
|
|||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
@@ -86,6 +87,13 @@ fun AddAgentScreen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 页面退出时清空数据
|
||||||
|
DisposableEffect(Unit) {
|
||||||
|
onDispose {
|
||||||
|
model.clearData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
@@ -230,10 +238,8 @@ fun AddAgentScreen() {
|
|||||||
val result = model.createAgent(context)
|
val result = model.createAgent(context)
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
println("AddAgent: Agent created successfully, closing page")
|
println("AddAgent: Agent created successfully, closing page")
|
||||||
// 创建成功,关闭页面
|
// 创建成功,清空数据并关闭页面
|
||||||
model.name = ""
|
model.clearData()
|
||||||
model.desc = ""
|
|
||||||
model.isFromAddAgent = false // 重置标志
|
|
||||||
navController.popBackStack()
|
navController.popBackStack()
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|||||||
@@ -81,4 +81,15 @@ object AddAgentViewModel : ViewModel() {
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空所有页面数据
|
||||||
|
*/
|
||||||
|
fun clearData() {
|
||||||
|
name = ""
|
||||||
|
desc = ""
|
||||||
|
croppedBitmap = null
|
||||||
|
isUpdating = false
|
||||||
|
isFromAddAgent = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@ import androidx.activity.compose.rememberLauncherForActivityResult
|
|||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.animation.core.animateDpAsState
|
import androidx.compose.animation.core.animateDpAsState
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
@@ -49,6 +50,7 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.runtime.snapshotFlow
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.shadow
|
import androidx.compose.ui.draw.shadow
|
||||||
import androidx.compose.ui.focus.onFocusChanged
|
import androidx.compose.ui.focus.onFocusChanged
|
||||||
@@ -81,6 +83,7 @@ import com.aiosman.ravenow.ui.composables.DropdownMenu
|
|||||||
import com.aiosman.ravenow.ui.composables.MenuItem
|
import com.aiosman.ravenow.ui.composables.MenuItem
|
||||||
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
|
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
|
||||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
|
import com.aiosman.ravenow.utils.NetworkUtils
|
||||||
import com.tencent.imsdk.v2.V2TIMMessage
|
import com.tencent.imsdk.v2.V2TIMMessage
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
@@ -228,6 +231,7 @@ fun ChatAiScreen(userId: String) {
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
isMenuExpanded = false
|
isMenuExpanded = false
|
||||||
|
if (NetworkUtils.isNetworkAvailable(context)) {
|
||||||
viewModel.viewModelScope.launch {
|
viewModel.viewModelScope.launch {
|
||||||
if (viewModel.notificationStrategy == "mute") {
|
if (viewModel.notificationStrategy == "mute") {
|
||||||
viewModel.updateNotificationStrategy("active")
|
viewModel.updateNotificationStrategy("active")
|
||||||
@@ -235,6 +239,9 @@ fun ChatAiScreen(userId: String) {
|
|||||||
viewModel.updateNotificationStrategy("mute")
|
viewModel.updateNotificationStrategy("mute")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -260,7 +267,11 @@ fun ChatAiScreen(userId: String) {
|
|||||||
ChatAiInput(
|
ChatAiInput(
|
||||||
onSendImage = {
|
onSendImage = {
|
||||||
it?.let {
|
it?.let {
|
||||||
|
if (NetworkUtils.isNetworkAvailable(context)) {
|
||||||
viewModel.sendImageMessage(it, context)
|
viewModel.sendImageMessage(it, context)
|
||||||
|
} else {
|
||||||
|
android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
@@ -355,19 +366,28 @@ fun ChatAiSelfItem(item: ChatItem) {
|
|||||||
Column(
|
Column(
|
||||||
horizontalAlignment = androidx.compose.ui.Alignment.End,
|
horizontalAlignment = androidx.compose.ui.Alignment.End,
|
||||||
) {
|
) {
|
||||||
|
/* Text(
|
||||||
|
text = item.nickname,
|
||||||
|
style = TextStyle(
|
||||||
|
color = Color.Gray,
|
||||||
|
fontSize = 12.sp,
|
||||||
|
),
|
||||||
|
modifier = Modifier.padding(bottom = 2.dp)
|
||||||
|
)
|
||||||
|
*/
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.widthIn(
|
.widthIn(
|
||||||
min = 20.dp,
|
min = 20.dp,
|
||||||
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
||||||
)
|
)
|
||||||
.clip(RoundedCornerShape(8.dp))
|
.clip(RoundedCornerShape(20.dp))
|
||||||
.background(Color(0xFF000000))
|
.background(Color(0xFF6246FF))
|
||||||
.padding(
|
.padding(
|
||||||
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
||||||
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
||||||
)
|
)
|
||||||
.padding(bottom = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 3.dp else 0.dp))
|
|
||||||
) {
|
) {
|
||||||
when (item.messageType) {
|
when (item.messageType) {
|
||||||
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
||||||
@@ -375,7 +395,7 @@ fun ChatAiSelfItem(item: ChatItem) {
|
|||||||
text = item.message,
|
text = item.message,
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
color = Color.White,
|
color = Color.White,
|
||||||
fontSize = 16.sp,
|
fontSize = 14.sp,
|
||||||
),
|
),
|
||||||
textAlign = TextAlign.Start
|
textAlign = TextAlign.Start
|
||||||
)
|
)
|
||||||
@@ -391,28 +411,28 @@ fun ChatAiSelfItem(item: ChatItem) {
|
|||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
Text(
|
Text(
|
||||||
text = "Unsupported message type",
|
text = "不支持的消息类型",
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
color = Color.White,
|
color = Color.White,
|
||||||
fontSize = 16.sp,
|
fontSize = 14.sp,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.width(12.dp))
|
/*Spacer(modifier = Modifier.width(12.dp))
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(40.dp)
|
.size(24.dp)
|
||||||
.clip(RoundedCornerShape(40.dp))
|
.clip(RoundedCornerShape(24.dp))
|
||||||
) {
|
) {
|
||||||
CustomAsyncImage(
|
CustomAsyncImage(
|
||||||
imageUrl = item.avatar,
|
imageUrl = item.avatar,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
contentDescription = "avatar"
|
contentDescription = "avatar"
|
||||||
)
|
)
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -432,8 +452,8 @@ fun ChatAiOtherItem(item: ChatItem) {
|
|||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(40.dp)
|
.size(24.dp)
|
||||||
.clip(RoundedCornerShape(40.dp))
|
.clip(RoundedCornerShape(24.dp))
|
||||||
) {
|
) {
|
||||||
CustomAsyncImage(
|
CustomAsyncImage(
|
||||||
imageUrl = item.avatar,
|
imageUrl = item.avatar,
|
||||||
@@ -450,7 +470,7 @@ fun ChatAiOtherItem(item: ChatItem) {
|
|||||||
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
||||||
)
|
)
|
||||||
.clip(RoundedCornerShape(8.dp))
|
.clip(RoundedCornerShape(8.dp))
|
||||||
.background(AppColors.background)
|
.background(AppColors.bubbleBackground)
|
||||||
.padding(
|
.padding(
|
||||||
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
||||||
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
||||||
@@ -463,7 +483,7 @@ fun ChatAiOtherItem(item: ChatItem) {
|
|||||||
text = item.message,
|
text = item.message,
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
fontSize = 16.sp,
|
fontSize = 14.sp,
|
||||||
),
|
),
|
||||||
textAlign = TextAlign.Start
|
textAlign = TextAlign.Start
|
||||||
)
|
)
|
||||||
@@ -510,6 +530,7 @@ fun ChatAiInput(
|
|||||||
onSendImage: (Uri?) -> Unit = {},
|
onSendImage: (Uri?) -> Unit = {},
|
||||||
onSend: (String) -> Unit = {},
|
onSend: (String) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
val navigationBarHeight = with(LocalDensity.current) {
|
val navigationBarHeight = with(LocalDensity.current) {
|
||||||
WindowInsets.navigationBars.getBottom(this).toDp()
|
WindowInsets.navigationBars.getBottom(this).toDp()
|
||||||
}
|
}
|
||||||
@@ -525,9 +546,8 @@ fun ChatAiInput(
|
|||||||
), label = ""
|
), label = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
// 在 isKeyboardOpen 变化时立即更新 inputBarHeight 的动画目标值
|
|
||||||
LaunchedEffect(isKeyboardOpen) {
|
LaunchedEffect(isKeyboardOpen) {
|
||||||
inputBarHeight // 触发 inputBarHeight 的重组
|
inputBarHeight
|
||||||
}
|
}
|
||||||
val focusManager = LocalFocusManager.current
|
val focusManager = LocalFocusManager.current
|
||||||
val windowInsets = WindowInsets.ime
|
val windowInsets = WindowInsets.ime
|
||||||
@@ -549,20 +569,21 @@ fun ChatAiInput(
|
|||||||
onSendImage(uri)
|
onSendImage(uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Box( modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(start = 16.dp, end = 16.dp, bottom = 12.dp),){
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp)
|
.clip(RoundedCornerShape(20.dp))
|
||||||
.padding(bottom = inputBarHeight)
|
.background(appColors.decentBackground)
|
||||||
|
.padding(start = 16.dp, end = 8.dp, top = 2.dp, bottom = 2.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.clip(RoundedCornerShape(16.dp))
|
|
||||||
.background(appColors.background)
|
|
||||||
.padding(horizontal = 16.dp),
|
|
||||||
contentAlignment = Alignment.CenterStart,
|
|
||||||
) {
|
) {
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
value = text,
|
value = text,
|
||||||
@@ -574,6 +595,7 @@ fun ChatAiInput(
|
|||||||
fontSize = 16.sp
|
fontSize = 16.sp
|
||||||
),
|
),
|
||||||
cursorBrush = SolidColor(appColors.text),
|
cursorBrush = SolidColor(appColors.text),
|
||||||
|
singleLine = true,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 8.dp)
|
.padding(vertical = 8.dp)
|
||||||
@@ -596,27 +618,37 @@ fun ChatAiInput(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Crossfade(
|
Crossfade(
|
||||||
targetState = text.isNotEmpty(), animationSpec = tween(500),
|
targetState = text.isNotEmpty(), animationSpec = tween(500),
|
||||||
label = ""
|
label = ""
|
||||||
) { isNotEmpty ->
|
) { isNotEmpty ->
|
||||||
Icon(
|
val alpha by animateFloatAsState(
|
||||||
painter = painterResource(id = R.drawable.rider_pro_video_share),
|
targetValue = if (isNotEmpty) 1f else 0.5f,
|
||||||
contentDescription = "Emoji",
|
animationSpec = tween(300)
|
||||||
|
)
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.mipmap.rider_pro_im_send),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(32.dp)
|
.size(24.dp)
|
||||||
|
.alpha(alpha)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
if (text.isNotEmpty()) {
|
if (text.isNotEmpty()) {
|
||||||
|
if (NetworkUtils.isNetworkAvailable(context)) {
|
||||||
onSend(text)
|
onSend(text)
|
||||||
text = ""
|
text = ""
|
||||||
|
} else {
|
||||||
|
android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tint = if (isNotEmpty) appColors.main else appColors.chatActionColor
|
contentDescription = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun groupMessagesByTime(chatList: List<ChatItem>, viewModel: ChatAiViewModel): List<ChatItem> {
|
fun groupMessagesByTime(chatList: List<ChatItem>, viewModel: ChatAiViewModel): List<ChatItem> {
|
||||||
for (i in chatList.indices) { // Iterate in normal order
|
for (i in chatList.indices) { // Iterate in normal order
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ import com.aiosman.ravenow.ui.composables.DropdownMenu
|
|||||||
import com.aiosman.ravenow.ui.composables.MenuItem
|
import com.aiosman.ravenow.ui.composables.MenuItem
|
||||||
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
|
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
|
||||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
|
import com.aiosman.ravenow.utils.NetworkUtils
|
||||||
import com.tencent.imsdk.v2.V2TIMMessage
|
import com.tencent.imsdk.v2.V2TIMMessage
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
@@ -231,6 +232,7 @@ fun ChatScreen(userId: String) {
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
isMenuExpanded = false
|
isMenuExpanded = false
|
||||||
|
if (NetworkUtils.isNetworkAvailable(context)) {
|
||||||
viewModel.viewModelScope.launch {
|
viewModel.viewModelScope.launch {
|
||||||
if (viewModel.notificationStrategy == "mute") {
|
if (viewModel.notificationStrategy == "mute") {
|
||||||
viewModel.updateNotificationStrategy("active")
|
viewModel.updateNotificationStrategy("active")
|
||||||
@@ -238,6 +240,9 @@ fun ChatScreen(userId: String) {
|
|||||||
viewModel.updateNotificationStrategy("mute")
|
viewModel.updateNotificationStrategy("mute")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -262,7 +267,11 @@ fun ChatScreen(userId: String) {
|
|||||||
ChatInput(
|
ChatInput(
|
||||||
onSendImage = {
|
onSendImage = {
|
||||||
it?.let {
|
it?.let {
|
||||||
|
if (NetworkUtils.isNetworkAvailable(context)) {
|
||||||
viewModel.sendImageMessage(it, context)
|
viewModel.sendImageMessage(it, context)
|
||||||
|
} else {
|
||||||
|
android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
@@ -443,11 +452,11 @@ fun ChatOtherItem(item: ChatItem) {
|
|||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(24.dp)
|
.size(40.dp)
|
||||||
.clip(RoundedCornerShape(24.dp))
|
.clip(RoundedCornerShape(40.dp))
|
||||||
) {
|
) {
|
||||||
CustomAsyncImage(
|
CustomAsyncImage(
|
||||||
imageUrl = item.avatar.replace("storage/avatars/", "/avatar/"),
|
imageUrl = item.avatar,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
contentDescription = "avatar"
|
contentDescription = "avatar"
|
||||||
)
|
)
|
||||||
@@ -460,12 +469,13 @@ fun ChatOtherItem(item: ChatItem) {
|
|||||||
min = 20.dp,
|
min = 20.dp,
|
||||||
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
||||||
)
|
)
|
||||||
.clip(RoundedCornerShape(20.dp))
|
.clip(RoundedCornerShape(8.dp))
|
||||||
.background(AppColors.bubbleBackground)
|
.background(AppColors.background)
|
||||||
.padding(
|
.padding(
|
||||||
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
||||||
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
||||||
)
|
)
|
||||||
|
.padding(bottom = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 3.dp else 0.dp))
|
||||||
) {
|
) {
|
||||||
when (item.messageType) {
|
when (item.messageType) {
|
||||||
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
||||||
@@ -473,7 +483,7 @@ fun ChatOtherItem(item: ChatItem) {
|
|||||||
text = item.message,
|
text = item.message,
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
fontSize = 14.sp,
|
fontSize = 16.sp,
|
||||||
),
|
),
|
||||||
textAlign = TextAlign.Start
|
textAlign = TextAlign.Start
|
||||||
)
|
)
|
||||||
@@ -489,7 +499,7 @@ fun ChatOtherItem(item: ChatItem) {
|
|||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
Text(
|
Text(
|
||||||
text = "不支持的消息类型",
|
text = "Unsupported message type",
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
@@ -498,6 +508,7 @@ fun ChatOtherItem(item: ChatItem) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -519,6 +530,7 @@ fun ChatInput(
|
|||||||
onSendImage: (Uri?) -> Unit = {},
|
onSendImage: (Uri?) -> Unit = {},
|
||||||
onSend: (String) -> Unit = {},
|
onSend: (String) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
val navigationBarHeight = with(LocalDensity.current) {
|
val navigationBarHeight = with(LocalDensity.current) {
|
||||||
WindowInsets.navigationBars.getBottom(this).toDp()
|
WindowInsets.navigationBars.getBottom(this).toDp()
|
||||||
}
|
}
|
||||||
@@ -614,6 +626,7 @@ fun ChatInput(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(30.dp)
|
.size(30.dp)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
|
if (NetworkUtils.isNetworkAvailable(context)) {
|
||||||
imagePickUpLauncher.launch(
|
imagePickUpLauncher.launch(
|
||||||
Intent.createChooser(
|
Intent.createChooser(
|
||||||
Intent(Intent.ACTION_GET_CONTENT).apply {
|
Intent(Intent.ACTION_GET_CONTENT).apply {
|
||||||
@@ -622,6 +635,9 @@ fun ChatInput(
|
|||||||
"Select Image"
|
"Select Image"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -641,8 +657,12 @@ fun ChatInput(
|
|||||||
.alpha(alpha)
|
.alpha(alpha)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
if (text.isNotEmpty()) {
|
if (text.isNotEmpty()) {
|
||||||
|
if (NetworkUtils.isNetworkAvailable(context)) {
|
||||||
onSend(text)
|
onSend(text)
|
||||||
text = ""
|
text = ""
|
||||||
|
} else {
|
||||||
|
android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ import com.aiosman.ravenow.ui.composables.MenuItem
|
|||||||
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
|
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
|
||||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
import com.aiosman.ravenow.ui.navigateToGroupInfo
|
import com.aiosman.ravenow.ui.navigateToGroupInfo
|
||||||
|
import com.aiosman.ravenow.utils.NetworkUtils
|
||||||
import com.tencent.imsdk.v2.V2TIMMessage
|
import com.tencent.imsdk.v2.V2TIMMessage
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
@@ -257,7 +258,11 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) {
|
|||||||
GroupChatInput(
|
GroupChatInput(
|
||||||
onSendImage = { uri ->
|
onSendImage = { uri ->
|
||||||
uri?.let {
|
uri?.let {
|
||||||
|
if (NetworkUtils.isNetworkAvailable(context)) {
|
||||||
viewModel.sendImageMessage(it, context)
|
viewModel.sendImageMessage(it, context)
|
||||||
|
} else {
|
||||||
|
android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
) { message ->
|
) { message ->
|
||||||
@@ -566,6 +571,7 @@ fun GroupChatInput(
|
|||||||
onSendImage: (Uri?) -> Unit = {},
|
onSendImage: (Uri?) -> Unit = {},
|
||||||
onSend: (String) -> Unit = {},
|
onSend: (String) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
val navigationBarHeight = with(LocalDensity.current) {
|
val navigationBarHeight = with(LocalDensity.current) {
|
||||||
WindowInsets.navigationBars.getBottom(this).toDp()
|
WindowInsets.navigationBars.getBottom(this).toDp()
|
||||||
}
|
}
|
||||||
@@ -670,8 +676,12 @@ fun GroupChatInput(
|
|||||||
.alpha(alpha)
|
.alpha(alpha)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
if (text.isNotEmpty()) {
|
if (text.isNotEmpty()) {
|
||||||
|
if (NetworkUtils.isNetworkAvailable(context)) {
|
||||||
onSend(text)
|
onSend(text)
|
||||||
text = ""
|
text = ""
|
||||||
|
} else {
|
||||||
|
android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -24,7 +25,6 @@ data class MenuItem(
|
|||||||
val title: String,
|
val title: String,
|
||||||
val icon: Int,
|
val icon: Int,
|
||||||
val action: () -> Unit
|
val action: () -> Unit
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -36,13 +36,6 @@ fun DropdownMenu(
|
|||||||
) {
|
) {
|
||||||
val AppColors = LocalAppTheme.current
|
val AppColors = LocalAppTheme.current
|
||||||
|
|
||||||
MaterialTheme(
|
|
||||||
shapes = MaterialTheme.shapes.copy(
|
|
||||||
extraSmall = RoundedCornerShape(
|
|
||||||
16.dp
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
androidx.compose.material3.DropdownMenu(
|
androidx.compose.material3.DropdownMenu(
|
||||||
expanded = expanded,
|
expanded = expanded,
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
@@ -50,7 +43,7 @@ fun DropdownMenu(
|
|||||||
.let {
|
.let {
|
||||||
if (width != null) it.width(width.dp) else it
|
if (width != null) it.width(width.dp) else it
|
||||||
}
|
}
|
||||||
.background(AppColors.background)
|
.background(color = AppColors.background),
|
||||||
) {
|
) {
|
||||||
for (item in menuItems) {
|
for (item in menuItems) {
|
||||||
Box(
|
Box(
|
||||||
@@ -58,7 +51,8 @@ fun DropdownMenu(
|
|||||||
.padding(vertical = 14.dp, horizontal = 24.dp)
|
.padding(vertical = 14.dp, horizontal = 24.dp)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
item.action()
|
item.action()
|
||||||
}) {
|
}
|
||||||
|
) {
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
@@ -69,7 +63,6 @@ fun DropdownMenu(
|
|||||||
)
|
)
|
||||||
if (width != null) {
|
if (width != null) {
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Spacer(modifier = Modifier.width(16.dp))
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
}
|
}
|
||||||
@@ -84,4 +77,3 @@ fun DropdownMenu(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
@@ -363,7 +363,7 @@ fun IndexScreen() {
|
|||||||
@Composable
|
@Composable
|
||||||
fun Home() {
|
fun Home() {
|
||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(AppState.darkMode) {
|
||||||
systemUiController.setStatusBarColor(Color.Transparent, darkIcons = !AppState.darkMode)
|
systemUiController.setStatusBarColor(Color.Transparent, darkIcons = !AppState.darkMode)
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
@@ -380,7 +380,7 @@ fun Home() {
|
|||||||
@Composable
|
@Composable
|
||||||
fun Street() {
|
fun Street() {
|
||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(AppState.darkMode) {
|
||||||
systemUiController.setStatusBarColor(Color.Transparent, darkIcons = !AppState.darkMode)
|
systemUiController.setStatusBarColor(Color.Transparent, darkIcons = !AppState.darkMode)
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
@@ -396,7 +396,7 @@ fun Street() {
|
|||||||
@Composable
|
@Composable
|
||||||
fun Add() {
|
fun Add() {
|
||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(AppState.darkMode) {
|
||||||
systemUiController.setStatusBarColor(Color.Black, darkIcons = !AppState.darkMode)
|
systemUiController.setStatusBarColor(Color.Black, darkIcons = !AppState.darkMode)
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
@@ -413,7 +413,7 @@ fun Add() {
|
|||||||
@Composable
|
@Composable
|
||||||
fun Video() {
|
fun Video() {
|
||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(AppState.darkMode) {
|
||||||
systemUiController.setStatusBarColor(Color.Black, darkIcons = false)
|
systemUiController.setStatusBarColor(Color.Black, darkIcons = false)
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
@@ -430,7 +430,7 @@ fun Video() {
|
|||||||
@Composable
|
@Composable
|
||||||
fun Profile() {
|
fun Profile() {
|
||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(AppState.darkMode) {
|
||||||
systemUiController.setStatusBarColor(Color.Transparent, !AppState.darkMode)
|
systemUiController.setStatusBarColor(Color.Transparent, !AppState.darkMode)
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
@@ -446,7 +446,7 @@ fun Profile() {
|
|||||||
@Composable
|
@Composable
|
||||||
fun Notifications() {
|
fun Notifications() {
|
||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(AppState.darkMode) {
|
||||||
systemUiController.setStatusBarColor(Color.Transparent, !AppState.darkMode)
|
systemUiController.setStatusBarColor(Color.Transparent, !AppState.darkMode)
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import com.aiosman.ravenow.R
|
|||||||
import com.aiosman.ravenow.ui.NavigationRoute
|
import com.aiosman.ravenow.ui.NavigationRoute
|
||||||
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
||||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
|
import com.aiosman.ravenow.utils.NetworkUtils
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 智能体聊天列表页面
|
* 智能体聊天列表页面
|
||||||
@@ -123,8 +124,12 @@ fun AgentChatListScreen() {
|
|||||||
AgentChatListViewModel.goToUserDetail(conv, navController)
|
AgentChatListViewModel.goToUserDetail(conv, navController)
|
||||||
},
|
},
|
||||||
onChatClick = { conv ->
|
onChatClick = { conv ->
|
||||||
|
if (NetworkUtils.isNetworkAvailable(context)) {
|
||||||
model.createSingleChat(conv.trtcUserId)
|
model.createSingleChat(conv.trtcUserId)
|
||||||
model.goToChatAi(conv.trtcUserId,navController)
|
model.goToChatAi(conv.trtcUserId,navController)
|
||||||
|
} else {
|
||||||
|
android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import com.aiosman.ravenow.LocalNavController
|
|||||||
import com.aiosman.ravenow.R
|
import com.aiosman.ravenow.R
|
||||||
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
||||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
|
import com.aiosman.ravenow.utils.NetworkUtils
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -106,7 +107,11 @@ fun FriendChatListScreen() {
|
|||||||
FriendChatListViewModel.goToUserDetail(conv, navController)
|
FriendChatListViewModel.goToUserDetail(conv, navController)
|
||||||
},
|
},
|
||||||
onChatClick = { conv ->
|
onChatClick = { conv ->
|
||||||
|
if (NetworkUtils.isNetworkAvailable(context)) {
|
||||||
FriendChatListViewModel.goToChat(conv, navController)
|
FriendChatListViewModel.goToChat(conv, navController)
|
||||||
|
} else {
|
||||||
|
android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package com.aiosman.ravenow.ui.index.tabs.message.tab
|
package com.aiosman.ravenow.ui.index.tabs.message.tab
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
@@ -16,14 +14,11 @@ import androidx.compose.material3.CircularProgressIndicator
|
|||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
@@ -34,6 +29,7 @@ import com.aiosman.ravenow.LocalNavController
|
|||||||
import com.aiosman.ravenow.R
|
import com.aiosman.ravenow.R
|
||||||
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
||||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
|
import com.aiosman.ravenow.utils.NetworkUtils
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -51,15 +47,6 @@ fun GroupChatListScreen() {
|
|||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
GroupChatListViewModel.refreshPager(context = context)
|
GroupChatListViewModel.refreshPager(context = context)
|
||||||
// 初始化消息监听器
|
|
||||||
GroupChatListViewModel.initMessageListener(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在组件销毁时清理监听器
|
|
||||||
DisposableEffect(Unit) {
|
|
||||||
onDispose {
|
|
||||||
GroupChatListViewModel.removeMessageListener()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -79,31 +66,18 @@ fun GroupChatListScreen() {
|
|||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(80.dp))
|
|
||||||
Image(
|
|
||||||
painter = painterResource(id = if (isSystemInDarkTheme()) {
|
|
||||||
R.mipmap.icon_group_chat_empty // 深色模式图片
|
|
||||||
} else {
|
|
||||||
R.mipmap.icon_group_chat_empty // 浅色模式图片
|
|
||||||
}),
|
|
||||||
contentDescription = "null data",
|
|
||||||
modifier = Modifier
|
|
||||||
.size(140.dp)
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.group_chat_empty_title),
|
text = "暂无群聊",
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
fontWeight = FontWeight.W600
|
fontWeight = FontWeight.W600
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.group_chat_empty_subtitle),
|
text = "您还没有加入任何群聊",
|
||||||
color = AppColors.text,
|
color = AppColors.secondaryText,
|
||||||
fontSize = 14.sp
|
fontSize = 14.sp
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -121,10 +95,20 @@ fun GroupChatListScreen() {
|
|||||||
GroupChatListViewModel.goToGroupDetail(conv, navController)
|
GroupChatListViewModel.goToGroupDetail(conv, navController)
|
||||||
},
|
},
|
||||||
onChatClick = { conv ->
|
onChatClick = { conv ->
|
||||||
|
if (NetworkUtils.isNetworkAvailable(context)) {
|
||||||
GroupChatListViewModel.goToChat(conv, navController)
|
GroupChatListViewModel.goToChat(conv, navController)
|
||||||
|
} else {
|
||||||
|
android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (index < GroupChatListViewModel.groupChatList.size - 1) {
|
||||||
|
HorizontalDivider(
|
||||||
|
modifier = Modifier.padding(horizontal = 24.dp),
|
||||||
|
color = AppColors.divider
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GroupChatListViewModel.isLoading && GroupChatListViewModel.groupChatList.isNotEmpty()) {
|
if (GroupChatListViewModel.isLoading && GroupChatListViewModel.groupChatList.isNotEmpty()) {
|
||||||
@@ -180,11 +164,10 @@ fun GroupChatItem(
|
|||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp, vertical = 12.dp)
|
.padding(horizontal = 24.dp, vertical = 12.dp)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
onChatClick(conversation)
|
onChatClick(conversation)
|
||||||
},
|
}
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
) {
|
||||||
Box {
|
Box {
|
||||||
CustomAsyncImage(
|
CustomAsyncImage(
|
||||||
@@ -202,9 +185,9 @@ fun GroupChatItem(
|
|||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.padding(start = 12.dp, top = 2.dp),
|
.padding(start = 12.dp)
|
||||||
verticalArrangement = Arrangement.Center
|
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
@@ -212,22 +195,22 @@ fun GroupChatItem(
|
|||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = conversation.groupName,
|
text = conversation.groupName,
|
||||||
fontSize = 14.sp,
|
fontSize = 16.sp,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(6.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = conversation.lastMessageTime,
|
text = conversation.lastMessageTime,
|
||||||
fontSize = 11.sp,
|
fontSize = 12.sp,
|
||||||
color = AppColors.secondaryText
|
color = AppColors.secondaryText
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(6.dp))
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
@@ -235,29 +218,30 @@ fun GroupChatItem(
|
|||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "${if (conversation.isSelf) stringResource(R.string.friend_chat_me_prefix) else ""}${conversation.displayText}",
|
text = "${if (conversation.isSelf) stringResource(R.string.friend_chat_me_prefix) else ""}${conversation.displayText}",
|
||||||
fontSize = 12.sp,
|
fontSize = 14.sp,
|
||||||
color = AppColors.secondaryText,
|
color = AppColors.secondaryText,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(10.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
if (conversation.unreadCount > 0) {
|
if (conversation.unreadCount > 0) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(if (conversation.unreadCount > 99) 24.dp else 20.dp)
|
.size(if (conversation.unreadCount > 99) 24.dp else 20.dp)
|
||||||
.background(
|
.background(
|
||||||
color = Color(0xFFFF3B30),
|
color = AppColors.main,
|
||||||
shape = CircleShape
|
shape = CircleShape
|
||||||
),
|
),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = if (conversation.unreadCount > 99) "99+" else conversation.unreadCount.toString(),
|
text = if (conversation.unreadCount > 99) "99+" else conversation.unreadCount.toString(),
|
||||||
color = Color.White,
|
color = AppColors.mainText,
|
||||||
fontSize = if (conversation.unreadCount > 99) 11.sp else 12.sp,
|
fontSize = if (conversation.unreadCount > 99) 9.sp else 10.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.lazy.grid.GridCells
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
@@ -140,6 +141,7 @@ fun ProfileV3(
|
|||||||
val AppColors = appTheme
|
val AppColors = appTheme
|
||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
|
val gridState = rememberLazyGridState()
|
||||||
|
|
||||||
// observe list scrolling
|
// observe list scrolling
|
||||||
val reachedListBottom by remember {
|
val reachedListBottom by remember {
|
||||||
@@ -149,13 +151,28 @@ fun ProfileV3(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load more if scrolled to bottom
|
// observe grid scrolling for load more
|
||||||
|
val reachedGridBottom by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
val lastVisibleItem = gridState.layoutInfo.visibleItemsInfo.lastOrNull()
|
||||||
|
lastVisibleItem?.index != 0 && lastVisibleItem?.index == gridState.layoutInfo.totalItemsCount - 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// load more if scrolled to bottom of list
|
||||||
LaunchedEffect(reachedListBottom) {
|
LaunchedEffect(reachedListBottom) {
|
||||||
if (reachedListBottom) {
|
if (reachedListBottom) {
|
||||||
onLoadMore()
|
onLoadMore()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load more if scrolled to bottom of grid
|
||||||
|
LaunchedEffect(reachedGridBottom) {
|
||||||
|
if (reachedGridBottom) {
|
||||||
|
onLoadMore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun switchTheme() {
|
fun switchTheme() {
|
||||||
@@ -458,6 +475,7 @@ fun ProfileV3(
|
|||||||
0 ->
|
0 ->
|
||||||
LazyVerticalGrid(
|
LazyVerticalGrid(
|
||||||
columns = GridCells.Fixed(3),
|
columns = GridCells.Fixed(3),
|
||||||
|
state = gridState,
|
||||||
modifier = Modifier.fillMaxSize().padding(bottom = 8.dp),
|
modifier = Modifier.fillMaxSize().padding(bottom = 8.dp),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|||||||
71
app/src/main/java/com/aiosman/ravenow/utils/NetworkUtils.kt
Normal file
71
app/src/main/java/com/aiosman/ravenow/utils/NetworkUtils.kt
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package com.aiosman.ravenow.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.Network
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
|
import android.net.NetworkRequest
|
||||||
|
import android.os.Build
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
|
||||||
|
object NetworkUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查当前网络是否可用
|
||||||
|
*/
|
||||||
|
fun isNetworkAvailable(context: Context): Boolean {
|
||||||
|
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
|
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
val network = connectivityManager.activeNetwork ?: return false
|
||||||
|
val activeNetwork = connectivityManager.getNetworkCapabilities(network) ?: return false
|
||||||
|
|
||||||
|
activeNetwork.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
|
||||||
|
activeNetwork.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
val networkInfo = connectivityManager.activeNetworkInfo
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
networkInfo?.isConnected == true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取网络状态变化的Flow
|
||||||
|
*/
|
||||||
|
fun getNetworkStateFlow(context: Context): Flow<Boolean> = callbackFlow {
|
||||||
|
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
|
|
||||||
|
val networkCallback = object : ConnectivityManager.NetworkCallback() {
|
||||||
|
override fun onAvailable(network: Network) {
|
||||||
|
trySend(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLost(network: Network) {
|
||||||
|
trySend(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
|
||||||
|
val hasInternet = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
|
||||||
|
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
|
||||||
|
trySend(hasInternet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val networkRequest = NetworkRequest.Builder()
|
||||||
|
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
|
||||||
|
|
||||||
|
// 发送初始状态
|
||||||
|
trySend(isNetworkAvailable(context))
|
||||||
|
|
||||||
|
awaitClose {
|
||||||
|
connectivityManager.unregisterNetworkCallback(networkCallback)
|
||||||
|
}
|
||||||
|
}.distinctUntilChanged()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user