v0.2.4: One UI 9 & Material 3 Expressive UI/UX Redesign
This commit is contained in:
@@ -5,30 +5,39 @@ import android.content.pm.PackageManager
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
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.layout.*
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
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.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.snapshotFlow
|
|
||||||
import androidx.compose.ui.Modifier
|
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.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.core.content.ContextCompat
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
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.PermissionDialog
|
||||||
|
import com.hotdeal.alarm.presentation.components.elasticPressClickable
|
||||||
import com.hotdeal.alarm.presentation.deallist.DealListScreen
|
import com.hotdeal.alarm.presentation.deallist.DealListScreen
|
||||||
import com.hotdeal.alarm.presentation.settings.SettingsScreen
|
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
|
@Composable
|
||||||
fun MainScreen(
|
fun MainScreen(viewModel: MainViewModel) {
|
||||||
viewModel: MainViewModel,
|
|
||||||
navController: NavHostController = rememberNavController()
|
|
||||||
) {
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
@@ -53,37 +62,92 @@ fun MainScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val pagerState = rememberPagerState(
|
val pagerState = rememberPagerState(initialPage = 0, pageCount = { 2 })
|
||||||
initialPage = 0,
|
|
||||||
pageCount = { 2 }
|
|
||||||
)
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
var currentPage by remember { mutableStateOf(0) }
|
|
||||||
|
|
||||||
LaunchedEffect(pagerState) {
|
Scaffold(
|
||||||
snapshotFlow { pagerState.currentPage }.collect { page ->
|
bottomBar = {
|
||||||
currentPage = page
|
// 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)
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Column(
|
},
|
||||||
modifier = Modifier.fillMaxSize()
|
contentWindowInsets = WindowInsets(0, 0, 0, 0)
|
||||||
|
) { paddingValues ->
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(paddingValues)
|
||||||
) {
|
) {
|
||||||
HorizontalPager(
|
HorizontalPager(
|
||||||
state = pagerState,
|
state = pagerState,
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
beyondBoundsPageCount = 1
|
||||||
) { page ->
|
) { page ->
|
||||||
when (page) {
|
when (page) {
|
||||||
0 -> {
|
0 -> DealListScreen(
|
||||||
DealListScreen(
|
|
||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
onNavigateToSettings = {
|
onNavigateToSettings = {
|
||||||
coroutineScope.launch { pagerState.animateScrollToPage(1) }
|
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")
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user