27 Commits

Author SHA1 Message Date
2f2da0a159 lottie 依赖 2025-10-17 15:27:12 +08:00
4ffaf3c3a8 Merge pull request #38 from Kevinlinpr/zhong
编辑资料页面UI调整:添加横幅图片区域
2025-10-16 18:10:11 +08:00
29490d288b “我的”页面UI调整 2025-10-16 18:06:24 +08:00
a99ab30c4e 编辑资料页面UI调整:添加横幅图片区域 2025-10-15 18:54:04 +08:00
0442925ae9 Merge pull request #37 from Kevinlinpr/zhong
解决问题:首页智能体头像为默认头像时显示为空
2025-10-14 18:20:22 +08:00
9d3d13a22d 新增消息界面“全部”标签页 2025-10-14 17:40:25 +08:00
f0a9704e2d 个人信息页和用户信息页UI调整 2025-10-13 18:49:47 +08:00
7f2c103ada 修改首页智能体头像显示逻辑,先显示默认头像(所有情况都显示)如果有网络头像则覆盖显示。 2025-10-11 18:55:39 +08:00
bd01ae39d0 Merge pull request #36 from Kevinlinpr/zhong
UI调整
2025-10-10 21:42:24 +08:00
d94e3b5c20 消息界面通知按钮点击事件;新增通知界面 2025-10-10 18:41:57 +08:00
44cc76d2e3 日文资源文件
实现重新加载功能
收藏界面UI调整
2025-10-09 17:36:06 +08:00
fac6f23356 新建文件夹 app/src/main/assets 将.lottie文件放入
UI调整
2025-09-30 18:54:35 +08:00
39928abc46 Merge pull request #35 from Zhong202501/main
缺省图
2025-09-30 15:53:37 +08:00
4d0d7004b0 缺省图 2025-09-29 18:29:59 +08:00
28a6e3fef3 Merge pull request #34 from Zhong202501/main
添加启动界面
2025-09-28 18:50:51 +08:00
b275d88ef7 添加启动界面 2025-09-28 18:24:54 +08:00
595ef7f942 Merge pull request #33 from Zhong202501/main
Agent创建成功全局显示; 适配暗黑模式
2025-09-27 20:11:44 +08:00
1202b55c74 text颜色 2025-09-26 18:50:51 +08:00
074009d256 添加界面状态恢复逻辑 2025-09-26 18:31:27 +08:00
ad1de9e3f7 Agent创建成功全局显示;
适配暗黑模式
2025-09-26 17:01:46 +08:00
359bcfdfd7 Agent创建成功全局显示;
适配暗黑模式
2025-09-26 17:00:12 +08:00
1901fddb2e Merge pull request #32 from Zhong202501/main
创建弹窗UI调整
2025-09-26 11:29:03 +08:00
b96ae94bdb 界面逻辑优化 2025-09-25 18:32:34 +08:00
dedd356896 创建弹窗UI调整 2025-09-24 18:51:20 +08:00
bb9fda75ae Merge pull request #31 from Zhong202501/main
AI美化功能; 输入框逻辑优化; 文本资源文件;
2025-09-24 14:35:08 +08:00
ea911f113b AI美化功能 2025-09-23 18:32:01 +08:00
88f379fe5b Merge pull request #30 from Kevinlinpr/agent_scroll
优化AI界面,添加分页加载功能,支持动态加载更多智能体数据;重构UI布局
2025-09-23 13:43:55 +08:00
140 changed files with 2748 additions and 808 deletions

View File

@@ -125,7 +125,7 @@ dependencies {
// 添加 lifecycle-runtime-ktx 依赖 // 添加 lifecycle-runtime-ktx 依赖
implementation(libs.androidx.lifecycle.runtime.ktx.v262) implementation(libs.androidx.lifecycle.runtime.ktx.v262)
implementation (libs.eventbus) implementation (libs.eventbus)
implementation(libs.lottie)
} }

Binary file not shown.

View File

