v0.2.4: One UI 9 & Material 3 Expressive UI/UX Redesign

This commit is contained in:
2026-08-20 23:29:01 +00:00
parent da4ad8d3a3
commit 6e6747d1bb
@@ -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")
}