feat: 复刻小程序四大主页面与底部导航(UI 优先,本地 mock)
This commit is contained in:
@@ -15,9 +15,11 @@ android {
|
||||
dependencies {
|
||||
implementation(project(":core:designsystem"))
|
||||
implementation(project(":core:ui"))
|
||||
implementation(project(":core:model"))
|
||||
implementation(project(":core:data"))
|
||||
|
||||
implementation(project(":feature:auth"))
|
||||
implementation(project(":feature:home"))
|
||||
implementation(project(":feature:checkin"))
|
||||
implementation(project(":feature:plan"))
|
||||
implementation(project(":feature:course"))
|
||||
@@ -25,6 +27,7 @@ dependencies {
|
||||
implementation(project(":feature:feedback"))
|
||||
implementation(project(":feature:profile"))
|
||||
|
||||
implementation(libs.androidx.compose.material.icons.core)
|
||||
implementation(libs.androidx.core.ktx)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||
|
||||
@@ -1,41 +1,126 @@
|
||||
package com.mingyuan.android_client
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
import androidx.compose.material3.NavigationBarItemDefaults
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.navigation.NavGraph.Companion.findStartDestination
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.mingyuan.android_client.feature.auth.AUTH_ROUTE
|
||||
import com.mingyuan.android_client.feature.auth.AuthScreen
|
||||
import androidx.navigation.navArgument
|
||||
import com.mingyuan.android_client.core.designsystem.theme.TabActive
|
||||
import com.mingyuan.android_client.core.designsystem.theme.TabBackground
|
||||
import com.mingyuan.android_client.core.designsystem.theme.TabInactive
|
||||
import com.mingyuan.android_client.feature.checkin.CHECKIN_ROUTE
|
||||
import com.mingyuan.android_client.feature.checkin.CheckinScreen
|
||||
import com.mingyuan.android_client.feature.course.COURSE_ROUTE
|
||||
import com.mingyuan.android_client.feature.course.CourseScreen
|
||||
import com.mingyuan.android_client.feature.feedback.FEEDBACK_ROUTE
|
||||
import com.mingyuan.android_client.feature.feedback.FeedbackScreen
|
||||
import com.mingyuan.android_client.feature.home.HOME_ROUTE
|
||||
import com.mingyuan.android_client.feature.home.HomeScreen
|
||||
import com.mingyuan.android_client.feature.plan.PLAN_ROUTE
|
||||
import com.mingyuan.android_client.feature.plan.PLAN_SUBMIT_ROUTE
|
||||
import com.mingyuan.android_client.feature.plan.PlanScreen
|
||||
import com.mingyuan.android_client.feature.plan.PlanSubmitScreen
|
||||
import com.mingyuan.android_client.feature.plan.planSubmitRoute
|
||||
import com.mingyuan.android_client.feature.profile.PROFILE_ROUTE
|
||||
import com.mingyuan.android_client.feature.profile.ProfileScreen
|
||||
import com.mingyuan.android_client.feature.survey.SURVEY_ROUTE
|
||||
import com.mingyuan.android_client.feature.survey.SurveyScreen
|
||||
|
||||
/**
|
||||
* The single navigation graph for the app. Each feature exposes its own route constant and
|
||||
* screen composable; this host wires them together (see docs/architecture.md).
|
||||
* The single navigation graph for the app. Each feature exposes its own route constant and screen
|
||||
* composable; this host wires them together (see docs/architecture.md).
|
||||
*/
|
||||
@Composable
|
||||
fun AppNavHost() {
|
||||
val navController = rememberNavController()
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = CHECKIN_ROUTE,
|
||||
) {
|
||||
composable(AUTH_ROUTE) { AuthScreen() }
|
||||
composable(CHECKIN_ROUTE) { CheckinScreen() }
|
||||
composable(PLAN_ROUTE) { PlanScreen() }
|
||||
composable(COURSE_ROUTE) { CourseScreen() }
|
||||
composable(SURVEY_ROUTE) { SurveyScreen() }
|
||||
composable(FEEDBACK_ROUTE) { FeedbackScreen() }
|
||||
composable(PROFILE_ROUTE) { ProfileScreen() }
|
||||
val backStackEntry by navController.currentBackStackEntryAsState()
|
||||
val currentRoute = backStackEntry?.destination?.route
|
||||
val topLevelRoutes = TopLevelDestination.entries.map { it.route }.toSet()
|
||||
|
||||
val navigateToTab: (String) -> Unit = { route ->
|
||||
navController.navigate(route) {
|
||||
popUpTo(navController.graph.findStartDestination().id) {
|
||||
saveState = true
|
||||
}
|
||||
launchSingleTop = true
|
||||
restoreState = true
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
containerColor = TabBackground,
|
||||
bottomBar = {
|
||||
if (currentRoute in topLevelRoutes) {
|
||||
MingyuanBottomBar(
|
||||
currentRoute = currentRoute,
|
||||
onNavigate = navigateToTab,
|
||||
)
|
||||
}
|
||||
},
|
||||
) { innerPadding ->
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = HOME_ROUTE,
|
||||
modifier = Modifier.padding(innerPadding),
|
||||
) {
|
||||
composable(HOME_ROUTE) {
|
||||
HomeScreen(
|
||||
onNavigateToCheckin = { navigateToTab(CHECKIN_ROUTE) },
|
||||
onNavigateToPlan = { navigateToTab(PLAN_ROUTE) },
|
||||
)
|
||||
}
|
||||
composable(CHECKIN_ROUTE) { CheckinScreen() }
|
||||
composable(PLAN_ROUTE) {
|
||||
PlanScreen(
|
||||
onNavigateToPlanSubmit = { type, periodKey ->
|
||||
navController.navigate(planSubmitRoute(type, periodKey))
|
||||
},
|
||||
)
|
||||
}
|
||||
composable(
|
||||
route = PLAN_SUBMIT_ROUTE,
|
||||
arguments = listOf(
|
||||
navArgument("planType") { type = NavType.StringType },
|
||||
navArgument("periodKey") {
|
||||
type = NavType.StringType
|
||||
defaultValue = ""
|
||||
},
|
||||
),
|
||||
) {
|
||||
PlanSubmitScreen(onBack = { navController.popBackStack() })
|
||||
}
|
||||
composable(PROFILE_ROUTE) { ProfileScreen() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MingyuanBottomBar(
|
||||
currentRoute: String?,
|
||||
onNavigate: (String) -> Unit,
|
||||
) {
|
||||
NavigationBar(containerColor = TabBackground) {
|
||||
TopLevelDestination.entries.forEach { destination ->
|
||||
NavigationBarItem(
|
||||
selected = currentRoute == destination.route,
|
||||
onClick = { onNavigate(destination.route) },
|
||||
icon = { Icon(destination.icon, contentDescription = destination.label) },
|
||||
label = { Text(destination.label) },
|
||||
colors = NavigationBarItemDefaults.colors(
|
||||
selectedIconColor = TabActive,
|
||||
selectedTextColor = TabActive,
|
||||
unselectedIconColor = TabInactive,
|
||||
unselectedTextColor = TabInactive,
|
||||
indicatorColor = Color.Transparent,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import com.mingyuan.android_client.core.designsystem.theme.MingyuanTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.mingyuan.android_client
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.CheckCircle
|
||||
import androidx.compose.material.icons.filled.DateRange
|
||||
import androidx.compose.material.icons.filled.Home
|
||||
import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import com.mingyuan.android_client.feature.checkin.CHECKIN_ROUTE
|
||||
import com.mingyuan.android_client.feature.home.HOME_ROUTE
|
||||
import com.mingyuan.android_client.feature.plan.PLAN_ROUTE
|
||||
import com.mingyuan.android_client.feature.profile.PROFILE_ROUTE
|
||||
|
||||
/** The four top-level tabs shown in the bottom navigation bar. */
|
||||
enum class TopLevelDestination(
|
||||
val route: String,
|
||||
val label: String,
|
||||
val icon: ImageVector,
|
||||
) {
|
||||
HOME(HOME_ROUTE, "首页", Icons.Filled.Home),
|
||||
CHECKIN(CHECKIN_ROUTE, "打卡", Icons.Filled.CheckCircle),
|
||||
PLAN(PLAN_ROUTE, "计划", Icons.Filled.DateRange),
|
||||
PROFILE(PROFILE_ROUTE, "我的", Icons.Filled.Person),
|
||||
}
|
||||
Reference in New Issue
Block a user