diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/CreateBottomSheet.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/CreateBottomSheet.kt
new file mode 100644
index 0000000..08e640a
--- /dev/null
+++ b/app/src/main/java/com/aiosman/ravenow/ui/index/CreateBottomSheet.kt
@@ -0,0 +1,150 @@
+package com.aiosman.ravenow.ui.index
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+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.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.BottomSheetDefaults
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.ModalBottomSheet
+import androidx.compose.material3.SheetState
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.compose.ui.res.stringResource
+import com.aiosman.ravenow.LocalAppTheme
+import com.aiosman.ravenow.R
+import com.aiosman.ravenow.ui.modifiers.noRippleClickable
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun CreateBottomSheet(
+ sheetState: SheetState,
+ onDismiss: () -> Unit,
+ onAiClick: () -> Unit,
+ onGroupChatClick: () -> Unit,
+ onMomentClick: () -> Unit
+) {
+ val appColors = LocalAppTheme.current
+
+ ModalBottomSheet(
+ onDismissRequest = onDismiss,
+ sheetState = sheetState,
+ windowInsets = BottomSheetDefaults.windowInsets,
+ containerColor = appColors.background,
+ dragHandle = null,
+ shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp)
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 24.dp, bottom = 24.dp),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ // 标题
+ Text(
+ text = stringResource(R.string.create_title),
+ fontSize = 18.sp,
+ fontWeight = FontWeight.Bold,
+ color = appColors.text,
+ modifier = Modifier.padding(bottom = 32.dp)
+ )
+
+ // 三个创建选项
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceEvenly
+ ) {
+ // 群聊选项
+ CreateOption(
+ icon = R.drawable.ic_create_group_chat,
+ label = stringResource(R.string.create_group_chat_option),
+ onClick = onGroupChatClick
+ )
+ // 动态选项
+ CreateOption(
+ icon = R.drawable.ic_create_monent,
+ label = stringResource(R.string.create_moment),
+ onClick = onMomentClick
+ )
+ // AI选项
+ CreateOption(
+ icon = R.drawable.ic_create_ai,
+ label = stringResource(R.string.create_ai),
+ onClick = onAiClick
+ )
+
+
+
+
+ }
+
+ Spacer(modifier = Modifier.height(40.dp))
+
+ // 关闭按钮
+ Box(
+ modifier = Modifier
+ .size(32.dp)
+ .clip(CircleShape)
+ .noRippleClickable { onDismiss() },
+ contentAlignment = Alignment.Center
+ ) {
+ Image(
+ painter = painterResource(R.drawable.ic_create_close),
+ contentDescription = stringResource(R.string.create_close),
+ modifier = Modifier.size(32.dp)
+ )
+ }
+
+ Spacer(modifier = Modifier.height(16.dp))
+ }
+ }
+}
+
+@Composable
+private fun CreateOption(
+ icon: Int,
+ label: String,
+ onClick: () -> Unit
+) {
+ val appColors = LocalAppTheme.current
+
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = Modifier.noRippleClickable { onClick() }
+ ) {
+ // 直接使用图标,不要背景
+ Image(
+ painter = painterResource(icon),
+ contentDescription = label,
+ modifier = Modifier.size(72.dp)
+ )
+
+ Spacer(modifier = Modifier.height(12.dp))
+
+ // 文字标签
+ Text(
+ text = label,
+ fontSize = 14.sp,
+ fontWeight = FontWeight.Medium,
+ color = appColors.text
+ )
+ }
+}
diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt
index 492ca51..aa67042 100644
--- a/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt
+++ b/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt
@@ -25,6 +25,7 @@ import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.DrawerValue
+import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.NavigationBar
@@ -34,6 +35,7 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Switch
import androidx.compose.material3.SwitchDefaults
import androidx.compose.material3.Text
+import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.material3.rememberDrawerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
@@ -78,9 +80,10 @@ import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.aiosman.ravenow.ui.post.NewPostViewModel
import com.aiosman.ravenow.utils.ResourceCleanupManager
import com.google.accompanist.systemuicontroller.rememberSystemUiController
+import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
-@OptIn(ExperimentalFoundationApi::class)
+@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
@Composable
fun IndexScreen() {
val AppColors = LocalAppTheme.current
@@ -101,6 +104,7 @@ fun IndexScreen() {
val pagerState = rememberPagerState(pageCount = { item.size })
val coroutineScope = rememberCoroutineScope()
val drawerState = rememberDrawerState(DrawerValue.Closed)
+ val bottomSheetState = rememberModalBottomSheetState()
val context = LocalContext.current
// 注意:不要在离开 Index 路由时全量清理资源,以免返回后列表被重置
@@ -292,8 +296,8 @@ fun IndexScreen() {
navController.navigate(NavigationRoute.Login.route)
return@noRippleClickable
}
- NewPostViewModel.asNewPost()
- navController.navigate(NavigationRoute.NewPost.route)
+ // 显示创建底部弹窗
+ model.showCreateBottomSheet = true
return@noRippleClickable
}
@@ -389,6 +393,56 @@ fun IndexScreen() {
}
}
}
+
+ // 创建底部弹窗
+ if (model.showCreateBottomSheet) {
+ CreateBottomSheet(
+ sheetState = bottomSheetState,
+ onDismiss = {
+ // 使用协程来优雅地关闭弹窗
+ coroutineScope.launch {
+ bottomSheetState.hide()
+ model.showCreateBottomSheet = false
+ }
+ },
+ onAiClick = {
+ // 使用协程来优雅地关闭弹窗并导航
+ coroutineScope.launch {
+ bottomSheetState.hide() // 触发关闭动画
+ model.showCreateBottomSheet = false
+ // 检查游客模式,如果是游客则跳转登录
+ if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CREATE_AGENT)) {
+ navController.navigate(NavigationRoute.Login.route)
+ } else {
+ navController.navigate(NavigationRoute.AddAgent.route)
+ }
+ }
+ },
+ onGroupChatClick = {
+ // 使用协程来优雅地关闭弹窗并导航
+ coroutineScope.launch {
+ bottomSheetState.hide() // 触发关闭动画
+ model.showCreateBottomSheet = false
+ // 检查游客模式,如果是游客则跳转登录
+ if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.JOIN_GROUP_CHAT)) {
+ navController.navigate(NavigationRoute.Login.route)
+ } else {
+ navController.navigate(NavigationRoute.CreateGroupChat.route)
+ }
+ }
+ },
+ onMomentClick = {
+ // 使用协程来优雅地关闭弹窗并导航
+ coroutineScope.launch {
+ bottomSheetState.hide() // 触发关闭动画
+ model.showCreateBottomSheet = false
+ // 导航到动态创建页面
+ NewPostViewModel.asNewPost()
+ navController.navigate(NavigationRoute.NewPost.route)
+ }
+ }
+ )
+ }
}
}
diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/IndexViewModel.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/IndexViewModel.kt
index 78cf73e..cc8e5fc 100644
--- a/app/src/main/java/com/aiosman/ravenow/ui/index/IndexViewModel.kt
+++ b/app/src/main/java/com/aiosman/ravenow/ui/index/IndexViewModel.kt
@@ -9,9 +9,12 @@ object IndexViewModel:ViewModel() {
var tabIndex by mutableStateOf(0)
var openDrawer by mutableStateOf(false)
+
+ var showCreateBottomSheet by mutableStateOf(false)
fun ResetModel(){
tabIndex = 0
+ showCreateBottomSheet = false
}
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_create_ai.xml b/app/src/main/res/drawable/ic_create_ai.xml
new file mode 100644
index 0000000..2b53d35
--- /dev/null
+++ b/app/src/main/res/drawable/ic_create_ai.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_create_close.xml b/app/src/main/res/drawable/ic_create_close.xml
new file mode 100644
index 0000000..ba97b4d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_create_close.xml
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_create_group_chat.xml b/app/src/main/res/drawable/ic_create_group_chat.xml
new file mode 100644
index 0000000..d872100
--- /dev/null
+++ b/app/src/main/res/drawable/ic_create_group_chat.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_create_monent.xml b/app/src/main/res/drawable/ic_create_monent.xml
new file mode 100644
index 0000000..7c4fea7
--- /dev/null
+++ b/app/src/main/res/drawable/ic_create_monent.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
new file mode 100644
index 0000000..4bb424f
--- /dev/null
+++ b/app/src/main/res/values-ja/strings.xml
@@ -0,0 +1,9 @@
+
+
+
+ 作成
+ AI
+ グループチャット
+ モーメント
+ 閉じる
+
diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml
index 4a5ab7e..169da43 100644
--- a/app/src/main/res/values-zh/strings.xml
+++ b/app/src/main/res/values-zh/strings.xml
@@ -190,5 +190,12 @@
创建中...
发现
密码不能超过 %1$d 个字符
+
+
+ 创建
+ AI
+ 群聊
+ 动态
+ 关闭
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 4938d21..dae2fb1 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -186,5 +186,12 @@
创建中...
发现
Password cannot exceed %1$d characters
+
+
+ Create
+ AI
+ Group Chat
+ Moment
+ Close
\ No newline at end of file