diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4550ef6..169a1af 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools">
+
diff --git a/app/src/main/java/com/aiosman/ravenow/ui/account/AccountSetting.kt b/app/src/main/java/com/aiosman/ravenow/ui/account/AccountSetting.kt
index a3ee75f..093d2dc 100644
--- a/app/src/main/java/com/aiosman/ravenow/ui/account/AccountSetting.kt
+++ b/app/src/main/java/com/aiosman/ravenow/ui/account/AccountSetting.kt
@@ -92,7 +92,8 @@ fun AccountSetting() {
),
dragHandle = {},
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
- windowInsets = WindowInsets(0)
+ windowInsets = WindowInsets(0),
+ modifier = Modifier.height(600.dp) // 设置固定高度
) {
RemoveAccountModal(
onRemove = {
diff --git a/app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgent.kt b/app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgent.kt
index e547b38..4ae22db 100644
--- a/app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgent.kt
+++ b/app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgent.kt
@@ -19,6 +19,7 @@ import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -86,6 +87,13 @@ fun AddAgentScreen() {
}
+ // 页面退出时清空数据
+ DisposableEffect(Unit) {
+ onDispose {
+ model.clearData()
+ }
+ }
+
Column(
modifier = Modifier
.fillMaxSize()
@@ -230,10 +238,8 @@ fun AddAgentScreen() {
val result = model.createAgent(context)
if (result != null) {
println("AddAgent: Agent created successfully, closing page")
- // 创建成功,关闭页面
- model.name = ""
- model.desc = ""
- model.isFromAddAgent = false // 重置标志
+ // 创建成功,清空数据并关闭页面
+ model.clearData()
navController.popBackStack()
}
} catch (e: Exception) {
diff --git a/app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgentViewModel.kt b/app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgentViewModel.kt
index 1efc27f..cc606cc 100644
--- a/app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgentViewModel.kt
+++ b/app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgentViewModel.kt
@@ -81,4 +81,15 @@ object AddAgentViewModel : ViewModel() {
else -> null
}
}
+
+ /**
+ * 清空所有页面数据
+ */
+ fun clearData() {
+ name = ""
+ desc = ""
+ croppedBitmap = null
+ isUpdating = false
+ isFromAddAgent = false
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatAiScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatAiScreen.kt
index bb7d91e..5c0bfbc 100644
--- a/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatAiScreen.kt
+++ b/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatAiScreen.kt
@@ -8,6 +8,7 @@ import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.animateDpAsState
+import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
@@ -49,6 +50,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
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.StatusBarSpacer
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
+import com.aiosman.ravenow.utils.NetworkUtils
import com.tencent.imsdk.v2.V2TIMMessage
import kotlinx.coroutines.launch
import java.util.UUID
@@ -228,12 +231,16 @@ fun ChatAiScreen(userId: String) {
) {
isMenuExpanded = false
- viewModel.viewModelScope.launch {
- if (viewModel.notificationStrategy == "mute") {
- viewModel.updateNotificationStrategy("active")
- } else {
- viewModel.updateNotificationStrategy("mute")
+ if (NetworkUtils.isNetworkAvailable(context)) {
+ viewModel.viewModelScope.launch {
+ if (viewModel.notificationStrategy == "mute") {
+ viewModel.updateNotificationStrategy("active")
+ } else {
+ viewModel.updateNotificationStrategy("mute")
+ }
}
+ } else {
+ android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
}
}
),
@@ -260,7 +267,11 @@ fun ChatAiScreen(userId: String) {
ChatAiInput(
onSendImage = {
it?.let {
- viewModel.sendImageMessage(it, context)
+ if (NetworkUtils.isNetworkAvailable(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(
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(
modifier = Modifier
.widthIn(
min = 20.dp,
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
)
- .clip(RoundedCornerShape(8.dp))
- .background(Color(0xFF000000))
+ .clip(RoundedCornerShape(20.dp))
+ .background(Color(0xFF6246FF))
.padding(
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)
)
- .padding(bottom = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 3.dp else 0.dp))
+
) {
when (item.messageType) {
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
@@ -375,7 +395,7 @@ fun ChatAiSelfItem(item: ChatItem) {
text = item.message,
style = TextStyle(
color = Color.White,
- fontSize = 16.sp,
+ fontSize = 14.sp,
),
textAlign = TextAlign.Start
)
@@ -391,28 +411,28 @@ fun ChatAiSelfItem(item: ChatItem) {
else -> {
Text(
- text = "Unsupported message type",
+ text = "不支持的消息类型",
style = TextStyle(
color = Color.White,
- fontSize = 16.sp,
+ fontSize = 14.sp,
)
)
}
}
}
}
- Spacer(modifier = Modifier.width(12.dp))
+ /*Spacer(modifier = Modifier.width(12.dp))
Box(
modifier = Modifier
- .size(40.dp)
- .clip(RoundedCornerShape(40.dp))
+ .size(24.dp)
+ .clip(RoundedCornerShape(24.dp))
) {
CustomAsyncImage(
imageUrl = item.avatar,
modifier = Modifier.fillMaxSize(),
contentDescription = "avatar"
)
- }
+ }*/
}
}
}
@@ -432,8 +452,8 @@ fun ChatAiOtherItem(item: ChatItem) {
) {
Box(
modifier = Modifier
- .size(40.dp)
- .clip(RoundedCornerShape(40.dp))
+ .size(24.dp)
+ .clip(RoundedCornerShape(24.dp))
) {
CustomAsyncImage(
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)
)
.clip(RoundedCornerShape(8.dp))
- .background(AppColors.background)
+ .background(AppColors.bubbleBackground)
.padding(
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)
@@ -463,7 +483,7 @@ fun ChatAiOtherItem(item: ChatItem) {
text = item.message,
style = TextStyle(
color = AppColors.text,
- fontSize = 16.sp,
+ fontSize = 14.sp,
),
textAlign = TextAlign.Start
)
@@ -510,6 +530,7 @@ fun ChatAiInput(
onSendImage: (Uri?) -> Unit = {},
onSend: (String) -> Unit = {},
) {
+ val context = LocalContext.current
val navigationBarHeight = with(LocalDensity.current) {
WindowInsets.navigationBars.getBottom(this).toDp()
}
@@ -525,9 +546,8 @@ fun ChatAiInput(
), label = ""
)
- // 在 isKeyboardOpen 变化时立即更新 inputBarHeight 的动画目标值
LaunchedEffect(isKeyboardOpen) {
- inputBarHeight // 触发 inputBarHeight 的重组
+ inputBarHeight
}
val focusManager = LocalFocusManager.current
val windowInsets = WindowInsets.ime
@@ -549,71 +569,83 @@ fun ChatAiInput(
onSendImage(uri)
}
}
+ Box( modifier = Modifier
+ .fillMaxWidth()
+ .padding(start = 16.dp, end = 16.dp, bottom = 12.dp),){
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .padding(horizontal = 16.dp)
- .padding(bottom = inputBarHeight)
- ) {
- Box(
+ Row(
modifier = Modifier
- .weight(1f)
- .clip(RoundedCornerShape(16.dp))
- .background(appColors.background)
- .padding(horizontal = 16.dp),
- contentAlignment = Alignment.CenterStart,
+ .fillMaxWidth()
+ .clip(RoundedCornerShape(20.dp))
+ .background(appColors.decentBackground)
+ .padding(start = 16.dp, end = 8.dp, top = 2.dp, bottom = 2.dp),
+ verticalAlignment = Alignment.CenterVertically,
) {
- BasicTextField(
- value = text,
- onValueChange = {
- text = it
- },
- textStyle = TextStyle(
- color = appColors.text,
- fontSize = 16.sp
- ),
- cursorBrush = SolidColor(appColors.text),
+ Box(
modifier = Modifier
- .fillMaxWidth()
- .padding(vertical = 8.dp)
- .onFocusChanged { focusState ->
- isKeyboardOpen = focusState.isFocused
- }
- .pointerInput(Unit) {
- awaitPointerEventScope {
- keyboardController = softwareKeyboardController
- awaitFirstDown().also {
- keyboardController?.show()
+ .weight(1f)
+ ) {
+ BasicTextField(
+ value = text,
+ onValueChange = {
+ text = it
+ },
+ textStyle = TextStyle(
+ color = appColors.text,
+ fontSize = 16.sp
+ ),
+ cursorBrush = SolidColor(appColors.text),
+ singleLine = true,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(vertical = 8.dp)
+ .onFocusChanged { focusState ->
+ isKeyboardOpen = focusState.isFocused
+ }
+ .pointerInput(Unit) {
+ awaitPointerEventScope {
+ keyboardController = softwareKeyboardController
+ awaitFirstDown().also {
+ keyboardController?.show()
+ }
}
+ },
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
+ keyboardActions = KeyboardActions(
+ onDone = {
+ keyboardController?.hide()
}
- },
- keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
- keyboardActions = KeyboardActions(
- onDone = {
- keyboardController?.hide()
- }
+ )
)
- )
- }
- Spacer(modifier = Modifier.width(8.dp))
- Crossfade(
- targetState = text.isNotEmpty(), animationSpec = tween(500),
- label = ""
- ) { isNotEmpty ->
- Icon(
- painter = painterResource(id = R.drawable.rider_pro_video_share),
- contentDescription = "Emoji",
- modifier = Modifier
- .size(32.dp)
- .noRippleClickable {
- if (text.isNotEmpty()) {
- onSend(text)
- text = ""
- }
- },
- tint = if (isNotEmpty) appColors.main else appColors.chatActionColor
- )
+ }
+
+ Spacer(modifier = Modifier.width(8.dp))
+ Crossfade(
+ targetState = text.isNotEmpty(), animationSpec = tween(500),
+ label = ""
+ ) { isNotEmpty ->
+ val alpha by animateFloatAsState(
+ targetValue = if (isNotEmpty) 1f else 0.5f,
+ animationSpec = tween(300)
+ )
+ Image(
+ painter = painterResource(R.mipmap.rider_pro_im_send),
+ modifier = Modifier
+ .size(24.dp)
+ .alpha(alpha)
+ .noRippleClickable {
+ if (text.isNotEmpty()) {
+ if (NetworkUtils.isNetworkAvailable(context)) {
+ onSend(text)
+ text = ""
+ } else {
+ android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
+ }
+ }
+ },
+ contentDescription = null,
+ )
+ }
}
}
}
diff --git a/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatScreen.kt
index cf691b8..62b4485 100644
--- a/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatScreen.kt
+++ b/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatScreen.kt
@@ -83,6 +83,7 @@ import com.aiosman.ravenow.ui.composables.DropdownMenu
import com.aiosman.ravenow.ui.composables.MenuItem
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
+import com.aiosman.ravenow.utils.NetworkUtils
import com.tencent.imsdk.v2.V2TIMMessage
import kotlinx.coroutines.launch
import java.util.UUID
@@ -231,12 +232,16 @@ fun ChatScreen(userId: String) {
) {
isMenuExpanded = false
- viewModel.viewModelScope.launch {
- if (viewModel.notificationStrategy == "mute") {
- viewModel.updateNotificationStrategy("active")
- } else {
- viewModel.updateNotificationStrategy("mute")
+ if (NetworkUtils.isNetworkAvailable(context)) {
+ viewModel.viewModelScope.launch {
+ if (viewModel.notificationStrategy == "mute") {
+ viewModel.updateNotificationStrategy("active")
+ } else {
+ viewModel.updateNotificationStrategy("mute")
+ }
}
+ } else {
+ android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
}
}
),
@@ -262,7 +267,11 @@ fun ChatScreen(userId: String) {
ChatInput(
onSendImage = {
it?.let {
- viewModel.sendImageMessage(it, context)
+ if (NetworkUtils.isNetworkAvailable(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(
modifier = Modifier
- .size(24.dp)
- .clip(RoundedCornerShape(24.dp))
+ .size(40.dp)
+ .clip(RoundedCornerShape(40.dp))
) {
CustomAsyncImage(
- imageUrl = item.avatar.replace("storage/avatars/", "/avatar/"),
+ imageUrl = item.avatar,
modifier = Modifier.fillMaxSize(),
contentDescription = "avatar"
)
@@ -460,12 +469,13 @@ fun ChatOtherItem(item: ChatItem) {
min = 20.dp,
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
)
- .clip(RoundedCornerShape(20.dp))
- .background(AppColors.bubbleBackground)
+ .clip(RoundedCornerShape(8.dp))
+ .background(AppColors.background)
.padding(
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)
)
+ .padding(bottom = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 3.dp else 0.dp))
) {
when (item.messageType) {
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
@@ -473,7 +483,7 @@ fun ChatOtherItem(item: ChatItem) {
text = item.message,
style = TextStyle(
color = AppColors.text,
- fontSize = 14.sp,
+ fontSize = 16.sp,
),
textAlign = TextAlign.Start
)
@@ -489,7 +499,7 @@ fun ChatOtherItem(item: ChatItem) {
else -> {
Text(
- text = "不支持的消息类型",
+ text = "Unsupported message type",
style = TextStyle(
color = AppColors.text,
fontSize = 16.sp,
@@ -498,6 +508,7 @@ fun ChatOtherItem(item: ChatItem) {
}
}
}
+
}
}
@@ -519,6 +530,7 @@ fun ChatInput(
onSendImage: (Uri?) -> Unit = {},
onSend: (String) -> Unit = {},
) {
+ val context = LocalContext.current
val navigationBarHeight = with(LocalDensity.current) {
WindowInsets.navigationBars.getBottom(this).toDp()
}
@@ -614,14 +626,18 @@ fun ChatInput(
modifier = Modifier
.size(30.dp)
.noRippleClickable {
- imagePickUpLauncher.launch(
- Intent.createChooser(
- Intent(Intent.ACTION_GET_CONTENT).apply {
- type = "image/*"
- },
- "Select Image"
+ if (NetworkUtils.isNetworkAvailable(context)) {
+ imagePickUpLauncher.launch(
+ Intent.createChooser(
+ Intent(Intent.ACTION_GET_CONTENT).apply {
+ type = "image/*"
+ },
+ "Select Image"
+ )
)
- )
+ } else {
+ android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
+ }
},
)
@@ -634,19 +650,23 @@ fun ChatInput(
targetValue = if (isNotEmpty) 1f else 0.5f,
animationSpec = tween(300)
)
- Image(
- painter = painterResource(R.mipmap.rider_pro_im_send),
- modifier = Modifier
- .size(24.dp)
- .alpha(alpha)
- .noRippleClickable {
- if (text.isNotEmpty()) {
+ Image(
+ painter = painterResource(R.mipmap.rider_pro_im_send),
+ modifier = Modifier
+ .size(24.dp)
+ .alpha(alpha)
+ .noRippleClickable {
+ if (text.isNotEmpty()) {
+ if (NetworkUtils.isNetworkAvailable(context)) {
onSend(text)
text = ""
+ } else {
+ android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
}
- },
- contentDescription = null,
- )
+ }
+ },
+ contentDescription = null,
+ )
}
}
}
diff --git a/app/src/main/java/com/aiosman/ravenow/ui/chat/GroupChatScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/chat/GroupChatScreen.kt
index 7fd6c89..24ed55f 100644
--- a/app/src/main/java/com/aiosman/ravenow/ui/chat/GroupChatScreen.kt
+++ b/app/src/main/java/com/aiosman/ravenow/ui/chat/GroupChatScreen.kt
@@ -85,6 +85,7 @@ import com.aiosman.ravenow.ui.composables.MenuItem
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.aiosman.ravenow.ui.navigateToGroupInfo
+import com.aiosman.ravenow.utils.NetworkUtils
import com.tencent.imsdk.v2.V2TIMMessage
import kotlinx.coroutines.launch
import java.util.UUID
@@ -257,7 +258,11 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) {
GroupChatInput(
onSendImage = { uri ->
uri?.let {
- viewModel.sendImageMessage(it, context)
+ if (NetworkUtils.isNetworkAvailable(context)) {
+ viewModel.sendImageMessage(it, context)
+ } else {
+ android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
+ }
}
},
) { message ->
@@ -566,6 +571,7 @@ fun GroupChatInput(
onSendImage: (Uri?) -> Unit = {},
onSend: (String) -> Unit = {},
) {
+ val context = LocalContext.current
val navigationBarHeight = with(LocalDensity.current) {
WindowInsets.navigationBars.getBottom(this).toDp()
}
@@ -670,8 +676,12 @@ fun GroupChatInput(
.alpha(alpha)
.noRippleClickable {
if (text.isNotEmpty()) {
- onSend(text)
- text = ""
+ if (NetworkUtils.isNetworkAvailable(context)) {
+ onSend(text)
+ text = ""
+ } else {
+ android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
+ }
}
},
contentDescription = null,
diff --git a/app/src/main/java/com/aiosman/ravenow/ui/composables/DropdownMenu.kt b/app/src/main/java/com/aiosman/ravenow/ui/composables/DropdownMenu.kt
index 95105a3..ac04812 100644
--- a/app/src/main/java/com/aiosman/ravenow/ui/composables/DropdownMenu.kt
+++ b/app/src/main/java/com/aiosman/ravenow/ui/composables/DropdownMenu.kt
@@ -14,6 +14,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
@@ -24,7 +25,6 @@ data class MenuItem(
val title: String,
val icon: Int,
val action: () -> Unit
-
)
@Composable
@@ -36,50 +36,42 @@ fun DropdownMenu(
) {
val AppColors = LocalAppTheme.current
- MaterialTheme(
- shapes = MaterialTheme.shapes.copy(
- extraSmall = RoundedCornerShape(
- 16.dp
- )
- )
+ androidx.compose.material3.DropdownMenu(
+ expanded = expanded,
+ onDismissRequest = onDismissRequest,
+ modifier = Modifier
+ .let {
+ if (width != null) it.width(width.dp) else it
+ }
+ .background(color = AppColors.background),
) {
- androidx.compose.material3.DropdownMenu(
- expanded = expanded,
- onDismissRequest = onDismissRequest,
- modifier = Modifier
- .let {
- if (width != null) it.width(width.dp) else it
- }
- .background(AppColors.background)
- ) {
- for (item in menuItems) {
- Box(
- modifier = Modifier
- .padding(vertical = 14.dp, horizontal = 24.dp)
- .noRippleClickable {
- item.action()
- }) {
- Row(
- verticalAlignment = Alignment.CenterVertically
- ) {
- Text(
- item.title,
- fontWeight = FontWeight.W500,
- color = AppColors.text,
- )
- if (width != null) {
- Spacer(modifier = Modifier.weight(1f))
-
- } else {
- Spacer(modifier = Modifier.width(16.dp))
- }
- Icon(
- painter = painterResource(id = item.icon),
- contentDescription = "",
- modifier = Modifier.size(24.dp),
- tint = AppColors.text
- )
+ for (item in menuItems) {
+ Box(
+ modifier = Modifier
+ .padding(vertical = 14.dp, horizontal = 24.dp)
+ .noRippleClickable {
+ item.action()
}
+ ) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ item.title,
+ fontWeight = FontWeight.W500,
+ color = AppColors.text,
+ )
+ if (width != null) {
+ Spacer(modifier = Modifier.weight(1f))
+ } else {
+ Spacer(modifier = Modifier.width(16.dp))
+ }
+ Icon(
+ painter = painterResource(id = item.icon),
+ contentDescription = "",
+ modifier = Modifier.size(24.dp),
+ tint = AppColors.text
+ )
}
}
}
diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt
index 15df560..bcee8aa 100644
--- a/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt
+++ b/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt
@@ -363,7 +363,7 @@ fun IndexScreen() {
@Composable
fun Home() {
val systemUiController = rememberSystemUiController()
- LaunchedEffect(Unit) {
+ LaunchedEffect(AppState.darkMode) {
systemUiController.setStatusBarColor(Color.Transparent, darkIcons = !AppState.darkMode)
}
Column(
@@ -380,7 +380,7 @@ fun Home() {
@Composable
fun Street() {
val systemUiController = rememberSystemUiController()
- LaunchedEffect(Unit) {
+ LaunchedEffect(AppState.darkMode) {
systemUiController.setStatusBarColor(Color.Transparent, darkIcons = !AppState.darkMode)
}
Column(
@@ -396,7 +396,7 @@ fun Street() {
@Composable
fun Add() {
val systemUiController = rememberSystemUiController()
- LaunchedEffect(Unit) {
+ LaunchedEffect(AppState.darkMode) {
systemUiController.setStatusBarColor(Color.Black, darkIcons = !AppState.darkMode)
}
Column(
@@ -413,7 +413,7 @@ fun Add() {
@Composable
fun Video() {
val systemUiController = rememberSystemUiController()
- LaunchedEffect(Unit) {
+ LaunchedEffect(AppState.darkMode) {
systemUiController.setStatusBarColor(Color.Black, darkIcons = false)
}
Column(
@@ -430,7 +430,7 @@ fun Video() {
@Composable
fun Profile() {
val systemUiController = rememberSystemUiController()
- LaunchedEffect(Unit) {
+ LaunchedEffect(AppState.darkMode) {
systemUiController.setStatusBarColor(Color.Transparent, !AppState.darkMode)
}
Column(
@@ -446,7 +446,7 @@ fun Profile() {
@Composable
fun Notifications() {
val systemUiController = rememberSystemUiController()
- LaunchedEffect(Unit) {
+ LaunchedEffect(AppState.darkMode) {
systemUiController.setStatusBarColor(Color.Transparent, !AppState.darkMode)
}
Column(
diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/tab/AgentChatListScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/tab/AgentChatListScreen.kt
index 741d5f5..b1e76d0 100644
--- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/tab/AgentChatListScreen.kt
+++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/tab/AgentChatListScreen.kt
@@ -44,6 +44,7 @@ import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
+import com.aiosman.ravenow.utils.NetworkUtils
/**
* 智能体聊天列表页面
@@ -123,8 +124,12 @@ fun AgentChatListScreen() {
AgentChatListViewModel.goToUserDetail(conv, navController)
},
onChatClick = { conv ->
- model.createSingleChat(conv.trtcUserId)
- model.goToChatAi(conv.trtcUserId,navController)
+ if (NetworkUtils.isNetworkAvailable(context)) {
+ model.createSingleChat(conv.trtcUserId)
+ model.goToChatAi(conv.trtcUserId,navController)
+ } else {
+ android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
+ }
}
)
diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/tab/FriendChatListScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/tab/FriendChatListScreen.kt
index 6c19e92..1c084ad 100644
--- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/tab/FriendChatListScreen.kt
+++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/tab/FriendChatListScreen.kt
@@ -32,6 +32,7 @@ import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
+import com.aiosman.ravenow.utils.NetworkUtils
@OptIn(ExperimentalMaterialApi::class)
@Composable
@@ -106,7 +107,11 @@ fun FriendChatListScreen() {
FriendChatListViewModel.goToUserDetail(conv, navController)
},
onChatClick = { conv ->
- FriendChatListViewModel.goToChat(conv, navController)
+ if (NetworkUtils.isNetworkAvailable(context)) {
+ FriendChatListViewModel.goToChat(conv, navController)
+ } else {
+ android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show()
+ }
}
)
diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/tab/GroupChatListScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/tab/GroupChatListScreen.kt
index 3c58c4c..5aab6b0 100644
--- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/tab/GroupChatListScreen.kt
+++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/tab/GroupChatListScreen.kt
@@ -1,8 +1,6 @@
package com.aiosman.ravenow.ui.index.tabs.message.tab
-import androidx.compose.foundation.Image
import androidx.compose.foundation.background
-import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
@@ -16,14 +14,11 @@ import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
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.platform.LocalContext
-import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
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.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
+import com.aiosman.ravenow.utils.NetworkUtils
@OptIn(ExperimentalMaterialApi::class)
@Composable
@@ -51,15 +47,6 @@ fun GroupChatListScreen() {
LaunchedEffect(Unit) {
GroupChatListViewModel.refreshPager(context = context)
- // 初始化消息监听器
- GroupChatListViewModel.initMessageListener(context)
- }
-
- // 在组件销毁时清理监听器
- DisposableEffect(Unit) {
- onDispose {
- GroupChatListViewModel.removeMessageListener()
- }
}
@@ -79,31 +66,18 @@ fun GroupChatListScreen() {
.fillMaxSize()
.padding(16.dp),
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 = stringResource(R.string.group_chat_empty_title),
+ text = "暂无群聊",
color = AppColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.height(8.dp))
Text(
- text = stringResource(R.string.group_chat_empty_subtitle),
- color = AppColors.text,
+ text = "您还没有加入任何群聊",
+ color = AppColors.secondaryText,
fontSize = 14.sp
)
}
@@ -121,10 +95,20 @@ fun GroupChatListScreen() {
GroupChatListViewModel.goToGroupDetail(conv, navController)
},
onChatClick = { conv ->
- GroupChatListViewModel.goToChat(conv, navController)
+ if (NetworkUtils.isNetworkAvailable(context)) {
+ 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()) {
@@ -180,11 +164,10 @@ fun GroupChatItem(
Row(
modifier = Modifier
.fillMaxWidth()
- .padding(horizontal = 16.dp, vertical = 12.dp)
+ .padding(horizontal = 24.dp, vertical = 12.dp)
.noRippleClickable {
onChatClick(conversation)
- },
- verticalAlignment = Alignment.CenterVertically
+ }
) {
Box {
CustomAsyncImage(
@@ -202,9 +185,9 @@ fun GroupChatItem(
Column(
modifier = Modifier
+
.weight(1f)
- .padding(start = 12.dp, top = 2.dp),
- verticalArrangement = Arrangement.Center
+ .padding(start = 12.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
@@ -212,22 +195,22 @@ fun GroupChatItem(
) {
Text(
text = conversation.groupName,
- fontSize = 14.sp,
+ fontSize = 16.sp,
fontWeight = FontWeight.Bold,
color = AppColors.text,
modifier = Modifier.weight(1f)
)
- Spacer(modifier = Modifier.width(6.dp))
+ Spacer(modifier = Modifier.width(8.dp))
Text(
text = conversation.lastMessageTime,
- fontSize = 11.sp,
+ fontSize = 12.sp,
color = AppColors.secondaryText
)
}
- Spacer(modifier = Modifier.height(6.dp))
+ Spacer(modifier = Modifier.height(4.dp))
Row(
modifier = Modifier.fillMaxWidth(),
@@ -235,29 +218,30 @@ fun GroupChatItem(
) {
Text(
text = "${if (conversation.isSelf) stringResource(R.string.friend_chat_me_prefix) else ""}${conversation.displayText}",
- fontSize = 12.sp,
+ fontSize = 14.sp,
color = AppColors.secondaryText,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f)
)
- Spacer(modifier = Modifier.width(10.dp))
+ Spacer(modifier = Modifier.width(8.dp))
if (conversation.unreadCount > 0) {
Box(
modifier = Modifier
.size(if (conversation.unreadCount > 99) 24.dp else 20.dp)
.background(
- color = Color(0xFFFF3B30),
+ color = AppColors.main,
shape = CircleShape
),
contentAlignment = Alignment.Center
) {
Text(
text = if (conversation.unreadCount > 99) "99+" else conversation.unreadCount.toString(),
- color = Color.White,
- fontSize = if (conversation.unreadCount > 99) 11.sp else 12.sp,
+ color = AppColors.mainText,
+ fontSize = if (conversation.unreadCount > 99) 9.sp else 10.sp,
+ fontWeight = FontWeight.Bold
)
}
}
diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/profile/ProfileV3.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/profile/ProfileV3.kt
index d38c960..015911b 100644
--- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/profile/ProfileV3.kt
+++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/profile/ProfileV3.kt
@@ -26,6 +26,7 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.lazy.grid.GridCells
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.rememberPagerState
import androidx.compose.foundation.shape.CircleShape
@@ -140,6 +141,7 @@ fun ProfileV3(
val AppColors = appTheme
val systemUiController = rememberSystemUiController()
val listState = rememberLazyListState()
+ val gridState = rememberLazyGridState()
// observe list scrolling
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) {
if (reachedListBottom) {
onLoadMore()
}
}
+ // load more if scrolled to bottom of grid
+ LaunchedEffect(reachedGridBottom) {
+ if (reachedGridBottom) {
+ onLoadMore()
+ }
+ }
+
fun switchTheme() {
@@ -451,15 +468,16 @@ fun ProfileV3(
pagerState = pagerState,
)
Spacer(modifier = Modifier.height(8.dp))
- HorizontalPager(
- state = pagerState,
- ) { idx ->
- when (idx) {
- 0 ->
- LazyVerticalGrid(
- columns = GridCells.Fixed(3),
- modifier = Modifier.fillMaxSize().padding(bottom = 8.dp),
- ) {
+ HorizontalPager(
+ state = pagerState,
+ ) { idx ->
+ when (idx) {
+ 0 ->
+ LazyVerticalGrid(
+ columns = GridCells.Fixed(3),
+ state = gridState,
+ modifier = Modifier.fillMaxSize().padding(bottom = 8.dp),
+ ) {
items(moments.size) { idx ->
val moment = moments[idx] ?: return@items
diff --git a/app/src/main/java/com/aiosman/ravenow/utils/NetworkUtils.kt b/app/src/main/java/com/aiosman/ravenow/utils/NetworkUtils.kt
new file mode 100644
index 0000000..fb21f1f
--- /dev/null
+++ b/app/src/main/java/com/aiosman/ravenow/utils/NetworkUtils.kt
@@ -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 = 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()
+}