Enhance AI Agent Profile Interaction

This commit introduces several enhancements to how AI agent profiles are displayed and interacted with:

**Profile Display:**
- **AI Account Distinction:** Profile pages now differentiate between regular user accounts and AI agent accounts.
    - AI agent profiles will not display the "Agents" tab in their profile.
    - The profile header height is adjusted for AI accounts.
- **Navigation Parameter:** An `isAiAccount` boolean parameter is added to the `AccountProfile` navigation route to indicate if the profile being viewed belongs to an AI.

**Interaction & Navigation:**
- **Avatar Click Navigation:**
    - Clicking an AI agent's avatar in various lists (Hot Agents, My Agents, User Agents Row, User Agents List) now navigates to the agent's dedicated profile page.
    - When navigating to an agent's profile from an agent list, `isAiAccount` is set to `true`.
- **Chat Initiation:** Clicking the chat button on AI agent cards in the "Agent" tab (both Hot and My Agents) now correctly initiates a chat with the respective AI.
- **ViewModel Updates:**
    - `AgentViewModel`, `MineAgentViewModel`, and `HotAgentViewModel` now include a `goToProfile` function to handle navigation to agent profiles, correctly passing the `isAiAccount` flag.

**Code Refinements:**
- Click handlers for agent avatars and chat buttons are now wrapped with `DebounceUtils.simpleDebounceClick` to prevent multiple rapid clicks.
- The `UserContentPageIndicator` now conditionally hides the "Agent" tab based on the `isAiAccount` status.
- `UserAgentsRow` and `UserAgentsList` now accept an `onAvatarClick` callback for navigating to agent profiles.
- `AgentItem` (used in `UserAgentsRow`) and `UserAgentCard` (used in `UserAgentsList`) now handle avatar clicks.
- The general `Agent` composable (used in `AiPostComposable`) now also supports an `onAvatarClick` callback.
This commit is contained in:
2025-09-01 14:17:44 +08:00
parent 484d641554
commit 83cff9d56c
23 changed files with 780 additions and 254 deletions

View File

