From 6e6747d1bb2b4661b1a9d0062192151cdd6aca7c Mon Sep 17 00:00:00 2001 From: sanjeok77 <1+sanjeok77@noreply.localhost> Date: Thu, 20 Aug 2026 23:29:01 +0000 Subject: [PATCH] v0.2.4: One UI 9 & Material 3 Expressive UI/UX Redesign --- .../alarm/presentation/main/MainScreen.kt | 135 +++++++++++++----- 1 file changed, 97 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/com/hotdeal/alarm/presentation/main/MainScreen.kt b/app/src/main/java/com/hotdeal/alarm/presentation/main/MainScreen.kt index adc0d2d..2286c5d 100644 --- a/app/src/main/java/com/hotdeal/alarm/presentation/main/MainScreen.kt +++ b/app/src/main/java/com/hotdeal/alarm/presentation/main/MainScreen.kt @@ -5,30 +5,39 @@ import android.content.pm.PackageManager import android.os.Build import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.animation.* +import androidx.compose.animation.core.* +import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.* +import androidx.compose.material.icons.outlined.* import androidx.compose.material3.* import androidx.compose.runtime.* -import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import androidx.core.content.ContextCompat import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation.NavHostController -import androidx.navigation.compose.rememberNavController -import kotlinx.coroutines.launch import com.hotdeal.alarm.presentation.components.PermissionDialog +import com.hotdeal.alarm.presentation.components.elasticPressClickable import com.hotdeal.alarm.presentation.deallist.DealListScreen import com.hotdeal.alarm.presentation.settings.SettingsScreen +import com.hotdeal.alarm.ui.theme.CornerRadius +import kotlinx.coroutines.launch -@OptIn(ExperimentalFoundationApi::class) +/** + * One UI 9 Fluid Navigation Framework + * 한 손 조작성을 극대화한 하단 캡슐 내비게이션 바 및 화면 전환 + */ @Composable -fun MainScreen( - viewModel: MainViewModel, - navController: NavHostController = rememberNavController() -) { +fun MainScreen(viewModel: MainViewModel) { val context = LocalContext.current val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -53,37 +62,92 @@ fun MainScreen( } } - val pagerState = rememberPagerState( - initialPage = 0, - pageCount = { 2 } - ) + val pagerState = rememberPagerState(initialPage = 0, pageCount = { 2 }) val coroutineScope = rememberCoroutineScope() - var currentPage by remember { mutableStateOf(0) } - LaunchedEffect(pagerState) { - snapshotFlow { pagerState.currentPage }.collect { page -> - currentPage = page - } - } + Scaffold( + bottomBar = { + // One UI 9 Fluid Bottom Navigation Bar + Surface( + modifier = Modifier + .fillMaxWidth() + .navigationBarsPadding(), + color = MaterialTheme.colorScheme.surface, + tonalElevation = 3.dp, + border = androidx.compose.foundation.BorderStroke( + 0.8.dp, + MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.25f) + ) + ) { + NavigationBar( + containerColor = Color.Transparent, + tonalElevation = 0.dp, + modifier = Modifier.height(64.dp) + ) { + val navItems = listOf( + Triple(0, "핫딜 피드", Icons.Filled.LocalFireDepartment to Icons.Outlined.LocalFireDepartment), + Triple(1, "설정 & 관리", Icons.Filled.Tune to Icons.Outlined.Tune) + ) - Column( - modifier = Modifier.fillMaxSize() - ) { - HorizontalPager( - state = pagerState, - modifier = Modifier.weight(1f) - ) { page -> - when (page) { - 0 -> { - DealListScreen( + navItems.forEach { (pageIndex, label, icons) -> + val isSelected = pagerState.currentPage == pageIndex + val (selectedIcon, unselectedIcon) = icons + + NavigationBarItem( + selected = isSelected, + onClick = { + coroutineScope.launch { + pagerState.animateScrollToPage(pageIndex) + } + }, + icon = { + Icon( + imageVector = if (isSelected) selectedIcon else unselectedIcon, + contentDescription = label, + modifier = Modifier.size(24.dp) + ) + }, + label = { + Text( + text = label, + style = MaterialTheme.typography.labelSmall.copy( + fontWeight = if (isSelected) FontWeight.Bold else FontWeight.Medium, + fontSize = 11.sp + ) + ) + }, + colors = NavigationBarItemDefaults.colors( + selectedIconColor = MaterialTheme.colorScheme.primary, + selectedTextColor = MaterialTheme.colorScheme.primary, + unselectedIconColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f), + unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f), + indicatorColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.6f) + ) + ) + } + } + } + }, + contentWindowInsets = WindowInsets(0, 0, 0, 0) + ) { paddingValues -> + Box( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + ) { + HorizontalPager( + state = pagerState, + modifier = Modifier.fillMaxSize(), + beyondBoundsPageCount = 1 + ) { page -> + when (page) { + 0 -> DealListScreen( viewModel = viewModel, onNavigateToSettings = { coroutineScope.launch { pagerState.animateScrollToPage(1) } } ) - } - 1 -> { - SettingsScreen(viewModel = viewModel) + 1 -> SettingsScreen(viewModel = viewModel) } } } @@ -98,8 +162,3 @@ fun MainScreen( ) } } - -sealed class Screen(val route: String) { - object DealList : Screen("deal_list") - object Settings : Screen("settings") -}