@@ -45,6 +45,7 @@ object AppState {
var googleClientId: String? = null var googleClientId: String? = null
var enableGoogleLogin: Boolean = false var enableGoogleLogin: Boolean = false
var enableChat = false var enableChat = false
var agentCreatedSuccess by mutableStateOf(false)
suspend fun initWithAccount(scope: CoroutineScope, context: Context) { suspend fun initWithAccount(scope: CoroutineScope, context: Context) {
// 如果是游客模式,使用简化的初始化流程 // 如果是游客模式,使用简化的初始化流程
if (AppStore.isGuest) { if (AppStore.isGuest) {

View File

@@ -43,7 +43,12 @@ import com.google.firebase.analytics.analytics
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import androidx.compose.runtime.remember
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import com.aiosman.ravenow.ui.splash.SplashScreen
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
// Firebase Analytics // Firebase Analytics
@@ -122,11 +127,22 @@ class MainActivity : ComponentActivity() {
} }
setContent { setContent {
var showSplash by remember { mutableStateOf(true) }
LaunchedEffect(Unit) {
kotlinx.coroutines.delay(2000)
showSplash = false
}
if (showSplash) {
SplashScreen()
} else {
CompositionLocalProvider( CompositionLocalProvider(
LocalAppTheme provides AppState.appTheme LocalAppTheme provides AppState.appTheme
) { ) {
CheckUpdateDialog() CheckUpdateDialog()
Navigation(startDestination) { navController -> Navigation(startDestination) { navController ->
// 处理带有 postId 的通知点击 // 处理带有 postId 的通知点击
val postId = intent.getStringExtra("POST_ID") val postId = intent.getStringExtra("POST_ID")
var commentId = intent.getStringExtra("COMMENT_ID") var commentId = intent.getStringExtra("COMMENT_ID")
@@ -179,17 +195,15 @@ class MainActivity : ComponentActivity() {
} }
NewPostViewModel.asNewPostWithImageUris(imageUris!!.map { it.toString() }) NewPostViewModel.asNewPostWithImageUris(imageUris!!.map { it.toString() })
navController.navigate(NavigationRoute.NewPost.route) navController.navigate(NavigationRoute.NewPost.route)
}
}
}
}
} }
} }
} }
}
}
}
/** /**
* 请求通知权限 * 请求通知权限

View File

@@ -45,6 +45,7 @@ import com.aiosman.ravenow.ui.chat.ChatScreen
import com.aiosman.ravenow.ui.chat.GroupChatScreen import com.aiosman.ravenow.ui.chat.GroupChatScreen
import com.aiosman.ravenow.ui.comment.CommentsScreen import com.aiosman.ravenow.ui.comment.CommentsScreen
import com.aiosman.ravenow.ui.comment.notice.CommentNoticeScreen import com.aiosman.ravenow.ui.comment.notice.CommentNoticeScreen
import com.aiosman.ravenow.ui.composables.AgentCreatedSuccessIndicator
import com.aiosman.ravenow.ui.crop.ImageCropScreen import com.aiosman.ravenow.ui.crop.ImageCropScreen
import com.aiosman.ravenow.ui.favourite.FavouriteListPage import com.aiosman.ravenow.ui.favourite.FavouriteListPage
import com.aiosman.ravenow.ui.favourite.FavouriteNoticeScreen import com.aiosman.ravenow.ui.favourite.FavouriteNoticeScreen
@@ -70,6 +71,7 @@ import com.aiosman.ravenow.ui.post.NewPostScreen
import com.aiosman.ravenow.ui.post.PostScreen import com.aiosman.ravenow.ui.post.PostScreen
import com.aiosman.ravenow.ui.profile.AccountProfileV2 import com.aiosman.ravenow.ui.profile.AccountProfileV2
import com.aiosman.ravenow.ui.index.tabs.profile.vip.VipSelPage import com.aiosman.ravenow.ui.index.tabs.profile.vip.VipSelPage
import com.aiosman.ravenow.ui.notification.NotificationScreen
sealed class NavigationRoute( sealed class NavigationRoute(
val route: String, val route: String,
@@ -115,6 +117,7 @@ sealed class NavigationRoute(
data object GroupInfo : NavigationRoute("GroupInfo/{id}") data object GroupInfo : NavigationRoute("GroupInfo/{id}")
data object VipSelPage : NavigationRoute("VipSelPage") data object VipSelPage : NavigationRoute("VipSelPage")
data object RemoveAccountScreen: NavigationRoute("RemoveAccount") data object RemoveAccountScreen: NavigationRoute("RemoveAccount")
data object NotificationScreen : NavigationRoute("NotificationScreen")
} }
@@ -590,6 +593,13 @@ fun NavigationController(
} }
} }
composable(route = NavigationRoute.NotificationScreen.route) {
CompositionLocalProvider(
LocalAnimatedContentScope provides this,
) {
NotificationScreen()
}
}
} }
@@ -615,6 +625,7 @@ fun Navigation(
navController = navController, navController = navController,
startDestination = startDestination startDestination = startDestination
) )
AgentCreatedSuccessIndicator()
} }
} }
} }

View File

@@ -1,5 +1,8 @@
package com.aiosman.ravenow.ui.account package com.aiosman.ravenow.ui.account
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -47,12 +50,24 @@ import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import android.util.Log import android.util.Log
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Text
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import com.aiosman.ravenow.ConstVars
import com.aiosman.ravenow.ui.composables.pickupAndCompressLauncher
import java.io.File
/** /**
* 编辑用户资料界面 * 编辑用户资料界面
*/ */
@Composable @Composable
fun AccountEditScreen2() { fun AccountEditScreen2(onUpdateBanner: ((Uri, File, Context) -> Unit)? = null,) {
val model = AccountEditViewModel val model = AccountEditViewModel
val navController = LocalNavController.current val navController = LocalNavController.current
val context = LocalContext.current val context = LocalContext.current
@@ -61,6 +76,19 @@ fun AccountEditScreen2() {
// 防抖导航器 // 防抖导航器
val debouncedNavigation = rememberDebouncedNavigation() val debouncedNavigation = rememberDebouncedNavigation()
// 添加图片选择启动器
val scope = rememberCoroutineScope()
val pickBannerImageLauncher = pickupAndCompressLauncher(
context,
scope,
maxSize = ConstVars.BANNER_IMAGE_MAX_SIZE,
quality = 100
) { uri, file ->
// 处理选中的图片
onUpdateBanner?.invoke(uri, file, context)
}
fun onNicknameChange(value: String) { fun onNicknameChange(value: String) {
// 去除换行符,确保昵称不包含换行 // 去除换行符,确保昵称不包含换行
val cleanValue = value.replace("\n", "").replace("\r", "") val cleanValue = value.replace("\n", "").replace("\r", "")
@@ -152,7 +180,60 @@ fun AccountEditScreen2() {
) )
} }
} }
Spacer(modifier = Modifier.height(44.dp))
// 添加横幅图片区域
val banner = model.profile?.banner
Box(
modifier = Modifier
.fillMaxWidth()
.height(300.dp)
.clip(RoundedCornerShape(12.dp))
) {
if (banner != null) {
CustomAsyncImage(
context = LocalContext.current,
imageUrl = banner,
modifier = Modifier.fillMaxSize(),
contentDescription = "Banner",
contentScale = ContentScale.Crop
)
} else {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Gray.copy(alpha = 0.1f))
)
}
Box(
modifier = Modifier
.width(120.dp)
.height(42.dp)
.align(Alignment.BottomEnd)
.padding(end = 12.dp, bottom = 12.dp)
.background(
color = Color.Black.copy(alpha = 0.4f),
shape = RoundedCornerShape(9.dp)
)
.noRippleClickable {
Intent(Intent.ACTION_PICK).apply {
type = "image/*"
pickBannerImageLauncher.launch(this)
}
}
){
Text(
text = "change",
fontSize = 14.sp,
fontWeight = FontWeight.W600,
color = Color.White,
modifier = Modifier.align(Alignment.Center)
)
}
}
Spacer(modifier = Modifier.height(20.dp))
// 显示内容或加载状态 // 显示内容或加载状态
Log.d("AccountEditScreen2", "UI状态 - profile: ${model.profile?.nickName}, isLoading: ${model.isLoading}") Log.d("AccountEditScreen2", "UI状态 - profile: ${model.profile?.nickName}, isLoading: ${model.isLoading}")
@@ -180,7 +261,15 @@ fun AccountEditScreen2() {
modifier = Modifier modifier = Modifier
.size(32.dp) .size(32.dp)
.clip(CircleShape) .clip(CircleShape)
.background(appColors.main) .background(
brush = Brush.linearGradient(
colors = listOf(
Color(0xFF7c45ed),
Color(0x997c68ef),
Color(0xFF7bd8f8)
)
),
)
.align(Alignment.BottomEnd) .align(Alignment.BottomEnd)
.debouncedClickable( .debouncedClickable(
debounceTime = 800L debounceTime = 800L
@@ -198,7 +287,7 @@ fun AccountEditScreen2() {
) )
} }
} }
Spacer(modifier = Modifier.height(58.dp)) Spacer(modifier = Modifier.height(18.dp))
Column( Column(
modifier = Modifier modifier = Modifier
.weight(1f) .weight(1f)

View File

@@ -74,6 +74,17 @@ import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.offset
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.text.TextStyle
import com.aiosman.ravenow.ui.agent.AddAgentViewModel.showManualCreation
import com.airbnb.lottie.compose.LottieAnimation
import com.airbnb.lottie.compose.LottieCompositionSpec
import com.airbnb.lottie.compose.LottieConstants
import com.airbnb.lottie.compose.rememberLottieComposition
/** /**
* 添加智能体界面 * 添加智能体界面
*/ */
@@ -87,7 +98,10 @@ fun AddAgentScreen() {
var errorMessage by remember { mutableStateOf<String?>(null) } var errorMessage by remember { mutableStateOf<String?>(null) }
var isProcessing by remember { mutableStateOf(false) } var isProcessing by remember { mutableStateOf(false) }
var showWaveAnimation by remember { mutableStateOf(false) } var showWaveAnimation by remember { mutableStateOf(false) }
var isCreatingAgent by remember { mutableStateOf(false) } // 控制是否处于创建状态
var showManualCreationForm by remember { mutableStateOf(false) } // 控制是否显示手动创建表单
var tempDesc by remember { mutableStateOf("") } // 独立的临时描述变量
val keyboardController = LocalSoftwareKeyboardController.current
fun onNameChange(value: String) { fun onNameChange(value: String) {
model.name = value.trim() model.name = value.trim()
@@ -101,15 +115,37 @@ fun AddAgentScreen() {
fun onDescChange(value: String) { fun onDescChange(value: String) {
model.desc = value.trim() model.desc = value.trim()
agnetDescError = when { agnetDescError = when {
value.length > 100 -> "简介长度不能大于100" value.length > 512 -> "简介长度不能大于512"
else -> null
}
}
fun onTempDescChange(value: String) {
tempDesc = value.trim()
agnetDescError = when {
value.length > 512 -> "简介长度不能大于512"
else -> null else -> null
} }
} }
fun validate(): Boolean { fun validate(): Boolean {
return agnetNameError == null && agnetDescError == null return agnetNameError == null && agnetDescError == null
} }
// AI文案优化
suspend fun optimizeTextWithAI(content: String): String? {
return try {
val sessionId = ""
val response = com.aiosman.ravenow.data.api.ApiClient.api.agentMoment(
com.aiosman.ravenow.data.api.AgentMomentRequestBody(
generateText = content,
sessionId = sessionId
)
)
response.body()?.data
} catch (e: Exception) {
e.printStackTrace()
null
}
}
// 处理系统返回键 // 处理系统返回键
BackHandler { BackHandler {
@@ -123,7 +159,22 @@ fun AddAgentScreen() {
// 页面进入时重置头像选择状态 // 页面进入时重置头像选择状态
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
model.isSelectingAvatar = false model.isSelectingAvatar = false
// 根据标记恢复相应的状态
if (model.isAutoModeManualForm) {
// 恢复自动模式下的手动表单状态
showManualCreationForm = model.showManualCreationForm
isCreatingAgent = model.isCreatingAgent
showWaveAnimation = model.showWaveAnimation
showManualCreation = model.showManualCreation
} else {
// 恢复手动模式下的状态
showManualCreation = model.showManualCreation
showManualCreationForm = model.showManualCreationForm
isCreatingAgent = model.isCreatingAgent
showWaveAnimation = model.showWaveAnimation
} }
}
Column( Column(
modifier = Modifier modifier = Modifier
@@ -131,7 +182,9 @@ fun AddAgentScreen() {
.background(color = appColors.decentBackground), .background(color = appColors.decentBackground),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
var showManualCreation by remember { mutableStateOf(false) } var showManualCreation by remember {
mutableStateOf(model.showManualCreation)
}
StatusBarSpacer() StatusBarSpacer()
Box( Box(
modifier = Modifier.padding(horizontal = 14.dp, vertical = 16.dp) modifier = Modifier.padding(horizontal = 14.dp, vertical = 16.dp)
@@ -168,6 +221,8 @@ fun AddAgentScreen() {
} }
} }
Spacer(modifier = Modifier.height(1.dp)) Spacer(modifier = Modifier.height(1.dp))
if (!isCreatingAgent) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -185,17 +240,20 @@ fun AddAgentScreen() {
contentScale = ContentScale.Crop contentScale = ContentScale.Crop
) )
} }
}
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
Column( Column(
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
.padding(start = 20.dp) .padding(start = 20.dp)
) { ) {
Text( Text(
text = "${AppState.profile?.nickName ?: "User"} 你好呀!今天想创造什么?", text = "${AppState.profile?.nickName ?: "User"} ${stringResource(R.string.welcome_1)}",
fontSize = 16.sp, fontSize = 16.sp,
color = appColors.text,
fontWeight = FontWeight.W600 fontWeight = FontWeight.W600
) )
} }
if (!isCreatingAgent) {
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Column( Column(
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
@@ -203,16 +261,17 @@ fun AddAgentScreen() {
) { ) {
if (!showManualCreation) { if (!showManualCreation) {
Text( Text(
text = "只需要一句话你的专属AI将在这里诞生。", text = stringResource(R.string.welcome_2),
fontSize = 14.sp, fontSize = 14.sp,
color = LocalAppTheme.current.text.copy(alpha = 0.6f), color = appColors.text.copy(alpha = 0.6f),
) )
} }
} }
}
Spacer(modifier = Modifier.height(24.dp)) Spacer(modifier = Modifier.height(24.dp))
if (!showManualCreation) { if (!showManualCreation) {
//自动创造AI界面
Column( Column(
modifier = Modifier modifier = Modifier
.padding(horizontal = 20.dp) .padding(horizontal = 20.dp)
@@ -245,7 +304,6 @@ fun AddAgentScreen() {
) )
) { ) {
val focusRequester = remember { FocusRequester() } val focusRequester = remember { FocusRequester() }
val keyboardController = LocalSoftwareKeyboardController.current
Box( Box(
modifier = Modifier modifier = Modifier
@@ -258,36 +316,71 @@ fun AddAgentScreen() {
} }
) )
FormTextInput2( TextField(
value = model.desc, value = tempDesc,
hint = "一个会写诗的AI一个懂你笑点的AI...", onValueChange = { value -> onTempDescChange(value) },
background = appColors.inputBackground2,
focusRequester = focusRequester,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(95.dp) .height(95.dp)
) { value -> .focusRequester(focusRequester),
onDescChange(value) placeholder = {
} Text(
text = stringResource(R.string.agent_desc_hint_auto),
color = Color.Gray
)
},
textStyle = TextStyle(
color = LocalAppTheme.current.text,
fontSize = 16.sp
),
colors = TextFieldDefaults.colors(
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
focusedContainerColor = appColors.inputBackground2,
unfocusedContainerColor = appColors.inputBackground2,
),
shape = RoundedCornerShape(10.dp),
supportingText = null,
trailingIcon = null,
leadingIcon = null
)
Row( Row(
modifier = Modifier modifier = Modifier
.align(Alignment.BottomEnd) .align(Alignment.BottomEnd)
.padding(end = 12.dp, bottom = 12.dp) .padding(end = 12.dp, bottom = 12.dp)
.noRippleClickable { .noRippleClickable {
if (!isProcessing && model.desc.isNotEmpty()) { // 只有在有内容且未处理中且未创建中时才可点击
if (tempDesc.isNotEmpty() && !isProcessing && !isCreatingAgent) {
isProcessing = true isProcessing = true
showWaveAnimation = true // 显示构思动画
keyboardController?.hide()
model.viewModelScope.launch { model.viewModelScope.launch {
try { try {
//AI美化功能待实现 val optimizedText = optimizeTextWithAI(tempDesc)
if (optimizedText != null) {
onTempDescChange(optimizedText)
}
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} finally { } finally {
isProcessing = false isProcessing = false
showWaveAnimation = false
isCreatingAgent = true
showManualCreationForm = true
onDescChange(tempDesc)
} }
} }
} }
}, }
.then(
if (tempDesc.isEmpty() || isProcessing || isCreatingAgent) {
Modifier.alpha(0.5f)
} else {
Modifier
}
),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Icon( Icon(
@@ -298,7 +391,7 @@ fun AddAgentScreen() {
) )
Spacer(modifier = Modifier.width(5.dp)) Spacer(modifier = Modifier.width(5.dp))
Text( Text(
text = "AI美化", text = stringResource(R.string.agent_text_beautify),
color = Color(0xFF6246FF), color = Color(0xFF6246FF),
fontSize = 14.sp fontSize = 14.sp
) )
@@ -306,7 +399,8 @@ fun AddAgentScreen() {
} }
} }
Spacer(modifier = Modifier.height(24.dp)) Spacer(modifier = Modifier.height(24.dp))
if (showWaveAnimation) { if ((isCreatingAgent && showWaveAnimation) || (isProcessing && showWaveAnimation)) {
// 显示构思动画
Row( Row(
modifier = Modifier modifier = Modifier
.align(Alignment.Start) .align(Alignment.Start)
@@ -314,83 +408,113 @@ fun AddAgentScreen() {
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Box( Box(
modifier = Modifier.size(18.dp) modifier = Modifier.size(32.dp)
) { ) {
val infiniteTransition = rememberInfiniteTransition() LottieAnimation(
val dot1Translation by infiniteTransition.animateFloat( composition = rememberLottieComposition(LottieCompositionSpec.Asset("loading.lottie")).value,
initialValue = 0f, iterations = LottieConstants.IterateForever,
targetValue = -12f, modifier = Modifier.matchParentSize()
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 1000,
easing = FastOutSlowInEasing
),
repeatMode = RepeatMode.Reverse,
initialStartOffset = StartOffset(0)
)
)
val dot2Translation by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = -12f,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 1000,
easing = FastOutSlowInEasing
),
repeatMode = RepeatMode.Reverse,
initialStartOffset = StartOffset(333)
)
)
val dot3Translation by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = -12f,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 1000,
easing = FastOutSlowInEasing
),
repeatMode = RepeatMode.Reverse,
initialStartOffset = StartOffset(666)
)
)
// 三个彩色圆点
Box(
modifier = Modifier
.size(6.dp)
.align(Alignment.BottomStart)
.offset(y = dot1Translation.dp)
.background(Color(0xFFFFD400), CircleShape)
)
Box(
modifier = Modifier
.size(6.dp)
.align(Alignment.BottomCenter)
.offset(y = dot2Translation.dp)
.background(Color(0xFF2F80FF), CircleShape)
)
Box(
modifier = Modifier
.size(6.dp)
.align(Alignment.BottomEnd)
.offset(y = dot3Translation.dp)
.background(Color(0xFF27C84D), CircleShape)
) )
} }
Spacer(modifier = Modifier.width(8.dp))
Text( Text(
text = "正在为你构思", text = stringResource(R.string.ideaing),
color = Color.Black.copy(alpha = 0.6f), color = appColors.text.copy(alpha = 0.6f),
fontSize = 14.sp fontSize = 14.sp
) )
} }
} else if (isCreatingAgent && !showWaveAnimation && showManualCreationForm) {
Column(
modifier = Modifier
.padding(horizontal = 16.dp)
.align(Alignment.Start)
) {
Text(
text = stringResource(R.string.avatar),
fontSize = 12.sp,
color = appColors.text,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.height(4.dp))
Box(
modifier = Modifier
.size(72.dp)
.clip(CircleShape)
.background(
brush = Brush.linearGradient(
colors = listOf(
Color(0x777c45ed),
Color(0x777c68ef),
Color(0x557bd8f8)
)
)
)
.align(Alignment.Start)
.noRippleClickable {
// 保存当前状态
model.showManualCreationForm = showManualCreationForm
model.isCreatingAgent = isCreatingAgent
model.showWaveAnimation = showWaveAnimation
model.showManualCreation = showManualCreation
model.isAutoModeManualForm = true // 标记为自动模式下的手动表单
// 设置正在选择头像的标志
model.isSelectingAvatar = true
navController.navigate(NavigationRoute.AgentImageCrop.route)
},
contentAlignment = Alignment.Center
){
// 如果已有裁剪后的头像,则显示头像,否则显示编辑图标
if (model.croppedBitmap != null) {
Image(
bitmap = model.croppedBitmap!!.asImageBitmap(),
contentDescription = "Avatar",
modifier = Modifier
.size(72.dp)
.clip(CircleShape),
contentScale = ContentScale.Crop
)
} else { } else {
Icon(
painter = painterResource(id = R.mipmap.icons_infor_edit),
contentDescription = "Edit",
tint = Color.White,
modifier = Modifier.size(20.dp),
)
}
}
Spacer(modifier = Modifier.height(18.dp))
// 原版两个输入框
Text(
text = stringResource(R.string.agent_name),
fontSize = 12.sp,
color = appColors.text,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.height(4.dp))
FormTextInput(
value = model.name,
hint = stringResource(R.string.agent_name_hint_1),
background = appColors.inputBackground2,
modifier = Modifier.fillMaxWidth(),
) { value ->
onNameChange(value)
}
Text(
text = stringResource(R.string.agent_desc),
fontSize = 12.sp,
color = appColors.text,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.height(4.dp))
FormTextInput2(
value = model.desc,
hint = stringResource(R.string.agent_desc_hint),
background = appColors.inputBackground2,
modifier = Modifier.fillMaxWidth(),
) { value ->
onDescChange(value)
}
}
} else if (!isCreatingAgent && !showWaveAnimation) {
Box( Box(
modifier = Modifier modifier = Modifier
.align(Alignment.Start) .align(Alignment.Start)
@@ -408,6 +532,8 @@ fun AddAgentScreen() {
) )
.noRippleClickable { .noRippleClickable {
showManualCreation = true showManualCreation = true
tempDesc = ""
agnetDescError = null
} }
) { ) {
Row( Row(
@@ -419,12 +545,13 @@ fun AddAgentScreen() {
Icon( Icon(
painter = painterResource(id = R.mipmap.icons_infor_edit), painter = painterResource(id = R.mipmap.icons_infor_edit),
contentDescription = null, contentDescription = null,
tint = appColors.text,
modifier = Modifier.size(18.dp), modifier = Modifier.size(18.dp),
) )
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
Text( Text(
text = "手动创造Ai", text = stringResource(R.string.create_agent_hand),
color = Color.Black, color = appColors.text,
fontWeight = FontWeight.W600, fontWeight = FontWeight.W600,
fontSize = 14.sp fontSize = 14.sp
) )
@@ -432,12 +559,12 @@ fun AddAgentScreen() {
} }
} }
}else { }else {
//手动创造AI界面
Column( Column(
modifier = Modifier modifier = Modifier
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
.align(Alignment.Start) .align(Alignment.Start)
) { ) {
// 添加新的一句话创造AI按钮
Box( Box(
modifier = Modifier modifier = Modifier
.align(Alignment.Start) .align(Alignment.Start)
@@ -466,6 +593,13 @@ fun AddAgentScreen() {
) )
.noRippleClickable { .noRippleClickable {
showManualCreation = false showManualCreation = false
model.name = ""
model.desc = ""
model.croppedBitmap = null
isCreatingAgent = false
showManualCreationForm = false
showWaveAnimation = false
isProcessing = false
} }
) { ) {
Row( Row(
@@ -477,13 +611,13 @@ fun AddAgentScreen() {
Icon( Icon(
painter = painterResource(id = R.mipmap.icons_info_magic), painter = painterResource(id = R.mipmap.icons_info_magic),
contentDescription = null, contentDescription = null,
tint = Color.Black, tint = appColors.text,
modifier = Modifier.size(18.dp), modifier = Modifier.size(18.dp),
) )
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
Text( Text(
text = "一句话创造AI", text = stringResource(R.string.create_agent_auto),
color = Color.Black, color = appColors.text,
fontWeight = FontWeight.W600, fontWeight = FontWeight.W600,
fontSize = 14.sp fontSize = 14.sp
) )
@@ -492,8 +626,9 @@ fun AddAgentScreen() {
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
Text( Text(
text = "头像", text = stringResource(R.string.avatar),
fontSize = 12.sp, fontSize = 12.sp,
color = appColors.text,
fontWeight = FontWeight.W600 fontWeight = FontWeight.W600
) )
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
@@ -512,12 +647,29 @@ fun AddAgentScreen() {
) )
.align(Alignment.Start) .align(Alignment.Start)
.noRippleClickable { .noRippleClickable {
// 保存当前状态
model.showManualCreation = showManualCreation
model.showManualCreationForm = showManualCreationForm
model.isCreatingAgent = isCreatingAgent
model.showWaveAnimation = showWaveAnimation
model.isAutoModeManualForm = false // 标记为手动模式下的手动表单
// 设置正在选择头像的标志 // 设置正在选择头像的标志
model.isSelectingAvatar = true model.isSelectingAvatar = true
navController.navigate(NavigationRoute.AgentImageCrop.route) navController.navigate(NavigationRoute.AgentImageCrop.route)
}, },
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
// 如果已有裁剪后的头像,则显示头像,否则显示编辑图标
if (model.croppedBitmap != null) {
Image(
bitmap = model.croppedBitmap!!.asImageBitmap(),
contentDescription = "Avatar",
modifier = Modifier
.size(72.dp)
.clip(CircleShape),
contentScale = ContentScale.Crop
)
} else {
Icon( Icon(
painter = painterResource(id = R.mipmap.icons_infor_edit), painter = painterResource(id = R.mipmap.icons_infor_edit),
contentDescription = "Edit", contentDescription = "Edit",
@@ -526,6 +678,7 @@ fun AddAgentScreen() {
) )
} }
} }
}
Spacer(modifier = Modifier.height(18.dp)) Spacer(modifier = Modifier.height(18.dp))
// 原版两个输入框 // 原版两个输入框
Column( Column(
@@ -535,12 +688,13 @@ fun AddAgentScreen() {
Text( Text(
text = stringResource(R.string.agent_name), text = stringResource(R.string.agent_name),
fontSize = 12.sp, fontSize = 12.sp,
color = appColors.text,
fontWeight = FontWeight.W600 fontWeight = FontWeight.W600
) )
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
FormTextInput( FormTextInput(
value = model.name, value = model.name,
hint = "给它取个名字,让它成为独一无二的你", hint = stringResource(R.string.agent_name_hint_1),
background = appColors.inputBackground2, background = appColors.inputBackground2,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) { value -> ) { value ->
@@ -549,6 +703,7 @@ fun AddAgentScreen() {
Text( Text(
text = stringResource(R.string.agent_desc), text = stringResource(R.string.agent_desc),
fontSize = 12.sp, fontSize = 12.sp,
color = appColors.text,
fontWeight = FontWeight.W600 fontWeight = FontWeight.W600
) )
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
@@ -561,6 +716,7 @@ fun AddAgentScreen() {
onDescChange(value) onDescChange(value)
} }
} }
//手动创造AI界面
} }
// 错误信息显示 // 错误信息显示
@@ -577,7 +733,6 @@ fun AddAgentScreen() {
) )
} }
} }
ActionButton( ActionButton(
modifier = Modifier modifier = Modifier
.width(345.dp) .width(345.dp)
@@ -613,9 +768,6 @@ fun AddAgentScreen() {
// 清除之前的错误信息 // 清除之前的错误信息
errorMessage = null errorMessage = null
// 显示波动动画
showWaveAnimation = true
// 调用创建智能体API // 调用创建智能体API
model.viewModelScope.launch { model.viewModelScope.launch {
try { try {
@@ -624,14 +776,15 @@ fun AddAgentScreen() {
// 创建成功,清空数据并关闭页面 // 创建成功,清空数据并关闭页面
model.clearData() model.clearData()
navController.popBackStack() navController.popBackStack()
AppState.agentCreatedSuccess = true
} }
} catch (e: Exception) { } catch (e: Exception) {
// 隐藏波动动画
showWaveAnimation = false
// 显示错误信息 // 显示错误信息
errorMessage = "创建智能体失败: ${e.message}" errorMessage = "创建智能体失败: ${e.message}"
e.printStackTrace() e.printStackTrace()
// 3秒后清除错误信息
kotlinx.coroutines.delay(3000)
errorMessage = null
} }
} }
} }

View File

@@ -24,7 +24,12 @@ object AddAgentViewModel : ViewModel() {
var croppedBitmap by mutableStateOf<Bitmap?>(null) var croppedBitmap by mutableStateOf<Bitmap?>(null)
var isUpdating by mutableStateOf(false) var isUpdating by mutableStateOf(false)
var isSelectingAvatar by mutableStateOf(false) // 标记是否正在选择头像 var isSelectingAvatar by mutableStateOf(false) // 标记是否正在选择头像
var showManualCreationForm by mutableStateOf(false)
var isCreatingAgent by mutableStateOf(false)
var showWaveAnimation by mutableStateOf(false)
var showManualCreation by mutableStateOf(false)
// 添加一个标志来区分两种手动表单状态
var isAutoModeManualForm by mutableStateOf(false)
suspend fun updateAgentAvatar(context: Context) { suspend fun updateAgentAvatar(context: Context) {
croppedBitmap?.let { croppedBitmap?.let {
val file = File(context.cacheDir, "agent_avatar.jpg") val file = File(context.cacheDir, "agent_avatar.jpg")
@@ -66,11 +71,11 @@ object AddAgentViewModel : ViewModel() {
fun validate(): String? { fun validate(): String? {
return when { return when {
// name.isEmpty() -> "智能体名称不能为空" name.isEmpty() -> "智能体名称不能为空"
// name.length < 2 -> "智能体名称长度不能少于2个字符" name.length < 2 -> "智能体名称长度不能少于2个字符"
// name.length > 20 -> "智能体名称长度不能超过20个字符" name.length > 20 -> "智能体名称长度不能超过20个字符"
desc.isEmpty() -> "智能体描述不能为空" desc.isEmpty() -> "智能体描述不能为空"
desc.length > 100 -> "智能体描述长度不能超过100个字符" desc.length > 512 -> "智能体描述长度不能超过512个字符"
else -> null else -> null
} }
} }
@@ -84,5 +89,10 @@ object AddAgentViewModel : ViewModel() {
croppedBitmap = null croppedBitmap = null
isUpdating = false isUpdating = false
isSelectingAvatar = false isSelectingAvatar = false
showManualCreationForm = false
isCreatingAgent = false
showWaveAnimation = false
showManualCreation = false
isAutoModeManualForm = false
} }
} }

View File

@@ -47,7 +47,8 @@ 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.navigateToPost import com.aiosman.ravenow.ui.navigateToPost
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import com.aiosman.ravenow.utils.NetworkUtils
import com.aiosman.ravenow.ui.network.ReloadButton
@Composable @Composable
fun CommentNoticeScreen() { fun CommentNoticeScreen() {
val viewModel = viewModel<CommentNoticeListViewModel>( val viewModel = viewModel<CommentNoticeListViewModel>(
@@ -71,14 +72,47 @@ fun CommentNoticeScreen() {
modifier = Modifier.fillMaxSize().background(color = AppColors.background) modifier = Modifier.fillMaxSize().background(color = AppColors.background)
) { ) {
StatusBarSpacer() StatusBarSpacer()
val isNetworkAvailable = NetworkUtils.isNetworkAvailable(LocalContext.current)
if (!isNetworkAvailable) {
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxSize()
.padding(16.dp) .padding(top = 149.dp),
contentAlignment = Alignment.TopCenter
) { ) {
NoticeScreenHeader(stringResource(R.string.comment), moreIcon = false) Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
androidx.compose.foundation.Image(
painter = painterResource(id = R.mipmap.invalid_name_10),
contentDescription = "network error",
modifier = Modifier.size(181.dp)
)
Spacer(modifier = Modifier.size(24.dp))
Text(
text = stringResource(R.string.friend_chat_no_network_title),
color = AppColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.size(8.dp))
Text(
text = stringResource(R.string.friend_chat_no_network_subtitle),
color = AppColors.text,
fontSize = 14.sp,
fontWeight = FontWeight.W400
)
Spacer(modifier = Modifier.height(16.dp))
ReloadButton(
onClick = {
viewModel.initData(context, force = true)
} }
if (comments.itemCount == 0 && comments.loadState.refresh is LoadState.NotLoading) { )
}
}
} else if (comments.itemCount == 0 && comments.loadState.refresh is LoadState.NotLoading) {
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@@ -92,7 +126,7 @@ fun CommentNoticeScreen() {
androidx.compose.foundation.Image( androidx.compose.foundation.Image(
painter = painterResource( painter = painterResource(
id =if(AppState.darkMode) R.mipmap.qst_pl_qs_as_img id =if(AppState.darkMode) R.mipmap.qst_pl_qs_as_img
else R.mipmap.qst_pl_qs_img), else R.mipmap.invalid_name_11),
contentDescription = "No Comment", contentDescription = "No Comment",
modifier = Modifier.size(181.dp) modifier = Modifier.size(181.dp)
) )

View File

@@ -0,0 +1,75 @@
package com.aiosman.ravenow.ui.composables
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.ravenow.AppState
import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.composables.toolbar.CollapsingToolbarScaffoldScopeInstance.align
import kotlinx.coroutines.delay
@Composable
fun AgentCreatedSuccessIndicator() {
val appColors = LocalAppTheme.current
if (AppState.agentCreatedSuccess) {
Box(
modifier = Modifier
.fillMaxSize()
.padding(bottom = 70.dp),
contentAlignment = Alignment.BottomCenter
) {
Box(
modifier = Modifier
.width(150.dp)
.height(40.dp)
.background(appColors.text.copy(alpha = 0.5f), shape = RoundedCornerShape(15.dp)),
contentAlignment = Alignment.CenterStart
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(horizontal = 8.dp, vertical = 6.dp)
) {
Icon(
painter = painterResource(id = R.mipmap.bars_x_buttons_home_n_copy_2),
contentDescription = null,
modifier = Modifier.size(20.dp),
tint = Color.Unspecified
)
Spacer(modifier = Modifier.width(7.dp))
Text(
text = stringResource(R.string.create_success),
color = appColors.background,
fontSize = 13.sp
)
}
}
}
LaunchedEffect(Unit) {
delay(3000)
AppState.agentCreatedSuccess = false
}
}
}

View File

@@ -22,11 +22,15 @@ import androidx.compose.foundation.text.BasicTextField
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.remember
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.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
@@ -34,6 +38,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.aiosman.ravenow.LocalAppTheme import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.R import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
/** /**
* 水平布局的输入框 * 水平布局的输入框
@@ -49,6 +54,9 @@ fun FormTextInput(
onValueChange: (String) -> Unit onValueChange: (String) -> Unit
) { ) {
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val focusRequester = remember { FocusRequester() }
val keyboardController = LocalSoftwareKeyboardController.current
Column( Column(
modifier = modifier modifier = modifier
) { ) {
@@ -63,7 +71,11 @@ fun FormTextInput(
it it
} }
} }
.padding(17.dp), .padding(17.dp)
.noRippleClickable {
focusRequester.requestFocus()
keyboardController?.show()
},
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
label?.let { label?.let {
@@ -88,7 +100,7 @@ fun FormTextInput(
modifier = Modifier modifier = Modifier
.size(16.dp) .size(16.dp)
.align(Alignment.TopStart), .align(Alignment.TopStart),
tint = Color.Unspecified.copy(alpha = 0.4f) tint = AppColors.text.copy(alpha = 0.4f)
) )
Row( Row(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
@@ -114,6 +126,8 @@ fun FormTextInput(
onValueChange = { onValueChange = {
onValueChange(it) onValueChange(it)
}, },
modifier = Modifier
.focusRequester(focusRequester),
singleLine = true, singleLine = true,
textStyle = TextStyle( textStyle = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,

View File

@@ -22,6 +22,7 @@ import androidx.compose.foundation.text.BasicTextField
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.remember
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
@@ -29,6 +30,7 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
@@ -36,6 +38,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.aiosman.ravenow.LocalAppTheme import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.R import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
/** /**
* 垂直布局的输入框 * 垂直布局的输入框
@@ -52,6 +55,9 @@ fun FormTextInput2(
onValueChange: (String) -> Unit onValueChange: (String) -> Unit
) { ) {
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val localFocusRequester = focusRequester ?: remember { FocusRequester() }
val keyboardController = LocalSoftwareKeyboardController.current
Column( Column(
modifier = modifier.height(150.dp) modifier = modifier.height(150.dp)
) { ) {
@@ -66,7 +72,11 @@ fun FormTextInput2(
it it
} }
} }
.padding(17.dp), .padding(17.dp)
.noRippleClickable {
localFocusRequester.requestFocus()
keyboardController?.show()
},
) { ) {
label?.let { label?.let {
@@ -91,7 +101,7 @@ fun FormTextInput2(
modifier = Modifier modifier = Modifier
.size(16.dp) .size(16.dp)
.align(Alignment.TopStart), .align(Alignment.TopStart),
tint = Color.Unspecified.copy(alpha = 0.4f) tint = AppColors.text.copy(alpha = 0.4f)
) )
Row( Row(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
@@ -112,19 +122,13 @@ fun FormTextInput2(
} }
BasicTextField( BasicTextField(
maxLines = 5, maxLines = 6,
value = value, value = value,
onValueChange = { onValueChange = {
onValueChange(it) onValueChange(it)
}, },
modifier = Modifier modifier = Modifier
.let { .focusRequester(localFocusRequester),
if (focusRequester != null) {
it.focusRequester(focusRequester)
} else {
it
}
},
textStyle = TextStyle( textStyle = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,

View File

@@ -4,18 +4,23 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
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.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
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.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@@ -24,7 +29,9 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource 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.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems
import com.aiosman.ravenow.LocalAppTheme import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController import com.aiosman.ravenow.LocalNavController
@@ -35,6 +42,8 @@ import com.aiosman.ravenow.ui.composables.StatusBarSpacer
import com.aiosman.ravenow.ui.favourite.FavouriteListViewModel.refreshPager import com.aiosman.ravenow.ui.favourite.FavouriteListViewModel.refreshPager
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.aiosman.ravenow.ui.navigateToPost import com.aiosman.ravenow.ui.navigateToPost
import com.aiosman.ravenow.ui.network.ReloadButton
import com.aiosman.ravenow.utils.NetworkUtils
@OptIn(ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterialApi::class)
@Composable @Composable
@@ -71,6 +80,75 @@ fun FavouriteListPage() {
) { ) {
NoticeScreenHeader(stringResource(R.string.favourites_upper), moreIcon = false) NoticeScreenHeader(stringResource(R.string.favourites_upper), moreIcon = false)
} }
val isNetworkAvailable = NetworkUtils.isNetworkAvailable(LocalContext.current)
var moments = dataFlow.collectAsLazyPagingItems()
if (!isNetworkAvailable) {
Box(
modifier = Modifier
.fillMaxSize()
.padding(top=149.dp),
contentAlignment = Alignment.TopCenter
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
Image(
painter = painterResource(id = R.mipmap.invalid_name_10),
contentDescription = "network error",
modifier = Modifier.size(181.dp)
)
Spacer(modifier = Modifier.size(24.dp))
Text(
text = stringResource(R.string.friend_chat_no_network_title),
color = AppColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.size(8.dp))
Text(
text = stringResource(R.string.friend_chat_no_network_subtitle),
color = AppColors.secondaryText,
fontSize = 14.sp,
fontWeight = FontWeight.W400
)
Spacer(modifier = Modifier.height(16.dp))
ReloadButton(
onClick = {
model.refreshPager(force = true)
}
)
}
}
} else if(moments.itemCount == 0) {
Box(
modifier = Modifier
.fillMaxSize()
.padding(top=189.dp),
contentAlignment = Alignment.TopCenter
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
Image(
painter = painterResource(
id = if (com.aiosman.ravenow.AppState.darkMode) R.mipmap.syss_yh_qs_as_img
else R.mipmap.invalid_name_1),
contentDescription = "No favourites",
modifier = Modifier.size(110.dp)
)
Spacer(modifier = Modifier.size(24.dp))
Text(
text = stringResource(R.string.favourites_null),
color = AppColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600
)
}
}
}else{
LazyVerticalGrid( LazyVerticalGrid(
columns = GridCells.Fixed(3), columns = GridCells.Fixed(3),
modifier = Modifier.fillMaxSize().padding(horizontal = 16.dp) modifier = Modifier.fillMaxSize().padding(horizontal = 16.dp)
@@ -111,15 +189,11 @@ fun FavouriteListPage() {
) )
} }
} }
}
} }
} }
} }
}
}
PullRefreshIndicator( PullRefreshIndicator(
FavouriteListViewModel.isLoading, FavouriteListViewModel.isLoading,
state, state,

View File

@@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
@@ -19,6 +20,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource 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
@@ -37,6 +39,8 @@ import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.ui.comment.NoticeScreenHeader import com.aiosman.ravenow.ui.comment.NoticeScreenHeader
import com.aiosman.ravenow.ui.composables.StatusBarMaskLayout import com.aiosman.ravenow.ui.composables.StatusBarMaskLayout
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import com.aiosman.ravenow.utils.NetworkUtils
import com.aiosman.ravenow.ui.network.ReloadButton
@OptIn(ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterialApi::class)
@Composable @Composable
@@ -67,7 +71,47 @@ fun FollowerListScreen(userId: Int) {
) { ) {
NoticeScreenHeader(stringResource(R.string.followers_upper), moreIcon = false) NoticeScreenHeader(stringResource(R.string.followers_upper), moreIcon = false)
} }
if (users.itemCount == 0) { val isNetworkAvailable = NetworkUtils.isNetworkAvailable(LocalContext.current)
if (!isNetworkAvailable) {
Box(
modifier = Modifier
.fillMaxSize()
.padding(top = 149.dp),
contentAlignment = Alignment.TopCenter
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
Image(
painter = painterResource(id = R.mipmap.invalid_name_10),
contentDescription = "network error",
modifier = Modifier.size(181.dp)
)
Spacer(modifier = Modifier.size(24.dp))
androidx.compose.material.Text(
text = stringResource(R.string.friend_chat_no_network_title),
color = appColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.size(8.dp))
androidx.compose.material.Text(
text = stringResource(R.string.friend_chat_no_network_subtitle),
color = appColors.text,
fontSize = 14.sp,
fontWeight = FontWeight.W400
)
Spacer(modifier = Modifier.height(16.dp))
ReloadButton(
onClick = {
model.loadData(userId, true)
}
)
}
}
} else if (users.itemCount == 0) {
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@@ -81,7 +125,7 @@ fun FollowerListScreen(userId: Int) {
Image( Image(
painter = painterResource( painter = painterResource(
id =if(AppState.darkMode) R.mipmap.qst_fs_qs_as_img id =if(AppState.darkMode) R.mipmap.qst_fs_qs_as_img
else R.mipmap.qst_fs_qs_img), else R.mipmap.invalid_name_8),
contentDescription = null, contentDescription = null,
modifier = Modifier.size(181.dp) modifier = Modifier.size(181.dp)
) )

View File

@@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
@@ -37,7 +38,9 @@ import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.composables.FollowButton import com.aiosman.ravenow.ui.composables.FollowButton
import com.aiosman.ravenow.ui.composables.StatusBarMaskLayout import com.aiosman.ravenow.ui.composables.StatusBarMaskLayout
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.aiosman.ravenow.ui.network.ReloadButton
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import com.aiosman.ravenow.utils.NetworkUtils
/** /**
* 关注消息列表 * 关注消息列表
@@ -54,19 +57,51 @@ fun FollowerNoticeScreen() {
val model = FollowerNoticeViewModel val model = FollowerNoticeViewModel
var dataFlow = model.followerItemsFlow var dataFlow = model.followerItemsFlow
var followers = dataFlow.collectAsLazyPagingItems() var followers = dataFlow.collectAsLazyPagingItems()
Box(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp)
.background(color = AppColors.background)
) {
NoticeScreenHeader(stringResource(R.string.followers_upper), moreIcon = false)
}
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
model.reload() model.reload()
model.updateNotice() model.updateNotice()
} }
if (followers.itemCount == 0) { val isNetworkAvailable = NetworkUtils.isNetworkAvailable(LocalContext.current)
if (!isNetworkAvailable) {
Box(
modifier = Modifier
.fillMaxSize()
.padding(top=149.dp),
contentAlignment = Alignment.TopCenter
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
Image(
painter = painterResource(id = R.mipmap.invalid_name_10),
contentDescription = "network error",
modifier = Modifier.size(181.dp)
)
Spacer(modifier = Modifier.size(24.dp))
androidx.compose.material.Text(
text = stringResource(R.string.friend_chat_no_network_title),
color = AppColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.size(8.dp))
androidx.compose.material.Text(
text = stringResource(R.string.friend_chat_no_network_subtitle),
color = AppColors.text,
fontSize = 14.sp,
fontWeight = FontWeight.W400
)
Spacer(modifier = Modifier.height(16.dp))
ReloadButton(
onClick = {
model.reload(force = true)
}
)
}
}
} else if (followers.itemCount == 0) {
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@@ -80,7 +115,7 @@ fun FollowerNoticeScreen() {
Image( Image(
painter = painterResource( painter = painterResource(
id =if(AppState.darkMode) R.mipmap.qst_fs_qs_as_img id =if(AppState.darkMode) R.mipmap.qst_fs_qs_as_img
else R.mipmap.qst_fs_qs_img), else R.mipmap.invalid_name_8),
contentDescription = "No Followers", contentDescription = "No Followers",
modifier = Modifier.size(181.dp) modifier = Modifier.size(181.dp)
) )

View File

@@ -20,6 +20,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource 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
@@ -37,7 +38,9 @@ import com.aiosman.ravenow.exp.viewModelFactory
import com.aiosman.ravenow.ui.NavigationRoute import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.ui.comment.NoticeScreenHeader import com.aiosman.ravenow.ui.comment.NoticeScreenHeader
import com.aiosman.ravenow.ui.composables.StatusBarMaskLayout import com.aiosman.ravenow.ui.composables.StatusBarMaskLayout
import com.aiosman.ravenow.ui.network.ReloadButton
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import com.aiosman.ravenow.utils.NetworkUtils
@OptIn(ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterialApi::class)
@Composable @Composable
@@ -69,7 +72,48 @@ fun FollowingListScreen(userId: Int) {
NoticeScreenHeader(stringResource(R.string.following_upper), moreIcon = false) NoticeScreenHeader(stringResource(R.string.following_upper), moreIcon = false)
} }
if(users.itemCount == 0) {
val isNetworkAvailable = NetworkUtils.isNetworkAvailable(LocalContext.current)
if (!isNetworkAvailable) {
Box(
modifier = Modifier
.fillMaxSize()
.padding(top=149.dp),
contentAlignment = Alignment.TopCenter
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
Image(
painter = painterResource(id = R.mipmap.invalid_name_10),
contentDescription = "network error",
modifier = Modifier.size(181.dp)
)
Spacer(modifier = Modifier.size(24.dp))
androidx.compose.material.Text(
text = stringResource(R.string.friend_chat_no_network_title),
color = appColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.size(8.dp))
androidx.compose.material.Text(
text = stringResource(R.string.friend_chat_no_network_subtitle),
color = appColors.secondaryText,
fontSize = 14.sp,
fontWeight = FontWeight.W400
)
Spacer(modifier = Modifier.height(16.dp))
ReloadButton(
onClick = {
model.loadData(userId, true)
}
)
}
}
} else if(users.itemCount == 0) {
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@@ -83,7 +127,7 @@ fun FollowingListScreen(userId: Int) {
Image( Image(
painter = painterResource( painter = painterResource(
id =if(AppState.darkMode) R.mipmap.qst_gz_qs_as_img_my id =if(AppState.darkMode) R.mipmap.qst_gz_qs_as_img_my
else R.mipmap.qst_gz_qs_img_my), else R.mipmap.invalid_name_9),
contentDescription = null, contentDescription = null,
modifier = Modifier.size(181.dp) modifier = Modifier.size(181.dp)
) )

View File

@@ -43,7 +43,7 @@ fun CreateBottomSheet(
onMomentClick: () -> Unit onMomentClick: () -> Unit
) { ) {
val appColors = LocalAppTheme.current val appColors = LocalAppTheme.current
//水平效果呈现镜像排列
ModalBottomSheet( ModalBottomSheet(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
sheetState = sheetState, sheetState = sheetState,
@@ -58,42 +58,59 @@ fun CreateBottomSheet(
.padding(top = 24.dp, bottom = 24.dp), .padding(top = 24.dp, bottom = 24.dp),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
// 标题 Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(R.mipmap.h_cj_rw_icon),
contentDescription = null,
modifier = Modifier
.padding(start = 16.dp),
colorFilter = androidx.compose.ui.graphics.ColorFilter.tint(appColors.text)
)
Spacer(modifier = Modifier.weight(1f))
Text( Text(
text = stringResource(R.string.create_title), text = stringResource(R.string.create_title),
fontSize = 18.sp, fontSize = 18.sp,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
color = appColors.text, color = appColors.text,
modifier = Modifier.padding(bottom = 32.dp) modifier = Modifier
.padding(end = 3.dp)
) )
Image(
painter = painterResource(R.mipmap.h_cj_x_img),
contentDescription = null,
modifier = Modifier
.padding(end = 18.dp),
colorFilter = androidx.compose.ui.graphics.ColorFilter.tint(appColors.text)
)
}
Spacer(modifier = Modifier.height(30.dp))
// 三个创建选项 // 三个创建选项
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly horizontalArrangement = Arrangement.SpaceEvenly
) { ) {
// 群聊选项
CreateOption(
icon = R.drawable.ic_create_group_chat,
label = stringResource(R.string.create_group_chat_option),
onClick = onGroupChatClick
)
// 动态选项 // 动态选项
CreateOption( CreateOption(
icon = R.drawable.ic_create_monent, icon = R.drawable.ic_create_monent,
label = stringResource(R.string.create_moment), label = stringResource(R.string.create_moment),
onClick = onMomentClick onClick = onMomentClick
) )
// 群聊选项
CreateOption(
icon = R.mipmap.icons_circle_camera,
label = stringResource(R.string.create_group_chat_option),
onClick = onGroupChatClick
)
// AI选项 // AI选项
CreateOption( CreateOption(
icon = R.drawable.ic_create_ai, icon = R.mipmap.icons_circle_ai,
label = stringResource(R.string.create_ai), label = stringResource(R.string.create_ai),
onClick = onAiClick onClick = onAiClick
) )
} }
Spacer(modifier = Modifier.height(40.dp)) Spacer(modifier = Modifier.height(40.dp))

View File

@@ -425,6 +425,13 @@ fun AgentCardSquare(agentItem: AgentItem, viewModel: AgentViewModel, navControll
.clip(RoundedCornerShape(avatarSize / 2)), .clip(RoundedCornerShape(avatarSize / 2)),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Image(
painter = painterResource(R.mipmap.group_copy),
contentDescription = "默认头像",
modifier = Modifier.size(avatarSize),
contentScale = androidx.compose.ui.layout.ContentScale.Crop
)
if (agentItem.avatar.isNotEmpty()) { if (agentItem.avatar.isNotEmpty()) {
CustomAsyncImage( CustomAsyncImage(
imageUrl = agentItem.avatar, imageUrl = agentItem.avatar,
@@ -434,13 +441,6 @@ fun AgentCardSquare(agentItem: AgentItem, viewModel: AgentViewModel, navControll
.clip(RoundedCornerShape(avatarSize / 2)), .clip(RoundedCornerShape(avatarSize / 2)),
contentScale = androidx.compose.ui.layout.ContentScale.Crop contentScale = androidx.compose.ui.layout.ContentScale.Crop
) )
} else {
Image(
painter = painterResource(R.mipmap.rider_pro_agent),
contentDescription = "默认头像",
modifier = Modifier.size(avatarSize / 2),
colorFilter = ColorFilter.tint(AppColors.secondaryText)
)
} }
} }
@@ -531,7 +531,7 @@ fun AgentViewPagerSection(agentItems: List<AgentItem>,viewModel: AgentViewModel)
// Agent内容 // Agent内容
Box( Box(
modifier = Modifier modifier = Modifier
.height(300.dp) .height(310.dp)
) { ) {
HorizontalPager( HorizontalPager(
state = pagerState, state = pagerState,
@@ -553,7 +553,7 @@ fun AgentViewPagerSection(agentItems: List<AgentItem>,viewModel: AgentViewModel)
agentItems = agentItems.drop(page * itemsPerPage).take(itemsPerPage), agentItems = agentItems.drop(page * itemsPerPage).take(itemsPerPage),
page = page, page = page,
modifier = Modifier modifier = Modifier
.height(300.dp) .height(310.dp)
.graphicsLayer { .graphicsLayer {
scaleX = scale scaleX = scale
scaleY = scale scaleY = scale
@@ -624,7 +624,7 @@ fun AgentCard2(viewModel: AgentViewModel,agentItem: AgentItem,navController: Nav
Box( Box(
modifier = Modifier modifier = Modifier
.size(48.dp) .size(48.dp)
.background(Color(0xFFF5F5F5), RoundedCornerShape(24.dp)) .background(Color(0x00F5F5F5), RoundedCornerShape(24.dp))
.clickable { .clickable {
if (DebounceUtils.simpleDebounceClick(lastClickTime, 500L) { if (DebounceUtils.simpleDebounceClick(lastClickTime, 500L) {
viewModel.goToProfile(agentItem.openId, navController) viewModel.goToProfile(agentItem.openId, navController)
@@ -634,6 +634,12 @@ fun AgentCard2(viewModel: AgentViewModel,agentItem: AgentItem,navController: Nav
}, },
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Image(
painter = painterResource(R.mipmap.group_copy),
contentDescription = "默认头像",
modifier = Modifier.size(48.dp),
)
if (agentItem.avatar.isNotEmpty()) { if (agentItem.avatar.isNotEmpty()) {
CustomAsyncImage( CustomAsyncImage(
imageUrl = agentItem.avatar, imageUrl = agentItem.avatar,
@@ -643,13 +649,6 @@ fun AgentCard2(viewModel: AgentViewModel,agentItem: AgentItem,navController: Nav
.clip(RoundedCornerShape(24.dp)), .clip(RoundedCornerShape(24.dp)),
contentScale = androidx.compose.ui.layout.ContentScale.Crop contentScale = androidx.compose.ui.layout.ContentScale.Crop
) )
} else {
Image(
painter = painterResource(R.mipmap.rider_pro_agent),
contentDescription = "默认头像",
modifier = Modifier.size(24.dp),
colorFilter = ColorFilter.tint(AppColors.secondaryText)
)
} }
} }

View File

@@ -78,7 +78,7 @@ import com.aiosman.ravenow.ui.like.LikeNoticeViewModel
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import com.aiosman.ravenow.ui.index.tabs.message.tab.AllChatListScreen
/** /**
* 消息列表界面 * 消息列表界面
@@ -95,7 +95,7 @@ fun NotificationsScreen() {
val navController = LocalNavController.current val navController = LocalNavController.current
val systemUiController = rememberSystemUiController() val systemUiController = rememberSystemUiController()
val context = LocalContext.current val context = LocalContext.current
var pagerState = rememberPagerState (pageCount = { 3 }) var pagerState = rememberPagerState (pageCount = { 4 })
var scope = rememberCoroutineScope() var scope = rememberCoroutineScope()
val state = rememberPullRefreshState(MessageListViewModel.isLoading, onRefresh = { val state = rememberPullRefreshState(MessageListViewModel.isLoading, onRefresh = {
MessageListViewModel.viewModelScope.launch { MessageListViewModel.viewModelScope.launch {
@@ -177,7 +177,7 @@ fun NotificationsScreen() {
modifier = Modifier modifier = Modifier
.size(24.dp) .size(24.dp)
.noRippleClickable { .noRippleClickable {
// TODO: 实现通知功能 navController.navigate(NavigationRoute.NotificationScreen.route)
}, },
colorFilter = ColorFilter.tint(AppColors.text) colorFilter = ColorFilter.tint(AppColors.text)
) )
@@ -324,7 +324,7 @@ fun NotificationsScreen() {
Box { Box {
TabItem( TabItem(
text = stringResource(R.string.chat_ai), text = stringResource(R.string.chat_all),
isSelected = pagerState.currentPage == 0, isSelected = pagerState.currentPage == 0,
onClick = { onClick = {
tabDebouncer { tabDebouncer {
@@ -335,6 +335,38 @@ fun NotificationsScreen() {
} }
) )
// 全部未读消息红点
val totalUnreadCount = AgentChatListViewModel.totalUnreadCount +
GroupChatListViewModel.totalUnreadCount +
FriendChatListViewModel.totalUnreadCount
if (totalUnreadCount > 0) {
Box(
modifier = Modifier
.size(8.dp)
.background(
color = Color(0xFFFF3B30),
shape = CircleShape
)
.align(Alignment.TopEnd)
.offset(x = 8.dp, y = (-4).dp)
)
}
}
TabSpacer()
Box {
TabItem(
text = stringResource(R.string.chat_ai),
isSelected = pagerState.currentPage == 1,
onClick = {
tabDebouncer {
scope.launch {
pagerState.animateScrollToPage(1)
}
}
}
)
// 智能体未读消息红点 // 智能体未读消息红点
if (AgentChatListViewModel.totalUnreadCount > 0) { if (AgentChatListViewModel.totalUnreadCount > 0) {
Box( Box(
@@ -353,11 +385,11 @@ fun NotificationsScreen() {
Box { Box {
TabItem( TabItem(
text = stringResource(R.string.chat_group), text = stringResource(R.string.chat_group),
isSelected = pagerState.currentPage == 1, isSelected = pagerState.currentPage == 2,
onClick = { onClick = {
tabDebouncer { tabDebouncer {
scope.launch { scope.launch {
pagerState.animateScrollToPage(1) pagerState.animateScrollToPage(2)
} }
} }
} }
@@ -378,14 +410,15 @@ fun NotificationsScreen() {
} }
} }
TabSpacer() TabSpacer()
Box { Box {
TabItem( TabItem(
text = stringResource(R.string.chat_friend), text = stringResource(R.string.chat_friend),
isSelected = pagerState.currentPage == 2, isSelected = pagerState.currentPage == 3,
onClick = { onClick = {
tabDebouncer { tabDebouncer {
scope.launch { scope.launch {
pagerState.animateScrollToPage(2) pagerState.animateScrollToPage(3)
} }
} }
} }
@@ -414,14 +447,17 @@ fun NotificationsScreen() {
) { ) {
when (it) { when (it) {
0 -> { 0 -> {
AllChatListScreen()
}
1 -> {
AgentChatListScreen() AgentChatListScreen()
} }
1 -> { 2 -> {
GroupChatListScreen() GroupChatListScreen()
} }
2 -> { 3 -> {
FriendChatListScreen() FriendChatListScreen()
} }
} }

View File

@@ -91,11 +91,14 @@ fun AgentChatListScreen() {
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
val isNetworkAvailable = NetworkUtils.isNetworkAvailable(context)
if (isNetworkAvailable) {
Spacer(modifier = Modifier.height(39.dp)) Spacer(modifier = Modifier.height(39.dp))
Image( Image(
painter = painterResource( painter = painterResource(
id = if(AppState.darkMode) R.mipmap.qs_znt_qs_as_img id = if(AppState.darkMode) R.mipmap.qs_znt_qs_as_img
else R.mipmap.qs_znt_qs_img), else R.mipmap.invalid_name_5),
contentDescription = "null data", contentDescription = "null data",
modifier = Modifier modifier = Modifier
.size(181.dp) .size(181.dp)
@@ -114,6 +117,35 @@ fun AgentChatListScreen() {
fontSize = 14.sp fontSize = 14.sp
) )
} }
else {
Spacer(modifier = Modifier.height(39.dp))
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),
color = AppColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = stringResource(R.string.friend_chat_no_network_subtitle),
color = AppColors.secondaryText,
fontSize = 14.sp
)
Spacer(modifier = Modifier.height(16.dp))
ReloadButton(
onClick = {
AgentChatListViewModel.refreshPager(context = context)
}
)
}
}
} else { } else {
LazyColumn( LazyColumn(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()

View File

@@ -0,0 +1,390 @@
package com.aiosman.ravenow.ui.index.tabs.message.tab
import android.widget.Toast
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
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.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.ravenow.AppState
import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.composables.rememberDebouncer
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.aiosman.ravenow.utils.NetworkUtils
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.ui.text.font.FontFamily
data class CombinedConversation(
val type: String, // "agent", "group", or "friend"
val agentConversation: AgentConversation? = null,
val groupConversation: GroupConversation? = null,
val friendConversation: FriendConversation? = null
) {
val id: String
get() = when (type) {
"agent" -> "agent_${agentConversation?.id ?: 0}"
"group" -> "group_${groupConversation?.id ?: 0}"
"friend" -> "friend_${friendConversation?.id ?: 0}"
else -> ""
}
val avatar: String
get() = when (type) {
"agent" -> agentConversation?.avatar ?: ""
"group" -> groupConversation?.avatar ?: ""
"friend" -> friendConversation?.avatar ?: ""
else -> ""
}
val name: String
get() = when (type) {
"agent" -> agentConversation?.nickname ?: ""
"group" -> groupConversation?.groupName ?: ""
"friend" -> friendConversation?.nickname ?: ""
else -> ""
}
val lastMessageTime: String
get() = when (type) {
"agent" -> agentConversation?.lastMessageTime ?: ""
"group" -> groupConversation?.lastMessageTime ?: ""
"friend" -> friendConversation?.lastMessageTime ?: ""
else -> ""
}
val displayText: String
get() = when (type) {
"agent" -> agentConversation?.displayText ?: ""
"group" -> groupConversation?.displayText ?: ""
"friend" -> friendConversation?.displayText ?: ""
else -> ""
}
val unreadCount: Int
get() = when (type) {
"agent" -> agentConversation?.unreadCount ?: 0
"group" -> groupConversation?.unreadCount ?: 0
"friend" -> friendConversation?.unreadCount ?: 0
else -> 0
}
val isSelf: Boolean
get() = when (type) {
"agent" -> agentConversation?.isSelf ?: false
"group" -> groupConversation?.isSelf ?: false
"friend" -> friendConversation?.isSelf ?: false
else -> false
}
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun AllChatListScreen() {
val context = LocalContext.current
val navController = LocalNavController.current
val AppColors = LocalAppTheme.current
var allConversations by remember { mutableStateOf<List<CombinedConversation>>(emptyList()) }
var refreshing by remember { mutableStateOf(false) }
var isLoading by remember { mutableStateOf(false) }
var error by remember { mutableStateOf<String?>(null) }
val state = rememberPullRefreshState(
refreshing = refreshing,
onRefresh = {
refreshing = true
refreshAllData(context,
onSuccess = { conversations ->
allConversations = conversations
refreshing = false
},
onError = { errorMsg ->
error = errorMsg
refreshing = false
}
)
}
)
LaunchedEffect(Unit) {
isLoading = true
refreshAllData(context,
onSuccess = { conversations ->
allConversations = conversations
isLoading = false
},
onError = { errorMsg ->
error = errorMsg
isLoading = false
}
)
}
Column(
modifier = Modifier
.fillMaxSize()
.background(AppColors.background)
) {
Box(
modifier = Modifier
.fillMaxSize()
.pullRefresh(state)
) {
if (allConversations.isEmpty() && !isLoading) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
val isNetworkAvailable = NetworkUtils.isNetworkAvailable(context)
if (isNetworkAvailable) {
Spacer(modifier = Modifier.height(39.dp))
Image(
painter = painterResource(
id = if(AppState.darkMode) R.mipmap.qs_py_qs_as_img
else R.mipmap.invalid_name_2),
contentDescription = "null data",
modifier = Modifier
.size(181.dp)
)
Spacer(modifier = Modifier.height(24.dp))
Text(
text = stringResource(R.string.friend_chat_empty_title),
color = AppColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = stringResource(R.string.friend_chat_empty_subtitle),
color = AppColors.secondaryText,
fontSize = 14.sp
)
} else {
Spacer(modifier = Modifier.height(39.dp))
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),
color = AppColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = stringResource(R.string.friend_chat_no_network_subtitle),
color = AppColors.secondaryText,
fontSize = 14.sp
)
Spacer(modifier = Modifier.height(16.dp))
ReloadButton(
onClick = {
isLoading = true
refreshAllData(context,
onSuccess = { conversations ->
allConversations = conversations
isLoading = false
},
onError = { errorMsg ->
error = errorMsg
isLoading = false
}
)
}
)
}
}
} else {
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
itemsIndexed(
items = allConversations,
key = { _, item -> item.id }
) { index, item ->
when (item.type) {
"agent" -> {
item.agentConversation?.let { agent ->
AgentChatItem(
conversation = agent,
onUserAvatarClick = { conv ->
AgentChatListViewModel.goToUserDetail(conv, navController)
},
onChatClick = { conv ->
if (NetworkUtils.isNetworkAvailable(context)) {
AgentChatListViewModel.createSingleChat(conv.trtcUserId)
AgentChatListViewModel.goToChatAi(conv.trtcUserId, navController)
} else {
Toast.makeText(context, "网络连接异常,请检查网络设置", Toast.LENGTH_SHORT).show()
}
}
)
}
}
"group" -> {
item.groupConversation?.let { group ->
GroupChatItem(
conversation = group,
onGroupAvatarClick = { conv ->
GroupChatListViewModel.goToGroupDetail(conv, navController)
},
onChatClick = { conv ->
if (NetworkUtils.isNetworkAvailable(context)) {
GroupChatListViewModel.goToChat(conv, navController)
} else {
Toast.makeText(context, "网络连接异常,请检查网络设置", Toast.LENGTH_SHORT).show()
}
}
)
}
}
"friend" -> {
item.friendConversation?.let { friend ->
FriendChatItem(
conversation = friend,
onUserAvatarClick = { conv ->
FriendChatListViewModel.goToUserDetail(conv, navController)
},
onChatClick = { conv ->
if (NetworkUtils.isNetworkAvailable(context)) {
FriendChatListViewModel.goToChat(conv, navController)
} else {
Toast.makeText(context, "网络连接异常,请检查网络设置", Toast.LENGTH_SHORT).show()
}
}
)
}
}
}
// 分隔线
// if (index < allConversations.size - 1) {
// HorizontalDivider(
// modifier = Modifier.padding(horizontal = 24.dp),
// color = AppColors.divider
// )
// }
}
if (isLoading && allConversations.isNotEmpty()) {
item {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator(
modifier = Modifier.size(24.dp),
color = AppColors.main
)
}
}
}
}
}
PullRefreshIndicator(
refreshing = refreshing,
state = state,
modifier = Modifier.align(Alignment.TopCenter)
)
}
error?.let { errorMsg ->
Box(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
contentAlignment = Alignment.Center
) {
Text(
text = errorMsg,
color = AppColors.error,
fontSize = 14.sp
)
}
}
}
}
fun refreshAllData(
context: android.content.Context,
onSuccess: (List<CombinedConversation>) -> Unit,
onError: (String) -> Unit
) {
try {
// 同时刷新所有类型的数据
AgentChatListViewModel.refreshPager(context = context)
GroupChatListViewModel.refreshPager(context = context)
FriendChatListViewModel.refreshPager(context = context)
val combinedList = mutableListOf<CombinedConversation>()
AgentChatListViewModel.agentChatList.forEach { agent ->
combinedList.add(CombinedConversation(type = "agent", agentConversation = agent))
}
GroupChatListViewModel.groupChatList.forEach { group ->
combinedList.add(CombinedConversation(type = "group", groupConversation = group))
}
FriendChatListViewModel.friendChatList.forEach { friend ->
val isDuplicate = combinedList.any {//判断重复
it.type == "agent" && it.agentConversation?.trtcUserId == friend.trtcUserId
}
if (!isDuplicate) {
combinedList.add(CombinedConversation(type = "friend", friendConversation = friend))
}
}
// 按最后消息时间排序
val sortedList = combinedList.sortedByDescending {
it.lastMessageTime
}
onSuccess(sortedList)
} catch (e: Exception) {
onError("刷新数据失败: ${e.message}")
}
}

View File

@@ -33,8 +33,14 @@ 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.composables.rememberDebouncer import com.aiosman.ravenow.ui.composables.rememberDebouncer
import com.aiosman.ravenow.ui.index.tabs.search.ReloadButton
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.aiosman.ravenow.utils.NetworkUtils import com.aiosman.ravenow.utils.NetworkUtils
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.graphics.Brush
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.foundation.layout.PaddingValues
@OptIn(ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterialApi::class)
@Composable @Composable
@@ -73,12 +79,14 @@ fun FriendChatListScreen() {
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
//verticalArrangement = Arrangement.Center //verticalArrangement = Arrangement.Center
) { ) {
val isNetworkAvailable = NetworkUtils.isNetworkAvailable(context)
if (isNetworkAvailable) {
Spacer(modifier = Modifier.height(39.dp)) Spacer(modifier = Modifier.height(39.dp))
Image( Image(
painter = painterResource( painter = painterResource(
id = if(AppState.darkMode) R.mipmap.qs_py_qs_as_img id = if(AppState.darkMode) R.mipmap.qs_py_qs_as_img
else R.mipmap.qs_py_qs_img), else R.mipmap.invalid_name_2),
contentDescription = "null data", contentDescription = "null data",
modifier = Modifier modifier = Modifier
.size(181.dp) .size(181.dp)
@@ -96,6 +104,34 @@ fun FriendChatListScreen() {
color = AppColors.secondaryText, color = AppColors.secondaryText,
fontSize = 14.sp fontSize = 14.sp
) )
}else {
Spacer(modifier = Modifier.height(39.dp))
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),
color = AppColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = stringResource(R.string.friend_chat_no_network_subtitle),
color = AppColors.secondaryText,
fontSize = 14.sp
)
Spacer(modifier = Modifier.height(16.dp))
ReloadButton(
onClick = {
FriendChatListViewModel.refreshPager(pullRefresh = true, context = context)
}
)
}
} }
} else { } else {
LazyColumn( LazyColumn(
@@ -266,4 +302,43 @@ 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
)
}
}
}

View File

@@ -71,11 +71,14 @@ fun GroupChatListScreen() {
.padding(16.dp), .padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
val isNetworkAvailable = NetworkUtils.isNetworkAvailable(context)
if (isNetworkAvailable) {
Spacer(modifier = Modifier.height(39.dp)) Spacer(modifier = Modifier.height(39.dp))
Image( Image(
painter = painterResource( painter = painterResource(
id = if(AppState.darkMode) R.mipmap.qs_ql_qs_as_img id = if(AppState.darkMode) R.mipmap.qs_ql_qs_as_img
else R.mipmap.qs_ql_qs_img), else R.mipmap.invalid_name_12),
contentDescription = "null data", contentDescription = "null data",
modifier = Modifier modifier = Modifier
.size(181.dp) .size(181.dp)
@@ -93,6 +96,34 @@ fun GroupChatListScreen() {
color = AppColors.secondaryText, color = AppColors.secondaryText,
fontSize = 14.sp fontSize = 14.sp
) )
}else {
Spacer(modifier = Modifier.height(39.dp))
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),
color = AppColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = stringResource(R.string.friend_chat_no_network_subtitle),
color = AppColors.secondaryText,
fontSize = 14.sp
)
Spacer(modifier = Modifier.height(16.dp))
ReloadButton(
onClick = {
GroupChatListViewModel.refreshPager(context = context)
}
)
}
} }
} else { } else {
LazyColumn( LazyColumn(

View File

@@ -43,6 +43,8 @@ import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.composables.MomentCard import com.aiosman.ravenow.ui.composables.MomentCard
import com.aiosman.ravenow.ui.composables.rememberDebouncer import com.aiosman.ravenow.ui.composables.rememberDebouncer
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import com.aiosman.ravenow.utils.NetworkUtils
import androidx.compose.ui.platform.LocalContext
/** /**
* 动态列表 * 动态列表
@@ -76,7 +78,49 @@ fun TimelineMomentsList() {
model.loadMore() model.loadMore()
} }
} }
if (moments.isEmpty()) { val isNetworkAvailable = NetworkUtils.isNetworkAvailable(LocalContext.current)
if (!isNetworkAvailable) {
Box(
modifier = Modifier
.fillMaxSize()
.padding(top = 188.dp),
contentAlignment = Alignment.TopCenter
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
val exploreDebouncer = rememberDebouncer()
Image(
painter = painterResource(id = R.mipmap.invalid_name_10),
contentDescription = "network error",
modifier = Modifier.size(140.dp)
)
Spacer(modifier = Modifier.size(24.dp))
Text(
text = stringResource(R.string.friend_chat_no_network_title),
color = AppColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.size(8.dp))
Text(
text = stringResource(R.string.friend_chat_no_network_subtitle),
color = AppColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W400
)
Spacer(modifier = Modifier.size(16.dp))
ExploreButton(
onClick = {
exploreDebouncer {
/* TODO: 添加点击事件处理 */
} }
)
}
}
} else if (moments.isEmpty()) {
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@@ -91,7 +135,7 @@ fun TimelineMomentsList() {
Image( Image(
painter = painterResource( painter = painterResource(
id = if(AppState.darkMode) R.mipmap.qst_gz_qs_as_img id = if(AppState.darkMode) R.mipmap.qst_gz_qs_as_img
else R.mipmap.qst_gz_qs_img), else R.mipmap.invalid_name_4),
contentDescription = null, contentDescription = null,
modifier = Modifier.size(140.dp) modifier = Modifier.size(140.dp)
) )
@@ -191,9 +235,9 @@ fun ExploreButton(
) { ) {
val gradientBrush = Brush.linearGradient( val gradientBrush = Brush.linearGradient(
colors = listOf( colors = listOf(
Color(0xFFee2a33), Color(0xFF7c45ed),
Color(0xFFd80264), Color(0xFF7c68ef),
Color(0xFF664c92) Color(0xFF7bd8f8)
) )
) )

View File

@@ -98,7 +98,7 @@ import com.google.accompanist.systemuicontroller.rememberSystemUiController
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File import java.io.File
import androidx.compose.foundation.rememberScrollState
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class) @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
@Composable @Composable
fun ProfileV3( fun ProfileV3(
@@ -119,7 +119,6 @@ fun ProfileV3(
postCount: Int? = null, // 新增参数用于传递帖子总数 postCount: Int? = null, // 新增参数用于传递帖子总数
) { ) {
val model = MyProfileViewModel val model = MyProfileViewModel
val state = rememberCollapsingToolbarScaffoldState()
val pagerState = rememberPagerState(pageCount = { if (isAiAccount) 1 else 2 }) val pagerState = rememberPagerState(pageCount = { if (isAiAccount) 1 else 2 })
val enabled by remember { mutableStateOf(true) } val enabled by remember { mutableStateOf(true) }
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues() val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
@@ -151,6 +150,15 @@ fun ProfileV3(
val systemUiController = rememberSystemUiController() val systemUiController = rememberSystemUiController()
val listState = rememberLazyListState() val listState = rememberLazyListState()
val gridState = rememberLazyGridState() val gridState = rememberLazyGridState()
val scrollState = rememberScrollState()
val toolbarAlpha by remember {
derivedStateOf {
val maxScroll = 500f // 最大滚动距离,可调整
val progress = (scrollState.value.coerceAtMost(maxScroll.toInt()) / maxScroll).coerceIn(0f, 1f)
progress
}
}
// observe list scrolling // observe list scrolling
val reachedListBottom by remember { val reachedListBottom by remember {
@@ -201,8 +209,6 @@ fun ProfileV3(
} }
} }
fun switchTheme() { fun switchTheme() {
// delay // delay
scope.launch { scope.launch {
@@ -281,43 +287,15 @@ fun ProfileV3(
Box( Box(
modifier = Modifier.pullRefresh(refreshState) modifier = Modifier.pullRefresh(refreshState)
) { ) {
CollapsingToolbarScaffold( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.background(AppColors.profileBackground), .verticalScroll(scrollState)
state = state,
scrollStrategy = ScrollStrategy.ExitUntilCollapsed,
toolbarScrollable = true,
enabled = enabled,
toolbar = { toolbarScrollState ->
Column(
modifier = Modifier
.fillMaxWidth()
.height(miniToolbarHeight.dp)
// 保持在最低高度和当前高度之间
.background(AppColors.profileBackground) .background(AppColors.profileBackground)
) { ) {
} // Banner
// header val banner = profile?.banner
Box( if (banner != null) {
modifier = Modifier
.parallax(0.5f)
.fillMaxWidth()
.height(if (isAiAccount) 600.dp else 700.dp)
.background(AppColors.profileBackground)
.verticalScroll(toolbarScrollState)
) {
Box(
modifier = Modifier.fillMaxSize()
) {
Column(
modifier = Modifier
.fillMaxWidth()
.graphicsLayer {
alpha = state.toolbarState.progress
}
) {
// banner
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -333,9 +311,7 @@ fun ProfileV3(
it.noRippleClickable { it.noRippleClickable {
Intent(Intent.ACTION_PICK).apply { Intent(Intent.ACTION_PICK).apply {
type = "image/*" type = "image/*"
pickBannerImageLauncher.launch( pickBannerImageLauncher.launch(this)
this
)
} }
} }
} else { } else {
@@ -350,44 +326,25 @@ fun ProfileV3(
), ),
) )
) { ) {
val banner = profile?.banner
if (banner != null) {
CustomAsyncImage( CustomAsyncImage(
LocalContext.current, LocalContext.current,
banner, banner,
modifier = Modifier modifier = Modifier.fillMaxSize(),
.fillMaxSize(),
contentDescription = "",
contentScale = ContentScale.Crop
)
} else {
Image(
painter = painterResource(id = R.drawable.rave_now_profile_backgrount_demo_1),
modifier = Modifier
.fillMaxSize(),
contentDescription = "", contentDescription = "",
contentScale = ContentScale.Crop contentScale = ContentScale.Crop
) )
} }
} }
} else {
Spacer(modifier = Modifier.height(100.dp))
}
} // 用户信息
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(AppColors.profileBackground) .background(AppColors.profileBackground)
) { .padding(horizontal = 16.dp)
// user info
Column(
modifier = Modifier
.fillMaxWidth()
) {
// Spacer(modifier = Modifier.height(16.dp))
// 个人信息
Box(
modifier = Modifier.padding(horizontal = 16.dp)
) { ) {
profile?.let { profile?.let {
UserItem( UserItem(
@@ -396,17 +353,20 @@ fun ProfileV3(
) )
} }
} }
Spacer(modifier = Modifier.height(20.dp)) Spacer(modifier = Modifier.height(20.dp))
// 操作按钮
profile?.let { profile?.let {
Box( Box(
modifier = Modifier.padding(horizontal = 16.dp) modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
) { ) {
if (isSelf) { if (isSelf) {
SelfProfileAction( SelfProfileAction(
onEditProfile = { onEditProfile = {
navController.navigate( navController.navigate(NavigationRoute.AccountEdit.route)
NavigationRoute.AccountEdit.route
)
}, },
onPremiumClick = { onPremiumClick = {
navController.navigate(NavigationRoute.VipSelPage.route) navController.navigate(NavigationRoute.VipSelPage.route)
@@ -424,24 +384,20 @@ fun ProfileV3(
} }
) )
} }
} }
} }
} }
// 添加用户智能体行(智能体用户不显示) // 用户智能体行
if (!isAiAccount) { if (!isAiAccount) {
UserAgentsRow( UserAgentsRow(
userId = if (isSelf) null else profile?.id, userId = if (isSelf) null else profile?.id,
modifier = Modifier.padding(top = 16.dp), modifier = Modifier.padding(top = 16.dp),
onMoreClick = { onMoreClick = {
// 导航到智能体列表页面 // 导航到智能体列表页面
// TODO: 实现导航逻辑
}, },
onAgentClick = { agent -> onAgentClick = { agent ->
// 导航到智能体详情页面 // 导航到智能体详情页面
// TODO: 实现导航逻辑
}, },
onAvatarClick = { agent -> onAvatarClick = { agent ->
// 导航到智能体个人主页 // 导航到智能体个人主页
@@ -469,115 +425,13 @@ fun ProfileV3(
} }
) )
} }
}
} // 内容
}
}
}
Box(modifier = Modifier.fillMaxWidth()) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.graphicsLayer {
alpha = 1 - state.toolbarState.progress
}
.background(AppColors.profileBackground)
.onGloballyPositioned {
miniToolbarHeight = with(density) {
it.size.height.toDp().value.toInt()
}
}
) {
StatusBarSpacer()
Row(
modifier = Modifier.padding(
horizontal = 16.dp,
vertical = 8.dp,
).noRippleClickable {
},
verticalAlignment = Alignment.CenterVertically
) {
if (!isMain) {
Image(
painter = painterResource(id = R.drawable.rider_pro_back_icon), // Replace with your image resource
contentDescription = "Back",
modifier = Modifier
.noRippleClickable {
navController.navigateUp()
}
.size(24.dp),
colorFilter = ColorFilter.tint(AppColors.text)
)
Spacer(modifier = Modifier.width(8.dp))
CustomAsyncImage(
LocalContext.current,
profile?.avatar,
modifier = Modifier
.size(32.dp)
.clip(CircleShape),
contentDescription = "",
contentScale = ContentScale.Crop
)
Spacer(modifier = Modifier.width(16.dp))
Text(
text = profile?.nickName ?: "",
fontSize = 16.sp,
fontWeight = FontWeight.W600,
color = AppColors.text
)
}
Spacer(modifier = Modifier.weight(1f))
if (isSelf&&isMain) {
Box(
modifier = Modifier
.size(24.dp)
.padding(16.dp)
)
}
}
Spacer(modifier = Modifier.height(8.dp))
}
if (isSelf&&isMain) {
Box(
modifier = Modifier
.align(Alignment.TopEnd)
.padding(
top = 32.dp ,
end = 16.dp
)
.noRippleClickable {
IndexViewModel.openDrawer = true
}
) {
Box(
modifier = Modifier
.padding(16.dp)
) {
Icon(
painter = painterResource(id = R.drawable.rider_pro_more_horizon),
contentDescription = "",
tint = AppColors.text
)
}
}
}
}
}
) {
Column(
modifier = Modifier
.fillMaxSize()
.background(AppColors.profileBackground) .background(AppColors.profileBackground)
.padding(top = 8.dp)
) { ) {
UserContentPageIndicator( UserContentPageIndicator(
pagerState = pagerState, pagerState = pagerState,
@@ -586,6 +440,7 @@ fun ProfileV3(
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
HorizontalPager( HorizontalPager(
state = pagerState, state = pagerState,
modifier = Modifier.height(500.dp) // 固定滚动高度
) { idx -> ) { idx ->
when (idx) { when (idx) {
0 -> 0 ->
@@ -615,15 +470,116 @@ fun ProfileV3(
} }
} }
} }
} }
// 顶部导航栏
TopNavigationBar(
isMain = isMain,
isSelf = isSelf,
profile = profile,
navController = navController,
alpha = toolbarAlpha
)
PullRefreshIndicator( PullRefreshIndicator(
model.refreshing, model.refreshing,
refreshState, refreshState,
Modifier.align(Alignment.TopCenter) Modifier.align(Alignment.TopCenter)
) )
} }
}
//顶部导航栏组件
@Composable
fun TopNavigationBar(
isMain: Boolean,
isSelf: Boolean,
profile: AccountProfileEntity?,
navController: androidx.navigation.NavController,
alpha: Float
) {
val appColors = LocalAppTheme.current
Box(
modifier = Modifier
.fillMaxWidth()
.graphicsLayer { this.alpha = alpha } // 应用透明度
) {
Column(
modifier = Modifier
.fillMaxWidth()
.background(appColors.profileBackground)
) {
StatusBarSpacer()
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp)
.noRippleClickable {
},
verticalAlignment = Alignment.CenterVertically
) {
if (!isMain) {
Image(
painter = painterResource(id = R.drawable.rider_pro_back_icon),
contentDescription = "Back",
modifier = Modifier
.noRippleClickable {
navController.navigateUp()
}
.size(24.dp),
colorFilter = ColorFilter.tint(appColors.text)
)
Spacer(modifier = Modifier.width(8.dp))
CustomAsyncImage(
LocalContext.current,
profile?.avatar,
modifier = Modifier
.size(32.dp)
.clip(CircleShape),
contentDescription = "",
contentScale = ContentScale.Crop
)
Spacer(modifier = Modifier.width(16.dp))
Text(
text = profile?.nickName ?: "",
fontSize = 16.sp,
fontWeight = FontWeight.W600,
color = appColors.text
)
}
Spacer(modifier = Modifier.weight(1f))
if (isSelf && isMain) {
Box(
modifier = Modifier
.size(24.dp)
.padding(16.dp)
)
}
}
Spacer(modifier = Modifier.height(8.dp))
}
if (isSelf && isMain) {
Box(
modifier = Modifier
.align(Alignment.TopEnd)
.padding(top = 32.dp, end = 16.dp)
.noRippleClickable {
IndexViewModel.openDrawer = true
}
) {
Box(
modifier = Modifier.padding(16.dp)
) {
Icon(
painter = painterResource(id = R.drawable.rider_pro_more_horizon),
contentDescription = "",
tint = appColors.text
)
}
}
}
}
} }
/** /**

View File

@@ -37,9 +37,16 @@ import androidx.compose.foundation.lazy.grid.itemsIndexed
import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.res.stringResource
import com.aiosman.ravenow.AppState import com.aiosman.ravenow.AppState
import com.aiosman.ravenow.ui.composables.rememberDebouncer import com.aiosman.ravenow.ui.composables.rememberDebouncer
import com.aiosman.ravenow.ui.index.tabs.profile.MyProfileViewModel
import com.aiosman.ravenow.ui.network.ReloadButton
import com.aiosman.ravenow.utils.NetworkUtils
@Composable @Composable
fun GalleryItem( fun GalleryItem(
moment: MomentEntity, moment: MomentEntity,
@@ -129,8 +136,50 @@ fun GalleryGrid(
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val gridState = rememberLazyGridState() val gridState = rememberLazyGridState()
val debouncer = rememberDebouncer() val debouncer = rememberDebouncer()
var refreshKey by remember { mutableStateOf(0) }
val isNetworkAvailable = NetworkUtils.isNetworkAvailable(LocalContext.current)
if (moments.isEmpty()) { if (!isNetworkAvailable) {
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(vertical = 60.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
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 = {
refreshKey++
MyProfileViewModel.ResetModel()
MyProfileViewModel.loadProfile(pullRefresh = true)
}
)
}
} else if (moments.isEmpty()) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@@ -141,7 +190,7 @@ fun GalleryGrid(
Image( Image(
painter = painterResource( painter = painterResource(
id = if(AppState.darkMode) R.mipmap.qs_dt_qs_as_img id = if(AppState.darkMode) R.mipmap.qs_dt_qs_as_img
else R.mipmap.qs_dt_qs_img), else R.mipmap.invalid_name_7),
contentDescription = "暂无图片", contentDescription = "暂无图片",
modifier = Modifier.size(181.dp), modifier = Modifier.size(181.dp),
) )

View File

@@ -50,8 +50,8 @@ fun OtherProfileAction(
// 定义渐变色 // 定义渐变色
val followGradient = Brush.horizontalGradient( val followGradient = Brush.horizontalGradient(
colors = listOf( colors = listOf(
Color(0xFFE53E3E), // 红色 Color(0xFF7c45ed),
Color(0xFF9F7AEA) // 紫色 Color(0x777c68ef)
) )
) )
@@ -100,7 +100,7 @@ fun OtherProfileAction(
Text( Text(
text = if (profile.isFollowing) "已关注" else stringResource(R.string.follow_upper), text = if (profile.isFollowing) "已关注" else stringResource(R.string.follow_upper),
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.W600, fontWeight = FontWeight.W900,
color = if (profile.isFollowing) { color = if (profile.isFollowing) {
// 已关注状态 - 灰色文字 // 已关注状态 - 灰色文字
AppColors.text.copy(alpha = 0.6f) AppColors.text.copy(alpha = 0.6f)
@@ -133,11 +133,37 @@ fun OtherProfileAction(
Text( Text(
text = stringResource(R.string.chat_upper), text = stringResource(R.string.chat_upper),
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.W600, fontWeight = FontWeight.W900,
color = AppColors.text, // 使用主题文字颜色 color = AppColors.text, // 使用主题文字颜色
) )
} }
} }
// 分享按钮 - 灰色背景样式
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
modifier = Modifier
.weight(1f)
.clip(RoundedCornerShape(8.dp))
.background(AppColors.nonActive)
.padding(horizontal = 16.dp, vertical = 12.dp)
.noRippleClickable {
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CHAT_WITH_AGENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
// TODO: 添加分享逻辑
}
}
) {
Text(
text = stringResource(R.string.share),
fontSize = 14.sp,
fontWeight = FontWeight.W900,
color = AppColors.text, // 使用主题文字颜色
)
}
} }
} }

View File

@@ -29,11 +29,13 @@ import com.aiosman.ravenow.ui.modifiers.noRippleClickable
@Composable @Composable
fun SelfProfileAction( fun SelfProfileAction(
onEditProfile: () -> Unit, onEditProfile: () -> Unit,
onPremiumClick: (() -> Unit)? = null onPremiumClick: (() -> Unit),
onShare: (() -> Unit)? = null
) { ) {
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val editProfileDebouncer = rememberDebouncer() val editProfileDebouncer = rememberDebouncer()
val premiumClickDebouncer = rememberDebouncer() val premiumClickDebouncer = rememberDebouncer()
val shareDebouncer = rememberDebouncer()
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
@@ -46,9 +48,9 @@ fun SelfProfileAction(
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
modifier = Modifier modifier = Modifier
.weight(1f) .weight(1f)
.clip(RoundedCornerShape(8.dp)) .clip(RoundedCornerShape(10.dp))
.background(AppColors.nonActive) .background(AppColors.nonActive)
.padding(horizontal = 16.dp, vertical = 12.dp) .padding(horizontal = 5.dp, vertical = 12.dp)
.noRippleClickable { .noRippleClickable {
editProfileDebouncer { editProfileDebouncer {
onEditProfile() onEditProfile()
@@ -58,39 +60,82 @@ fun SelfProfileAction(
Text( Text(
text = stringResource(R.string.edit_profile), text = stringResource(R.string.edit_profile),
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.W600, fontWeight = FontWeight.W900,
color = AppColors.text, color = AppColors.text,
) )
} }
// Rave Premium 按钮(右侧) // 预留按钮位置
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
modifier = Modifier modifier = Modifier
.weight(1f) .weight(1f)
.clip(RoundedCornerShape(8.dp)) .clip(RoundedCornerShape(10.dp))
.background(AppColors.premiumBackground)
.padding(horizontal = 16.dp, vertical = 12.dp) .padding(horizontal = 16.dp, vertical = 12.dp)
.noRippleClickable { .noRippleClickable {
premiumClickDebouncer {
onPremiumClick?.invoke() }
) {
Text(
text = "",
fontSize = 14.sp,
fontWeight = FontWeight.W900,
color = AppColors.text,
)
}
// 分享按钮
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
modifier = Modifier
.weight(1f)
.clip(RoundedCornerShape(10.dp))
.background(AppColors.nonActive)
.padding(horizontal = 16.dp, vertical = 12.dp)
.noRippleClickable {
shareDebouncer {
// TODO: 添加分享逻辑
} }
} }
) { ) {
Image(
painter = painterResource(id = R.drawable.ic_member),
contentDescription = "",
modifier = Modifier.size(18.dp),
colorFilter = ColorFilter.tint(AppColors.premiumText)
)
Spacer(modifier = Modifier.width(8.dp))
Text( Text(
text = "Rave Premium", text = stringResource(R.string.share),
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.W600, fontWeight = FontWeight.W900,
color = AppColors.premiumText, color = AppColors.text,
) )
} }
// // Rave Premium 按钮(右侧)
// Row(
// verticalAlignment = Alignment.CenterVertically,
// horizontalArrangement = Arrangement.Center,
// modifier = Modifier
// .weight(1f)
// .clip(RoundedCornerShape(8.dp))
// .background(AppColors.premiumBackground)
// .padding(horizontal = 16.dp, vertical = 12.dp)
// .noRippleClickable {
// premiumClickDebouncer {
// onPremiumClick?.invoke()
// }
// }
// ) {
// Image(
// painter = painterResource(id = R.drawable.ic_member),
// contentDescription = "",
// modifier = Modifier.size(18.dp),
// colorFilter = ColorFilter.tint(AppColors.premiumText)
// )
// Spacer(modifier = Modifier.width(8.dp))
// Text(
// text = "Rave Premium",
// fontSize = 14.sp,
// fontWeight = FontWeight.W600,
// color = AppColors.premiumText,
// )
// }
} }
} }

View File

@@ -19,6 +19,7 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
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
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@@ -29,6 +30,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource 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
@@ -44,7 +46,10 @@ import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.NavigationRoute import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.entity.AgentEntity import com.aiosman.ravenow.entity.AgentEntity
import com.aiosman.ravenow.ui.composables.CustomAsyncImage import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.index.tabs.profile.MyProfileViewModel
import com.aiosman.ravenow.ui.network.ReloadButton
import com.aiosman.ravenow.utils.DebounceUtils import com.aiosman.ravenow.utils.DebounceUtils
import com.aiosman.ravenow.utils.NetworkUtils
@Composable @Composable
fun UserAgentsList( fun UserAgentsList(
@@ -196,6 +201,7 @@ fun UserAgentCard(
@Composable @Composable
fun EmptyAgentsView() { fun EmptyAgentsView() {
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val isNetworkAvailable = NetworkUtils.isNetworkAvailable(LocalContext.current)
Column( Column(
modifier = Modifier modifier = Modifier
@@ -203,10 +209,11 @@ fun EmptyAgentsView() {
.padding(vertical = 60.dp), .padding(vertical = 60.dp),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
if (isNetworkAvailable) {
Image( Image(
painter = painterResource( painter = painterResource(
id =if(AppState.darkMode) R.mipmap.qs_ai_qs_as_img id =if(AppState.darkMode) R.mipmap.qs_ai_qs_as_img
else R.mipmap.qs_ai_qs_img), else R.mipmap.ai),
contentDescription = "暂无Agent", contentDescription = "暂无Agent",
modifier = Modifier.size(181.dp), modifier = Modifier.size(181.dp),
) )
@@ -228,5 +235,37 @@ fun EmptyAgentsView() {
color = AppColors.secondaryText, color = AppColors.secondaryText,
fontWeight = FontWeight.W400 fontWeight = FontWeight.W400
) )
} 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 = {
MyProfileViewModel.ResetModel()
MyProfileViewModel.loadProfile(pullRefresh = true)
}
)
}
} }
} }

View File

@@ -5,6 +5,7 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
@@ -28,6 +29,8 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon import androidx.compose.material.Icon
import androidx.compose.material.Tab import androidx.compose.material.Tab
import androidx.compose.material.TabRow import androidx.compose.material.TabRow
@@ -44,6 +47,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@@ -53,6 +57,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
@@ -70,6 +75,7 @@ import com.aiosman.ravenow.ui.index.tabs.message.tab.AgentChatListViewModel
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import com.aiosman.ravenow.utils.NetworkUtils
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@@ -304,6 +310,7 @@ fun MomentResultTab() {
var dataFlow = model.momentsFlow var dataFlow = model.momentsFlow
var moments = dataFlow.collectAsLazyPagingItems() var moments = dataFlow.collectAsLazyPagingItems()
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val context = LocalContext.current
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@@ -317,10 +324,13 @@ fun MomentResultTab() {
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center verticalArrangement = Arrangement.Center
) { ) {
val isNetworkAvailable = NetworkUtils.isNetworkAvailable(context)
if (isNetworkAvailable) {
androidx.compose.foundation.Image( androidx.compose.foundation.Image(
painter = painterResource( painter = painterResource(
id = if(AppState.darkMode) R.mipmap.syss_yh_qs_as_img id = if(AppState.darkMode) R.mipmap.syss_yh_qs_as_img
else R.mipmap.syss_yh_qs_img), else R.mipmap.invalid_name_1),
contentDescription = "No Comment", contentDescription = "No Comment",
modifier = Modifier.size(140.dp) modifier = Modifier.size(140.dp)
) )
@@ -337,6 +347,33 @@ fun MomentResultTab() {
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.W400 fontWeight = FontWeight.W400
) )
} else {
androidx.compose.foundation.Image(
painter = painterResource(id = R.mipmap.invalid_name_10),
contentDescription = "network error",
modifier = Modifier.size(140.dp)
)
Text(
text = stringResource(R.string.friend_chat_no_network_title),
color = LocalAppTheme.current.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = stringResource(R.string.friend_chat_no_network_subtitle),
color = LocalAppTheme.current.secondaryText,
fontSize = 14.sp,
fontWeight = FontWeight.W400
)
Spacer(modifier = Modifier.size(16.dp))
ReloadButton(
onClick = {
SearchViewModel.ResetModel()
SearchViewModel.search()
}
)
}
} }
} else { } else {
LazyColumn( LazyColumn(
@@ -369,6 +406,7 @@ fun UserResultTab() {
val model = SearchViewModel val model = SearchViewModel
val users = model.usersFlow.collectAsLazyPagingItems() val users = model.usersFlow.collectAsLazyPagingItems()
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val context = LocalContext.current
Box( Box(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) { ) {
@@ -380,10 +418,13 @@ fun UserResultTab() {
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center verticalArrangement = Arrangement.Center
) { ) {
val isNetworkAvailable = NetworkUtils.isNetworkAvailable(context)
if (isNetworkAvailable) {
androidx.compose.foundation.Image( androidx.compose.foundation.Image(
painter = painterResource( painter = painterResource(
id = if(AppState.darkMode) R.mipmap.syss_yh_qs_as_img id = if(AppState.darkMode) R.mipmap.syss_yh_qs_as_img
else R.mipmap.syss_yh_qs_img), else R.mipmap.invalid_name_1),
contentDescription = "No Comment", contentDescription = "No Comment",
modifier = Modifier.size(140.dp) modifier = Modifier.size(140.dp)
) )
@@ -400,6 +441,33 @@ fun UserResultTab() {
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.W400 fontWeight = FontWeight.W400
) )
} else {
androidx.compose.foundation.Image(
painter = painterResource(id = R.mipmap.invalid_name_10),
contentDescription = "network error",
modifier = Modifier.size(140.dp)
)
Text(
text = stringResource(R.string.friend_chat_no_network_title),
color = LocalAppTheme.current.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = stringResource(R.string.friend_chat_no_network_subtitle),
color = LocalAppTheme.current.secondaryText,
fontSize = 14.sp,
fontWeight = FontWeight.W400
)
Spacer(modifier = Modifier.size(16.dp))
ReloadButton(
onClick = {
SearchViewModel.ResetModel()
SearchViewModel.search()
}
)
}
} }
} else { } else {
LazyColumn( LazyColumn(
@@ -497,3 +565,42 @@ fun UserItem(
} }
} }
} }
@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,
)
}
}
}

View File

@@ -39,15 +39,14 @@ import com.aiosman.ravenow.R
import com.aiosman.ravenow.entity.AccountLikeEntity import com.aiosman.ravenow.entity.AccountLikeEntity
import com.aiosman.ravenow.exp.timeAgo import com.aiosman.ravenow.exp.timeAgo
import com.aiosman.ravenow.ui.NavigationRoute import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.ui.comment.NoticeScreenHeader
import com.aiosman.ravenow.ui.composables.BottomNavigationPlaceholder import com.aiosman.ravenow.ui.composables.BottomNavigationPlaceholder
import com.aiosman.ravenow.ui.composables.CustomAsyncImage import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.composables.StatusBarMaskLayout import com.aiosman.ravenow.ui.composables.StatusBarMaskLayout
import com.aiosman.ravenow.ui.index.tabs.profile.MyProfileViewModel
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.aiosman.ravenow.ui.navigateToPost import com.aiosman.ravenow.ui.navigateToPost
import java.util.Date import java.util.Date
import com.aiosman.ravenow.utils.NetworkUtils
import com.aiosman.ravenow.ui.network.ReloadButton
@Preview @Preview
@Composable @Composable
fun LikeNoticeScreen() { fun LikeNoticeScreen() {
@@ -72,18 +71,47 @@ fun LikeNoticeScreen() {
.background(color = AppColors.background) .background(color = AppColors.background)
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
) { ) {
val isNetworkAvailable = NetworkUtils.isNetworkAvailable(LocalContext.current)
if (!isNetworkAvailable) {
Box( Box(
modifier = Modifier modifier = Modifier.fillMaxSize()
.fillMaxWidth() .padding(top=149.dp),
.padding(vertical = 16.dp) contentAlignment = Alignment.TopCenter
) { ) {
NoticeScreenHeader( Column(
stringResource(R.string.like_upper), modifier = Modifier.fillMaxWidth(),
moreIcon = false horizontalAlignment = Alignment.CenterHorizontally
) {
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),
color = AppColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W600,
)
Spacer(modifier = Modifier.size(8.dp))
Text(
text = stringResource(R.string.friend_chat_no_network_subtitle),
color = AppColors.text,
fontSize = 14.sp,
fontWeight = FontWeight.W400
)
Spacer(modifier = Modifier.height(16.dp))
ReloadButton(
onClick = {
LikeNoticeViewModel.reload(force = true)
}
) )
} }
}
if (likes.itemCount == 0) { } else if (likes.itemCount == 0) {
Box( Box(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
.padding(top=149.dp), .padding(top=149.dp),
@@ -96,7 +124,7 @@ fun LikeNoticeScreen() {
Image( Image(
painter = painterResource( painter = painterResource(
id =if(AppState.darkMode) R.mipmap.qst_z_qs_as_img id =if(AppState.darkMode) R.mipmap.qst_z_qs_as_img
else R.mipmap.qst_z_qs_img), else R.mipmap.invalid_name_6),
contentDescription = "No Notice", contentDescription = "No Notice",
modifier = Modifier.size(181.dp) modifier = Modifier.size(181.dp)
) )

View File

@@ -0,0 +1,64 @@
package com.aiosman.ravenow.ui.network
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.ravenow.R
@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
)
}
}
}

View File

@@ -0,0 +1,144 @@
package com.aiosman.ravenow.ui.notification
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.comment.notice.CommentNoticeScreen
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
import com.aiosman.ravenow.ui.composables.TabItem
import com.aiosman.ravenow.ui.composables.TabSpacer
import com.aiosman.ravenow.ui.composables.rememberDebouncer
import com.aiosman.ravenow.ui.follower.FollowerNoticeScreen
import com.aiosman.ravenow.ui.like.LikeNoticeScreen
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import kotlinx.coroutines.launch
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun NotificationScreen() {
val AppColors = LocalAppTheme.current
val navController = LocalNavController.current
val scope = rememberCoroutineScope()
val pagerState = rememberPagerState(pageCount = { 3 })
val Debouncer = rememberDebouncer()
Column(
modifier = Modifier
.fillMaxSize()
.background(color = AppColors.background)
) {
StatusBarSpacer()
Row(
modifier = Modifier
.fillMaxWidth()
.height(56.dp)
.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(id = R.drawable.rider_pro_back_icon),
contentDescription = "Back",
modifier = Modifier
.size(24.dp)
.noRippleClickable {
Debouncer {
navController.popBackStack()
}
},
colorFilter = ColorFilter.tint(AppColors.text)
)
Spacer(modifier = Modifier.width(16.dp))
Text(
text = stringResource(R.string.group_info_notice_setting),
fontSize = 20.sp,
fontWeight = FontWeight.W900,
color = AppColors.text
)
}
Row(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(start = 16.dp, top = 8.dp, bottom = 16.dp),
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.Bottom
) {
TabItem(
text = stringResource(R.string.like),
isSelected = pagerState.currentPage == 0,
onClick = {
scope.launch {
pagerState.animateScrollToPage(0)
}
}
)
TabSpacer()
TabItem(
text = stringResource(R.string.followers_upper),
isSelected = pagerState.currentPage == 1,
onClick = {
scope.launch {
pagerState.animateScrollToPage(1)
}
}
)
TabSpacer()
TabItem(
text = stringResource(R.string.comment).uppercase(),
isSelected = pagerState.currentPage == 2,
onClick = {
scope.launch {
pagerState.animateScrollToPage(2)
}
}
)
}
HorizontalPager(
state = pagerState,
modifier = Modifier
.fillMaxWidth()
.weight(1f)
) { page ->
when (page) {
0 -> LikeNoticeScreen()
1 -> FollowerNoticeScreen()
2 -> CommentNoticeScreen()
}
}
}
}

View File

@@ -799,7 +799,7 @@ fun CommentContent(
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
Image( Image(
painter = painterResource(id = R.mipmap.qs_plq_qs_img), painter = painterResource(id = R.mipmap.invalid_name_3),
contentDescription = null, contentDescription = null,
modifier = Modifier.size(181.dp) modifier = Modifier.size(181.dp)
) )

View File

@@ -1,20 +1,19 @@
package com.aiosman.ravenow.ui.splash package com.aiosman.ravenow.ui.splash
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.size
import androidx.compose.material.Scaffold
import androidx.compose.material.Text import androidx.compose.material.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.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
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
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
@@ -22,38 +21,36 @@ import com.aiosman.ravenow.R
@Composable @Composable
fun SplashScreen() { fun SplashScreen() {
Scaffold {
it
Box( Box(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) { ) {
// to bottom // 居中的图标
Box( Image(
contentAlignment = Alignment.TopCenter, painter = painterResource(id = R.mipmap.invalid_name),
modifier = Modifier.padding(top = 211.dp) contentDescription = "App Logo",
) { modifier = Modifier
.align(Alignment.Center)
.size(120.dp)
)
// 底部文字
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth() verticalArrangement = Arrangement.Bottom,
modifier = Modifier
.fillMaxSize()
.padding(bottom = 80.dp)
) { ) {
Image( Image(
painter = painterResource(id = R.mipmap.rider_pro_logo), painterResource(id = R.mipmap.kp_p_img),
contentDescription = "Rave Now", contentDescription = "",
modifier = Modifier modifier = Modifier.size(85.dp, 25.dp)
.width(108.dp)
.height(45.dp)
) )
Spacer(modifier = Modifier.height(32.dp)) Spacer(modifier = Modifier.padding(top = 16.dp))
Text( Text(
"Rave Now".uppercase(), stringResource(R.string.splash_title),
fontSize = 28.sp, fontSize = 13.sp
fontWeight = FontWeight.Bold
) )
Text("Your Night Starts Here".uppercase(), fontSize = 20.sp, fontWeight = FontWeight.W700)
}
} }
} }
}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 836 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 919 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 852 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 965 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Some files were not shown because too many files have changed in this diff Show More