@@ -45,6 +45,12 @@ object AppState {
var enableGoogleLogin: Boolean = false
var enableChat = false
suspend fun initWithAccount(scope: CoroutineScope, context: Context) {
// 如果是游客模式,使用简化的初始化流程
if (AppStore.isGuest) {
initWithGuestAccount()
return
}
val accountService: AccountService = AccountServiceImpl()
// 获取用户认证信息
val resp = accountService.getMyAccount()
@@ -69,6 +75,18 @@ object AppState {
initChat(context)
}
/**
* 游客模式的简化初始化
*/
private fun initWithGuestAccount() {
// 游客模式下不初始化推送和TRTC
// 设置默认的用户信息
UserId = 0
profile = null
enableChat = false
Log.d("AppState", "Guest mode initialized without push notifications and TRTC")
}
private suspend fun initChat(context: Context){
val dictService :DictService = DictServiceImpl()
val enableItem = dictService.getDictByKey(ConstVars.DICT_KEY_ENABLE_TRTC)
@@ -149,6 +167,27 @@ object AppState {
AppStore.saveDarkMode(darkMode)
}
/**
* 检查是否是游客模式,并且是否需要登录
* @return true 如果是游客模式
*/
fun isGuestMode(): Boolean {
return AppStore.isGuest
}
/**
* 检查游客模式并提示登录
* @param onGuestMode 当是游客模式时的回调
* @return true 如果是游客模式
*/
fun checkGuestModeAndPromptLogin(onGuestMode: (() -> Unit)? = null): Boolean {
if (AppStore.isGuest) {
onGuestMode?.invoke()
return true
}
return false
}
fun ReloadAppState(context: Context) {
// 重置动态列表页面
TimelineMomentViewModel.ResetModel()
@@ -175,6 +214,9 @@ object AppState {
IndexViewModel.ResetModel()
UserId = null
// 清除游客状态
AppStore.isGuest = false
// 关闭 TrtcService
val trtcService = Intent(
context,

View File

@@ -41,3 +41,33 @@ object ConstVars {
const val DICT_KEY_REPORT_OPTIONS = "report_reasons"
}
enum class GuestLoginCheckOutScene {
CREATE_POST,
CREATE_AGENT,
VIEW_MESSAGES,
VIEW_PROFILE,
JOIN_GROUP_CHAT,
CHAT_WITH_AGENT,
LIKE_MOMENT,
COMMENT_MOMENT,
FOLLOW_USER,
REPORT_CONTENT
}
object GuestLoginCheckOut {
var NeedLoginScene = listOf<GuestLoginCheckOutScene>(
GuestLoginCheckOutScene.CREATE_POST,
GuestLoginCheckOutScene.CREATE_AGENT,
GuestLoginCheckOutScene.VIEW_MESSAGES,
GuestLoginCheckOutScene.VIEW_PROFILE,
GuestLoginCheckOutScene.JOIN_GROUP_CHAT,
GuestLoginCheckOutScene.CHAT_WITH_AGENT,
GuestLoginCheckOutScene.LIKE_MOMENT,
GuestLoginCheckOutScene.COMMENT_MOMENT,
GuestLoginCheckOutScene.FOLLOW_USER,
GuestLoginCheckOutScene.REPORT_CONTENT
)
fun needLogin(scene: GuestLoginCheckOutScene): Boolean {
return AppStore.isGuest && NeedLoginScene.contains(scene)
}
}

View File

@@ -114,8 +114,9 @@ class MainActivity : ComponentActivity() {
// 检查是否有登录态
val isAccountValidate = getAccount()
var startDestination = NavigationRoute.Login.route
// 如果有登录态,且记住登录状态,且账号有效,则初始化 FCM,下一步进入首页
if (AppStore.token != null && AppStore.rememberMe && isAccountValidate) {
// 如果有登录态,且记住登录状态,且账号有效,则初始化应用状态,下一步进入首页
if (AppStore.token != null && AppStore.rememberMe && (isAccountValidate || AppStore.isGuest)) {
// 根据用户类型进行相应的初始化游客模式会跳过推送和TRTC初始化
AppState.initWithAccount(scope, this@MainActivity)
startDestination = NavigationRoute.Index.route
}

View File

@@ -7,6 +7,7 @@ import com.aiosman.ravenow.data.api.AppConfig
import com.aiosman.ravenow.data.api.CaptchaInfo
import com.aiosman.ravenow.data.api.ChangePasswordRequestBody
import com.aiosman.ravenow.data.api.GoogleRegisterRequestBody
import com.aiosman.ravenow.data.api.GuestLoginRequestBody
import com.aiosman.ravenow.data.api.LoginUserRequestBody
import com.aiosman.ravenow.data.api.RegisterMessageChannelRequestBody
import com.aiosman.ravenow.data.api.RegisterRequestBody
@@ -300,6 +301,13 @@ interface AccountService {
*/
suspend fun loginUserWithGoogle(googleId: String): UserAuth
/**
* 游客登录
* @param deviceId 设备ID
* @param deviceInfo 设备信息
*/
suspend fun guestLogin(deviceId: String, deviceInfo: String? = null): UserAuth
/**
* 退出登录
*/
@@ -456,6 +464,21 @@ class AccountServiceImpl : AccountService {
return UserAuth(0, body.token)
}
override suspend fun guestLogin(deviceId: String, deviceInfo: String?): UserAuth {
val resp = ApiClient.api.guestLogin(GuestLoginRequestBody(
deviceId = deviceId,
deviceInfo = deviceInfo
))
if (!resp.isSuccessful) {
parseErrorResponse(resp.errorBody())?.let {
throw it.toServiceException()
}
throw ServiceException("Failed to guest login")
}
val body = resp.body() ?: throw ServiceException("Failed to guest login")
return UserAuth(0, body.token, isGuest = true)
}
override suspend fun regiterUserWithGoogleAccount(idToken: String) {
val resp = ApiClient.api.registerWithGoogle(GoogleRegisterRequestBody(idToken))
if (!resp.isSuccessful) {

View File

@@ -5,7 +5,8 @@ import com.aiosman.ravenow.entity.AccountProfileEntity
data class UserAuth(
val id: Int,
val token: String? = null
val token: String? = null,
val isGuest: Boolean = false
)
/**

View File

@@ -23,7 +23,29 @@ fun getUnsafeOkHttpClient(
): OkHttpClient {
return try {
// Create a trust manager that does not validate certificate chains
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {
}
@Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {
}
override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> {
return arrayOf()
}
})
// Install the all-trusting trust manager
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, java.security.SecureRandom())
// Create an ssl socket factory with our all-trusting manager
val sslSocketFactory = sslContext.socketFactory
OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
.hostnameVerifier { _, _ -> true }
.apply {
authInterceptor?.let {

View File

@@ -95,6 +95,19 @@ data class LoginUserRequestBody(
val captcha: CaptchaInfo? = null,
)
data class GuestLoginRequestBody(
@SerializedName("deviceID")
val deviceId: String,
@SerializedName("platform")
val platform: String = "android",
@SerializedName("deviceInfo")
val deviceInfo: String? = null,
@SerializedName("userAgent")
val userAgent: String? = null,
@SerializedName("ipAddress")
val ipAddress: String? = null
)
data class GoogleRegisterRequestBody(
@SerializedName("idToken")
val idToken: String
@@ -274,6 +287,9 @@ interface RaveNowAPI {
@POST("login")
suspend fun login(@Body body: LoginUserRequestBody): Response<AuthResult>
@POST("guest/login")
suspend fun guestLogin(@Body body: GuestLoginRequestBody): Response<AuthResult>
@GET("auth/token")
suspend fun checkToken(): Response<ValidateTokenResult>

View File

@@ -2,6 +2,7 @@ package com.aiosman.ravenow.entity
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.aiosman.ravenow.AppStore
import com.aiosman.ravenow.data.Agent
import com.aiosman.ravenow.data.ListContainer
import com.aiosman.ravenow.data.AgentService
@@ -28,24 +29,37 @@ suspend fun createAgent(
title: String,
desc: String,
avatar: UploadImage? = null,
workflowId:Int = 1,
isPublic:Boolean = true,
breakMode:Boolean = false,
useWorkflow:Boolean = true,
workflowId: Int = 1,
isPublic: Boolean = true,
breakMode: Boolean = false,
useWorkflow: Boolean = true,
): AgentEntity {
val textTitle = title.toRequestBody("text/plain".toMediaTypeOrNull())
val textDesc = desc.toRequestBody("text/plain".toMediaTypeOrNull())
val workflowIdRequestBody = workflowId.toString().toRequestBody("text/plain".toMediaTypeOrNull())
val workflowIdRequestBody =
workflowId.toString().toRequestBody("text/plain".toMediaTypeOrNull())
val isPublicRequestBody = isPublic.toString().toRequestBody("text/plain".toMediaTypeOrNull())
val breakModeRequestBody = breakMode.toString().toRequestBody("text/plain".toMediaTypeOrNull())
val useWorkflowRequestBody = useWorkflow.toString().toRequestBody("text/plain".toMediaTypeOrNull())
val useWorkflowRequestBody =
useWorkflow.toString().toRequestBody("text/plain".toMediaTypeOrNull())
val workflowInputsValue = "{\"si\":\"$desc\"}"
val workflowInputsRequestBody = workflowInputsValue.toRequestBody("text/plain".toMediaTypeOrNull())
val workflowInputsRequestBody =
workflowInputsValue.toRequestBody("text/plain".toMediaTypeOrNull())
val avatarField: MultipartBody.Part? = avatar?.let {
createMultipartBody(it.file, it.filename, "avatar")
}
val response = ApiClient.api.createAgent(avatarField, textTitle ,textDesc,textDesc,workflowIdRequestBody,isPublicRequestBody,breakModeRequestBody,useWorkflowRequestBody,workflowInputsRequestBody)
val response = ApiClient.api.createAgent(
avatarField,
textTitle,
textDesc,
textDesc,
workflowIdRequestBody,
isPublicRequestBody,
breakModeRequestBody,
useWorkflowRequestBody,
workflowInputsRequestBody
)
val body = response.body()?.data ?: throw ServiceException("Failed to create agent")
return body.toAgentEntity()
@@ -99,7 +113,11 @@ class AgentRemoteDataSource(
class AgentServiceImpl() : AgentService {
val agentBackend = AgentBackend()
override suspend fun getAgent(pageNumber: Int, pageSize: Int, authorId: Int?): ListContainer<AgentEntity> {
override suspend fun getAgent(
pageNumber: Int,
pageSize: Int,
authorId: Int?
): ListContainer<AgentEntity> {
return agentBackend.getAgent(
pageNumber = pageNumber,
authorId = authorId
@@ -107,50 +125,62 @@ class AgentServiceImpl() : AgentService {
}
}
class AgentBackend {
val DataBatchSize = 20
suspend fun getAgent(
pageNumber: Int,
authorId: Int? = null
): ListContainer<AgentEntity> {
val resp = if (authorId != null) {
ApiClient.api.getAgent(
page = pageNumber,
pageSize = DataBatchSize,
authorId = authorId
)
} else {
ApiClient.api.getMyAgent(
page = pageNumber,
pageSize = DataBatchSize
)
}
val body = resp.body() ?: throw ServiceException("Failed to get agents")
// 处理不同的返回类型
return if (authorId != null) {
// getAgent 返回 DataContainer<ListContainer<Agent>>
val dataContainer = body as com.aiosman.ravenow.data.DataContainer<com.aiosman.ravenow.data.ListContainer<com.aiosman.ravenow.data.Agent>>
val listContainer = dataContainer.data
ListContainer(
total = listContainer.total,
page = pageNumber,
pageSize = DataBatchSize,
list = listContainer.list.map { it.toAgentEntity() }
)
} else {
// getMyAgent 返回 ListContainer<Agent>
val listContainer = body as com.aiosman.ravenow.data.ListContainer<com.aiosman.ravenow.data.Agent>
ListContainer(
total = listContainer.total,
page = pageNumber,
pageSize = DataBatchSize,
list = listContainer.list.map { it.toAgentEntity() }
)
}
class AgentBackend {
val DataBatchSize = 20
suspend fun getAgent(
pageNumber: Int,
authorId: Int? = null
): ListContainer<AgentEntity> {
// 如果是游客模式且获取我的AgentauthorId为null返回空列表
if (authorId == null && AppStore.isGuest) {
return ListContainer(
total = 0,
page = pageNumber,
pageSize = DataBatchSize,
list = emptyList()
)
}
val resp = if (authorId != null) {
ApiClient.api.getAgent(
page = pageNumber,
pageSize = DataBatchSize,
authorId = authorId
)
} else {
ApiClient.api.getMyAgent(
page = pageNumber,
pageSize = DataBatchSize
)
}
val body = resp.body() ?: throw ServiceException("Failed to get agents")
// 处理不同的返回类型
return if (authorId != null) {
// getAgent 返回 DataContainer<ListContainer<Agent>>
val dataContainer =
body as com.aiosman.ravenow.data.DataContainer<com.aiosman.ravenow.data.ListContainer<com.aiosman.ravenow.data.Agent>>
val listContainer = dataContainer.data
ListContainer(
total = listContainer.total,
page = pageNumber,
pageSize = DataBatchSize,
list = listContainer.list.map { it.toAgentEntity() }
)
} else {
// getMyAgent 返回 ListContainer<Agent>
val listContainer =
body as com.aiosman.ravenow.data.ListContainer<com.aiosman.ravenow.data.Agent>
ListContainer(
total = listContainer.total,
page = pageNumber,
pageSize = DataBatchSize,
list = listContainer.list.map { it.toAgentEntity() }
)
}
}
}
data class AgentEntity(
//val author: String,
@@ -172,15 +202,27 @@ fun createMultipartBody(file: File, filename: String, name: String): MultipartBo
val requestFile = file.asRequestBody("image/*".toMediaTypeOrNull())
return MultipartBody.Part.createFormData(name, filename, requestFile)
}
class AgentLoaderExtraArgs(
val authorId: Int? = null
)
class AgentLoader : DataLoader<AgentEntity,AgentLoaderExtraArgs>() {
class AgentLoader : DataLoader<AgentEntity, AgentLoaderExtraArgs>() {
override suspend fun fetchData(
page: Int,
pageSize: Int,
extra: AgentLoaderExtraArgs
): ListContainer<AgentEntity> {
// 如果是游客模式且获取我的AgentauthorId为null返回空列表
if (extra.authorId == null && AppStore.isGuest) {
return ListContainer(
total = 0,
page = page,
pageSize = pageSize,
list = emptyList()
)
}
val result = if (extra.authorId != null) {
ApiClient.api.getAgent(
page = page,
@@ -193,24 +235,25 @@ class AgentLoader : DataLoader<AgentEntity,AgentLoaderExtraArgs>() {
pageSize = pageSize
)
}
val body = result.body() ?: throw ServiceException("Failed to get agent")
return if (extra.authorId != null) {
// getAgent 返回 DataContainer<ListContainer<Agent>>
val dataContainer = body as DataContainer<ListContainer<Agent>>
val listContainer = dataContainer.data
ListContainer(
list = listContainer.list.map { it.toAgentEntity()},
list = listContainer.list.map { it.toAgentEntity() },
total = listContainer.total,
page = page,
pageSize = pageSize
)
} else {
// getMyAgent 返回 ListContainer<Agent>
val listContainer = body as com.aiosman.ravenow.data.ListContainer<com.aiosman.ravenow.data.Agent>
val listContainer =
body as com.aiosman.ravenow.data.ListContainer<com.aiosman.ravenow.data.Agent>
ListContainer(
list = listContainer.list.map { it.toAgentEntity()},
list = listContainer.list.map { it.toAgentEntity() },
total = listContainer.total,
page = page,
pageSize = pageSize

View File

@@ -12,6 +12,7 @@ object AppStore {
private const val PREFS_NAME = "app_prefs_$STORE_VERSION"
var token: String? = null
var rememberMe: Boolean = false
var isGuest: Boolean = false
private lateinit var sharedPreferences: SharedPreferences
lateinit var googleSignInOptions: GoogleSignInOptions
fun init(context: Context) {
@@ -36,6 +37,7 @@ object AppStore {
sharedPreferences.edit().apply {
putString("token", token)
putBoolean("rememberMe", rememberMe)
putBoolean("isGuest", isGuest)
}.apply()
}
@@ -43,6 +45,7 @@ object AppStore {
// shared preferences
token = sharedPreferences.getString("token", null)
rememberMe = sharedPreferences.getBoolean("rememberMe", false)
isGuest = sharedPreferences.getBoolean("isGuest", false)
}
fun saveDarkMode(darkMode: Boolean) {

View File

@@ -59,6 +59,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.ravenow.AppState
import com.aiosman.ravenow.AppStore
import com.aiosman.ravenow.GuestLoginCheckOut
import com.aiosman.ravenow.GuestLoginCheckOutScene
import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.Messaging
@@ -238,10 +240,14 @@ fun IndexScreen() {
modifier = Modifier.noRippleClickable {
coroutineScope.launch {
drawerState.close()
Messaging.unregisterDevice(context)
// 只有非游客用户才需要取消注册推送设备
if (!AppStore.isGuest) {
Messaging.unregisterDevice(context)
}
AppStore.apply {
token = null
rememberMe = false
isGuest = false // 清除游客状态
saveData()
}
// 删除推送渠道
@@ -280,10 +286,32 @@ fun IndexScreen() {
.padding(top = 2.dp)
.noRippleClickable {
if (it.route === NavigationItem.Add.route) {
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CREATE_POST)) {
navController.navigate(NavigationRoute.Login.route)
return@noRippleClickable
}
NewPostViewModel.asNewPost()
navController.navigate(NavigationRoute.NewPost.route)
return@noRippleClickable
}
// 检查消息tab的游客模式
if (it.route === NavigationItem.Notification.route) {
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.VIEW_MESSAGES)) {
navController.navigate(NavigationRoute.Login.route)
return@noRippleClickable
}
}
// 检查我的tab的游客模式
if (it.route === NavigationItem.Profile.route) {
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.VIEW_PROFILE)) {
navController.navigate(NavigationRoute.Login.route)
return@noRippleClickable
}
}
coroutineScope.launch {
pagerState.scrollToPage(idx)
}

View File

@@ -46,6 +46,9 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.aiosman.ravenow.AppStore
import com.aiosman.ravenow.GuestLoginCheckOut
import com.aiosman.ravenow.GuestLoginCheckOutScene
import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R
@@ -70,7 +73,9 @@ fun Agent() {
val navigationBarPaddings =
WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 48.dp
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
var pagerState = rememberPagerState { 2 }
// 游客模式下只显示热门Agent正常用户显示我的Agent和热门Agent
val tabCount = if (AppStore.isGuest) 1 else 2
var pagerState = rememberPagerState { tabCount }
var scope = rememberCoroutineScope()
val viewModel: AgentViewModel = viewModel()
@@ -137,10 +142,15 @@ fun Agent() {
.size(36.dp)
.noRippleClickable {
if (DebounceUtils.simpleDebounceClick(lastClickTime, 500L) {
// 导航到添加智能体页面
navController.navigate(
NavigationRoute.AddAgent.route
)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CREATE_AGENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
// 导航到添加智能体页面
navController.navigate(
NavigationRoute.AddAgent.route
)
}
}) {
lastClickTime = System.currentTimeMillis()
}
@@ -205,27 +215,33 @@ fun Agent() {
color = AppColors.text
)
Spacer(modifier = Modifier.weight(1f))
TabItem(
text = stringResource(R.string.agent_mine),
isSelected = pagerState.currentPage == 0,
onClick = {
if (DebounceUtils.simpleDebounceClick(lastClickTime, 300L) {
scope.launch {
pagerState.animateScrollToPage(0)
// 只有非游客用户才显示"我的Agent"tab
if (!AppStore.isGuest) {
TabItem(
text = stringResource(R.string.agent_mine),
isSelected = pagerState.currentPage == 0,
onClick = {
if (DebounceUtils.simpleDebounceClick(lastClickTime, 300L) {
scope.launch {
pagerState.animateScrollToPage(0)
}
}) {
lastClickTime = System.currentTimeMillis()
}
}) {
lastClickTime = System.currentTimeMillis()
}
}
)
TabSpacer()
)
TabSpacer()
}
TabItem(
text = stringResource(R.string.agent_hot),
isSelected = pagerState.currentPage == 1,
isSelected = if (AppStore.isGuest) pagerState.currentPage == 0 else pagerState.currentPage == 1,
onClick = {
if (DebounceUtils.simpleDebounceClick(lastClickTime, 300L) {
scope.launch {
pagerState.animateScrollToPage(1)
val targetPage = if (AppStore.isGuest) 0 else 1
pagerState.animateScrollToPage(targetPage)
}
}) {
lastClickTime = System.currentTimeMillis()
@@ -261,23 +277,24 @@ fun Agent() {
.weight(1f),
beyondBoundsPageCount = 1 // 预加载相邻页面,避免切换时重新加载
) {
when (it) {
0 -> {
MineAgent()
if (AppStore.isGuest) {
// 游客模式下只显示热门Agent
when (it) {
0 -> {
HotAgent()
}
}
} else {
// 正常用户显示我的Agent和热门Agent
when (it) {
0 -> {
MineAgent()
}
1 -> {
HotAgent()
1 -> {
HotAgent()
}
}
2 -> {
}
3 -> {
}
}
}
}

View File

@@ -39,6 +39,7 @@ import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.ravenow.AppStore
import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R
@@ -62,7 +63,9 @@ fun MomentsList() {
val navigationBarPaddings =
WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 48.dp
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
var pagerState = rememberPagerState { 4 }
// 游客模式下不显示timeline只显示3个tabExplore、Dynamic、Hot
val tabCount = if (AppStore.isGuest) 3 else 4
var pagerState = rememberPagerState { tabCount }
var scope = rememberCoroutineScope()
Column(
modifier = Modifier
@@ -141,36 +144,40 @@ fun MomentsList() {
)
}
//关注tab
Spacer(modifier = Modifier.width(16.dp))
Column(
modifier = Modifier
.noRippleClickable {
scope.launch {
pagerState.animateScrollToPage(2)
}
},
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = stringResource(R.string.index_following),
fontSize = if (pagerState.currentPage == 2)18.sp else 16.sp,
color = if (pagerState.currentPage == 2) AppColors.text else Color(0X993c3c43),
fontWeight = FontWeight.W600)
Spacer(modifier = Modifier.height(4.dp))
Image(
painter = painterResource(
if (pagerState.currentPage == 2) R.mipmap.tab_indicator_selected
else R.drawable.tab_indicator_unselected
),
contentDescription = "tab indicator",
// 只有非游客用户才显示"关注"tab
if (!AppStore.isGuest) {
//关注tab
Spacer(modifier = Modifier.width(16.dp))
Column(
modifier = Modifier
.width(34.dp)
.height(4.dp)
)
.noRippleClickable {
scope.launch {
pagerState.animateScrollToPage(2)
}
},
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = stringResource(R.string.index_following),
fontSize = if (pagerState.currentPage == 2)18.sp else 16.sp,
color = if (pagerState.currentPage == 2) AppColors.text else Color(0X993c3c43),
fontWeight = FontWeight.W600)
Spacer(modifier = Modifier.height(4.dp))
Image(
painter = painterResource(
if (pagerState.currentPage == 2) R.mipmap.tab_indicator_selected
else R.drawable.tab_indicator_unselected
),
contentDescription = "tab indicator",
modifier = Modifier
.width(34.dp)
.height(4.dp)
)
}
}
//热门tab
Spacer(modifier = Modifier.width(16.dp))
@@ -178,7 +185,8 @@ fun MomentsList() {
modifier = Modifier
.noRippleClickable {
scope.launch {
pagerState.animateScrollToPage(3)
val targetPage = if (AppStore.isGuest) 2 else 3
pagerState.animateScrollToPage(targetPage)
}
},
verticalArrangement = Arrangement.Center,
@@ -186,14 +194,14 @@ fun MomentsList() {
) {
Text(
text = stringResource(R.string.index_hot),
fontSize = if (pagerState.currentPage == 3)18.sp else 16.sp,
color = if (pagerState.currentPage == 3) AppColors.text else Color(0X993c3c43),
fontSize = if ((AppStore.isGuest && pagerState.currentPage == 2) || (!AppStore.isGuest && pagerState.currentPage == 3)) 18.sp else 16.sp,
color = if ((AppStore.isGuest && pagerState.currentPage == 2) || (!AppStore.isGuest && pagerState.currentPage == 3)) AppColors.text else Color(0X993c3c43),
fontWeight = FontWeight.W600)
Spacer(modifier = Modifier.height(4.dp))
Image(
painter = painterResource(
if (pagerState.currentPage == 3) R.mipmap.tab_indicator_selected
if ((AppStore.isGuest && pagerState.currentPage == 2) || (!AppStore.isGuest && pagerState.currentPage == 3)) R.mipmap.tab_indicator_selected
else R.drawable.tab_indicator_unselected
),
contentDescription = "tab indicator",
@@ -228,22 +236,35 @@ fun MomentsList() {
.fillMaxWidth()
.weight(1f)
) {
when (it) {
0 -> {
Explore()
if (AppStore.isGuest) {
// 游客模式Explore(0), Dynamic(1), Hot(2)
when (it) {
0 -> {
Explore()
}
1 -> {
Dynamic()
}
2 -> {
HotMomentsList()
}
}
1 -> {
Dynamic()
} else {
// 正常用户Explore(0), Dynamic(1), Timeline(2), Hot(3)
when (it) {
0 -> {
Explore()
}
1 -> {
Dynamic()
}
2 -> {
TimelineMomentsList()
}
3 -> {
HotMomentsList()
}
}
2 -> {
TimelineMomentsList()
}
3 -> {
HotMomentsList()
}
}
}
}

View File

@@ -17,6 +17,10 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import com.aiosman.ravenow.GuestLoginCheckOut
import com.aiosman.ravenow.GuestLoginCheckOutScene
import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.ui.composables.MomentCard
import kotlinx.coroutines.launch
@@ -28,6 +32,7 @@ import kotlinx.coroutines.launch
fun Dynamic() {
val model = DynamicViewModel
var moments = model.moments
val navController = LocalNavController.current
val scope = rememberCoroutineScope()
val state = rememberPullRefreshState(model.refreshing, onRefresh = {
@@ -73,30 +78,50 @@ fun Dynamic() {
val momentItem = moments[idx] ?: return@items
MomentCard(momentEntity = momentItem,
onAddComment = {
scope.launch {
model.onAddComment(momentItem.id)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.COMMENT_MOMENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
scope.launch {
model.onAddComment(momentItem.id)
}
}
},
onLikeClick = {
scope.launch {
if (momentItem.liked) {
model.dislikeMoment(momentItem.id)
} else {
model.likeMoment(momentItem.id)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
scope.launch {
if (momentItem.liked) {
model.dislikeMoment(momentItem.id)
} else {
model.likeMoment(momentItem.id)
}
}
}
},
onFavoriteClick = {
scope.launch {
if (momentItem.isFavorite) {
model.unfavoriteMoment(momentItem.id)
} else {
model.favoriteMoment(momentItem.id)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
scope.launch {
if (momentItem.isFavorite) {
model.unfavoriteMoment(momentItem.id)
} else {
model.favoriteMoment(momentItem.id)
}
}
}
},
onFollowClick = {
model.followAction(momentItem)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.FOLLOW_USER)) {
navController.navigate(NavigationRoute.Login.route)
} else {
model.followAction(momentItem)
}
},
showFollowButton = true
)

View File

@@ -54,6 +54,8 @@ import androidx.compose.ui.res.stringResource
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import androidx.lifecycle.viewmodel.compose.viewModel
import com.aiosman.ravenow.AppStore
import com.aiosman.ravenow.GuestLoginCheckOut
import com.aiosman.ravenow.GuestLoginCheckOutScene
import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R
@@ -236,8 +238,13 @@ fun Explore() {
shape = RoundedCornerShape(8.dp)
)
.clickable {
viewModel.createSingleChat(agentItem.openId)
viewModel.goToChatAi(agentItem.openId, navController = navController)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CHAT_WITH_AGENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
viewModel.createSingleChat(agentItem.openId)
viewModel.goToChatAi(agentItem.openId, navController = navController)
}
},
contentAlignment = Alignment.Center
) {
@@ -353,19 +360,24 @@ fun Explore() {
},
shape = RoundedCornerShape(12.dp))
.clickable {
// 调用加入房间接口
viewModel.joinRoom(
trtcId = roomItem.trtcId.toString(),
name = roomItem.title,
avatar = roomItem.avatar,
navController = navController,
onSuccess = {
Toast.makeText(context, enterSuccessText, Toast.LENGTH_SHORT).show()
},
onError = { errorMessage ->
Toast.makeText(context, enterFailText, Toast.LENGTH_SHORT).show()
}
)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.JOIN_GROUP_CHAT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
// 调用加入房间接口
viewModel.joinRoom(
trtcId = roomItem.trtcId.toString(),
name = roomItem.title,
avatar = roomItem.avatar,
navController = navController,
onSuccess = {
Toast.makeText(context, enterSuccessText, Toast.LENGTH_SHORT).show()
},
onError = { errorMessage ->
Toast.makeText(context, enterFailText, Toast.LENGTH_SHORT).show()
}
)
}
},
verticalAlignment = Alignment.CenterVertically
@@ -615,19 +627,24 @@ fun Explore() {
shape = RoundedCornerShape(8.dp)
)
.clickable {
// 调用加入房间接口
viewModel.joinRoom(
trtcId = bannerItem.trtcId.toString(),
name = bannerItem.title,
avatar = bannerItem.avatar,
navController = navController,
onSuccess = {
Toast.makeText(context, enterSuccessText, Toast.LENGTH_SHORT).show()
},
onError = { errorMessage ->
Toast.makeText(context, enterFailText, Toast.LENGTH_SHORT).show()
}
)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.JOIN_GROUP_CHAT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
// 调用加入房间接口
viewModel.joinRoom(
trtcId = bannerItem.trtcId.toString(),
name = bannerItem.title,
avatar = bannerItem.avatar,
navController = navController,
onSuccess = {
Toast.makeText(context, enterSuccessText, Toast.LENGTH_SHORT).show()
},
onError = { errorMessage ->
Toast.makeText(context, enterFailText, Toast.LENGTH_SHORT).show()
}
)
}
},
contentAlignment = Alignment.Center
) {
@@ -671,7 +688,12 @@ fun Explore() {
Column(
modifier = Modifier
.clickable {
navController.navigate(NavigationRoute.CreateGroupChat.route)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.JOIN_GROUP_CHAT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
navController.navigate(NavigationRoute.CreateGroupChat.route)
}
},
horizontalAlignment = Alignment.CenterHorizontally
) {
@@ -706,8 +728,12 @@ fun Explore() {
Column(
modifier = Modifier
.clickable {
navController.navigate(
NavigationRoute.AddAgent.route)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CREATE_AGENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
navController.navigate(NavigationRoute.AddAgent.route)
}
},
horizontalAlignment = Alignment.CenterHorizontally
) {
@@ -737,8 +763,13 @@ fun Explore() {
Column(
modifier = Modifier
.clickable {
NewPostViewModel.asNewPost()
navController.navigate("NewPost")
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CREATE_POST)) {
navController.navigate(NavigationRoute.Login.route)
} else {
NewPostViewModel.asNewPost()
navController.navigate("NewPost")
}
},
horizontalAlignment = Alignment.CenterHorizontally
) {

View File

@@ -58,6 +58,12 @@ object MyProfileViewModel : ViewModel() {
}
suspend fun loadUserProfile() {
// 游客模式下不获取用户资料
if (AppStore.isGuest) {
MyProfileViewModel.profile = null
return
}
val profile = accountService.getMyAccountProfile()
MyProfileViewModel.profile = profile
}
@@ -71,6 +77,12 @@ object MyProfileViewModel : ViewModel() {
firstLoad = false
loadUserProfile()
refreshing = false
// 游客模式下不加载个人动态和智能体
if (AppStore.isGuest) {
return@launch
}
profile?.let {
try {
momentLoader.loadData(extra = MomentLoaderExtraArgs(authorId = it.id))
@@ -85,6 +97,12 @@ object MyProfileViewModel : ViewModel() {
}
fun loadMoreMoment() {
// 游客模式下不加载更多动态
if (AppStore.isGuest) {
Log.d("MyProfileViewModel", "loadMoreMoment: 游客模式下跳过加载更多动态")
return
}
viewModelScope.launch {
profile?.let { profileData ->
try {
@@ -100,19 +118,30 @@ object MyProfileViewModel : ViewModel() {
fun logout(context: Context) {
viewModelScope.launch {
Messaging.unregisterDevice(context)
// 只有非游客用户才需要取消注册推送设备
if (!AppStore.isGuest) {
Messaging.unregisterDevice(context)
}
AppStore.apply {
token = null
rememberMe = false
isGuest = false // 清除游客状态
saveData()
}
// 删除推送渠道
// 删除推送渠道和重置应用状态
AppState.ReloadAppState(context)
}
}
fun updateUserProfileBanner(bannerImageUrl: Uri?, file: File, context: Context) {
// 游客模式下不允许更新用户资料
if (AppStore.isGuest) {
Log.d("MyProfileViewModel", "updateUserProfileBanner: 游客模式下无法更新用户资料")
return
}
viewModelScope.launch {
val newBanner = bannerImageUrl?.let {
val cursor = context.contentResolver.query(it, null, null, null, null)
@@ -141,6 +170,12 @@ object MyProfileViewModel : ViewModel() {
}
fun likeMoment(momentLMomentEntity: MomentEntity) {
// 游客模式下不允许点赞
if (AppStore.isGuest) {
Log.d("MyProfileViewModel", "likeMoment: 游客模式下无法点赞")
return
}
viewModelScope.launch {
if (momentLMomentEntity.liked) {
momentService.dislikeMoment(momentLMomentEntity.id)

View File

@@ -61,6 +61,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.ravenow.AppState
import com.aiosman.ravenow.ConstVars
import com.aiosman.ravenow.GuestLoginCheckOut
import com.aiosman.ravenow.GuestLoginCheckOutScene
import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.MainActivity

View File

@@ -29,8 +29,12 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.ravenow.AppState
import com.aiosman.ravenow.GuestLoginCheckOut
import com.aiosman.ravenow.GuestLoginCheckOutScene
import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.entity.AccountProfileEntity
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
@@ -41,6 +45,7 @@ fun OtherProfileAction(
onChat: (() -> Unit)? = null
) {
val AppColors = LocalAppTheme.current
val navController = LocalNavController.current
// 定义渐变色
val followGradient = Brush.horizontalGradient(
@@ -84,7 +89,12 @@ fun OtherProfileAction(
}
.padding(horizontal = 16.dp, vertical = 12.dp)
.noRippleClickable {
onFollow?.invoke()
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.FOLLOW_USER)) {
navController.navigate(NavigationRoute.Login.route)
} else {
onFollow?.invoke()
}
}
) {
Text(
@@ -112,7 +122,12 @@ fun OtherProfileAction(
.background(AppColors.nonActive) // 使用主题灰色背景
.padding(horizontal = 16.dp, vertical = 12.dp)
.noRippleClickable {
onChat?.invoke()
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CHAT_WITH_AGENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
onChat?.invoke()
}
}
) {
Text(

View File

@@ -35,8 +35,12 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.ravenow.GuestLoginCheckOut
import com.aiosman.ravenow.GuestLoginCheckOutScene
import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.entity.AgentEntity
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.utils.DebounceUtils
@@ -82,6 +86,7 @@ fun UserAgentCard(
onAvatarClick: (AgentEntity) -> Unit = {}
) {
val AppColors = LocalAppTheme.current
val navController = LocalNavController.current
// 防抖状态
var lastClickTime by remember { mutableStateOf(0L) }
@@ -165,7 +170,12 @@ fun UserAgentCard(
)
.clickable {
if (DebounceUtils.simpleDebounceClick(lastClickTime, 500L) {
onAgentClick(agent)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CHAT_WITH_AGENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
onAgentClick(agent)
}
}) {
lastClickTime = System.currentTimeMillis()
}

View File

@@ -149,6 +149,7 @@ fun EmailSignupScreen() {
AppStore.apply {
token = authResp.token
this.rememberMe = rememberMe
isGuest = false // 清除游客状态
saveData()
}
// 获取token 信息

View File

@@ -153,6 +153,7 @@ fun LoginPage() {
AppStore.apply {
token = authResp.token
this.rememberMe = true
isGuest = false // 清除游客状态
saveData()
}
// 获取token 信息
@@ -180,6 +181,76 @@ fun LoginPage() {
}
}
fun guestLogin() {
coroutineScope.launch {
try {
// 生成设备ID
val deviceId = android.provider.Settings.Secure.getString(
context.contentResolver,
android.provider.Settings.Secure.ANDROID_ID
) ?: "unknown_device"
// 获取设备信息
val deviceInfo = "${android.os.Build.MANUFACTURER} ${android.os.Build.MODEL}"
// 调用游客登录API
val authResp = accountService.guestLogin(deviceId, deviceInfo)
// 保存token和游客状态
AppStore.apply {
token = authResp.token
isGuest = true
rememberMe = true
saveData()
}
// 显示成功提示
coroutineScope.launch(Dispatchers.Main) {
Toast.makeText(
context,
"游客登录成功",
Toast.LENGTH_SHORT
).show()
}
// 初始化应用状态游客模式会自动跳过推送和TRTC初始化
try {
AppState.initWithAccount(coroutineScope, context)
} catch (e: Exception) {
Log.e(TAG, "Failed to init with guest account", e)
// 游客模式下初始化失败不是致命错误,可以继续
}
// 导航到主页
coroutineScope.launch(Dispatchers.Main) {
navController.navigate(NavigationRoute.Index.route) {
popUpTo(NavigationRoute.Login.route) { inclusive = true }
}
}
} catch (e: ServiceException) {
coroutineScope.launch(Dispatchers.Main) {
Toast.makeText(
context,
"游客登录失败: ${e.message}",
Toast.LENGTH_SHORT
).show()
}
Log.e(TAG, "Guest login failed", e)
} catch (e: Exception) {
coroutineScope.launch(Dispatchers.Main) {
Toast.makeText(
context,
"游客登录失败",
Toast.LENGTH_SHORT
).show()
}
Log.e(TAG, "Guest login failed", e)
}
}
}
Box(
modifier = Modifier
.fillMaxSize()
@@ -260,6 +331,16 @@ fun LoginPage() {
NavigationRoute.UserAuth.route,
)
}
// 游客登录按钮
Spacer(modifier = Modifier.height(16.dp))
ActionButton(
modifier = Modifier.fillMaxWidth(),
text = "游客模式",
color = AppColors.text.copy(alpha = 0.7f),
) {
guestLogin()
}
Spacer(modifier = Modifier.height(70.dp))
}
}

View File

@@ -89,6 +89,7 @@ fun SignupScreen() {
AppStore.apply {
token = authResp.token
this.rememberMe = true
isGuest = false // 清除游客状态
saveData()
}
// 获取token 信息

View File

@@ -111,6 +111,7 @@ fun UserAuthScreen() {
AppStore.apply {
token = authResp.token
this.rememberMe = rememberMe
isGuest = false // 清除游客状态
saveData()
}
AppState.initWithAccount(scope, context)
@@ -163,6 +164,7 @@ fun UserAuthScreen() {
AppStore.apply {
token = authResp.token
this.rememberMe = rememberMe
isGuest = false // 清除游客状态
saveData()
}
navController.navigate(NavigationRoute.Index.route) {

View File

@@ -91,6 +91,8 @@ import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import com.aiosman.ravenow.AppState
import com.aiosman.ravenow.ConstVars
import com.aiosman.ravenow.GuestLoginCheckOut
import com.aiosman.ravenow.GuestLoginCheckOutScene
import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R
@@ -194,27 +196,45 @@ fun PostScreen(
},
isSelf = AppState.UserId?.toLong() == contextComment?.author,
onLikeClick = {
scope.launch {
commentModalState.hide()
showCommentMenu = false
}
contextComment?.let {
viewModel.viewModelScope.launch {
if (it.liked) {
viewModel.unlikeComment(it.id)
} else {
viewModel.likeComment(it.id)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
scope.launch {
commentModalState.hide()
showCommentMenu = false
}
navController.navigate(NavigationRoute.Login.route)
} else {
scope.launch {
commentModalState.hide()
showCommentMenu = false
}
contextComment?.let {
viewModel.viewModelScope.launch {
if (it.liked) {
viewModel.unlikeComment(it.id)
} else {
viewModel.likeComment(it.id)
}
}
}
}
},
onReplyClick = {
scope.launch {
commentModalState.hide()
showCommentMenu = false
replyComment = contextComment
showCommentModal = true
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.COMMENT_MOMENT)) {
scope.launch {
commentModalState.hide()
showCommentMenu = false
}
navController.navigate(NavigationRoute.Login.route)
} else {
scope.launch {
commentModalState.hide()
showCommentMenu = false
replyComment = contextComment
showCommentModal = true
}
}
}
)
@@ -293,24 +313,39 @@ fun PostScreen(
if (!viewModel.isError) {
PostBottomBar(
onLikeClick = {
scope.launch {
if (viewModel.moment?.liked == true) {
viewModel.dislikeMoment()
} else {
viewModel.likeMoment()
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
scope.launch {
if (viewModel.moment?.liked == true) {
viewModel.dislikeMoment()
} else {
viewModel.likeMoment()
}
}
}
},
onCreateCommentClick = {
replyComment = null
showCommentModal = true
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.COMMENT_MOMENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
replyComment = null
showCommentModal = true
}
},
onFavoriteClick = {
scope.launch {
if (viewModel.moment?.isFavorite == true) {
viewModel.unfavoriteMoment()
} else {
viewModel.favoriteMoment()
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
scope.launch {
if (viewModel.moment?.isFavorite == true) {
viewModel.unfavoriteMoment()
} else {
viewModel.favoriteMoment()
}
}
}
},
@@ -356,11 +391,16 @@ fun PostScreen(
userId = viewModel.moment?.authorId,
isFollowing = viewModel.moment?.followStatus == true,
onFollowClick = {
scope.launch {
if (viewModel.moment?.followStatus == true) {
viewModel.unfollowUser()
} else {
viewModel.followUser()
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.FOLLOW_USER)) {
navController.navigate(NavigationRoute.Login.route)
} else {
scope.launch {
if (viewModel.moment?.followStatus == true) {
viewModel.unfollowUser()
} else {
viewModel.followUser()
}
}
}
},
@@ -370,7 +410,12 @@ fun PostScreen(
}
},
onReportClick = {
showReportDialog = true
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.REPORT_CONTENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
showReportDialog = true
}
}
)
LazyColumn(
@@ -430,8 +475,13 @@ fun PostScreen(
contextComment = comment
},
onReply = { parentComment, _, _, _ ->
replyComment = parentComment
showCommentModal = true
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.COMMENT_MOMENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
replyComment = parentComment
showCommentModal = true
}
}
)
}
@@ -454,6 +504,7 @@ fun CommentContent(
onReply: (CommentEntity, Long?, String?, String?) -> Unit
) {
val AppColors = LocalAppTheme.current
val navController = LocalNavController.current
val commentsPagging = viewModel.commentsFlow.collectAsLazyPagingItems()
val addedTopLevelComment = viewModel.addedCommentList.filter {
@@ -468,11 +519,16 @@ fun CommentContent(
CommentItem(
it,
onLike = { comment ->
viewModel.viewModelScope.launch {
if (comment.liked) {
viewModel.unlikeComment(comment.id)
} else {
viewModel.likeComment(comment.id)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
viewModel.viewModelScope.launch {
if (comment.liked) {
viewModel.unlikeComment(comment.id)
} else {
viewModel.likeComment(comment.id)
}
}
}
},
@@ -480,12 +536,17 @@ fun CommentContent(
onLongClick(comment)
},
onReply = { parentComment, _, _, _ ->
onReply(
parentComment,
parentComment.author,
parentComment.name,
parentComment.avatar
)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.COMMENT_MOMENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
onReply(
parentComment,
parentComment.author,
parentComment.name,
parentComment.avatar
)
}
},
onLoadMoreSubComments = {
viewModel.viewModelScope.launch {
@@ -512,11 +573,16 @@ fun CommentContent(
CommentItem(
item,
onLike = { comment ->
viewModel.viewModelScope.launch {
if (comment.liked) {
viewModel.unlikeComment(comment.id)
} else {
viewModel.likeComment(comment.id)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
viewModel.viewModelScope.launch {
if (comment.liked) {
viewModel.unlikeComment(comment.id)
} else {
viewModel.likeComment(comment.id)
}
}
}
},
@@ -560,11 +626,16 @@ fun CommentContent(
CommentItem(
item,
onLike = { comment ->
viewModel.viewModelScope.launch {
if (comment.liked) {
viewModel.unlikeComment(comment.id)
} else {
viewModel.likeComment(comment.id)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
viewModel.viewModelScope.launch {
if (comment.liked) {
viewModel.unlikeComment(comment.id)
} else {
viewModel.likeComment(comment.id)
}
}
}
},
@@ -572,12 +643,17 @@ fun CommentContent(
onLongClick(comment)
},
onReply = { parentComment, _, _, _ ->
onReply(
parentComment,
parentComment.author,
parentComment.name,
parentComment.avatar
)
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.COMMENT_MOMENT)) {
navController.navigate(NavigationRoute.Login.route)
} else {
onReply(
parentComment,
parentComment.author,
parentComment.name,
parentComment.avatar
)
}
},
onLoadMoreSubComments = {
viewModel.viewModelScope.launch {