diff --git a/app/src/main/java/com/mob/utsmyanmar/AGENTS.md b/app/src/main/java/com/mob/utsmyanmar/AGENTS.md index 898970e..537e01e 100644 --- a/app/src/main/java/com/mob/utsmyanmar/AGENTS.md +++ b/app/src/main/java/com/mob/utsmyanmar/AGENTS.md @@ -1,6 +1,8 @@ ## Working agreements - use Scaffold and AppBar() in every main Screen +- use MVVM design pattern +- separate UiState and ViewModel for screen for better performance and smooth ### Re-usable Screens - PasswordInput.kt diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/dashboard/DashboardScreen2.kt b/app/src/main/java/com/mob/utsmyanmar/ui/dashboard/DashboardScreen2.kt index e071274..5ae5da1 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/dashboard/DashboardScreen2.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/dashboard/DashboardScreen2.kt @@ -22,11 +22,18 @@ import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.AccountBalanceWallet import androidx.compose.material.icons.filled.BarChart import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.ChevronRight +import androidx.compose.material.icons.filled.CreditCard +import androidx.compose.material.icons.filled.Lock +import androidx.compose.material.icons.filled.LockOpen import androidx.compose.material.icons.filled.Menu +import androidx.compose.material.icons.filled.Replay +import androidx.compose.material.icons.filled.SwapHoriz import androidx.compose.material.icons.filled.Sync +import androidx.compose.material.icons.filled.Undo import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults @@ -81,10 +88,10 @@ import kotlinx.coroutines.launch fun DashboardScreen2( onNavigateAmount: (String) -> Unit = {}, onNavigateSignOn: () -> Unit = {}, - onNavigateSeeMore: () -> Unit = {}, onNavigateSettlement: () -> Unit = {}, onNavigateVersion: () -> Unit = {}, onNavigateFunctions: () -> Unit = {}, + onNavigateAction: (String) -> Unit = {}, deviceInfoViewModel: DeviceInfoViewModel = viewModel() ) { val deviceInfo by deviceInfoViewModel.uiState.collectAsState() @@ -381,11 +388,14 @@ fun DashboardScreen2( .weight(1.5f) .fillMaxWidth(), ) { - MenuGrid( - onNavigateAmount = onNavigateAmount, - onNavigateSignOn = onNavigateSignOn, - onNavigateSeeMore = onNavigateSeeMore, - onNavigateSettlement = onNavigateSettlement + MenuPager( + items = buildMenuItems( + onNavigateAmount = onNavigateAmount, + onNavigateSignOn = onNavigateSignOn, + onNavigateSettlement = onNavigateSettlement, + onNavigateAction = onNavigateAction + ), + modifier = Modifier.fillMaxSize() ) } } @@ -562,75 +572,93 @@ private fun IconCircle( } } +private class DashboardMenuItem( + val title: String, + val iconContent: @Composable () -> Unit, + val onClick: () -> Unit +) + @Composable -private fun MenuGrid( +private fun buildMenuItems( onNavigateAmount: (String) -> Unit, onNavigateSignOn: () -> Unit, - onNavigateSeeMore: () -> Unit, - onNavigateSettlement: () -> Unit + onNavigateSettlement: () -> Unit, + onNavigateAction: (String) -> Unit +): List = listOf( + DashboardMenuItem("Sale", { Icon(painterResource(R.drawable.ic_terminal), contentDescription = null, modifier = Modifier.size(40.dp), tint = Color.LegacyRed) }) { onNavigateAmount("Sale") }, + DashboardMenuItem("MMQR", { Image(painter = painterResource(R.drawable.ic_mmqr_logo), contentDescription = null, modifier = Modifier.height(48.dp)) }) { }, + DashboardMenuItem("History", { Icon(painterResource(R.drawable.ic_history), contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { }, + DashboardMenuItem("Sign On", { Icon(painterResource(R.drawable.ic_sign_on), contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateSignOn() }, + DashboardMenuItem("Settlement", { Icon(painterResource(R.drawable.ic_settlement), contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateSettlement() }, + DashboardMenuItem("Void", { Icon(Icons.Default.Undo, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Void") }, + DashboardMenuItem("Refund", { Icon(Icons.Default.Replay, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Refund") }, + DashboardMenuItem("Pre-Auth", { Icon(Icons.Default.Lock, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Pre-Auth") }, + DashboardMenuItem("Pre-Auth Void", { Icon(Icons.Default.LockOpen, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Pre-Auth Void") }, + DashboardMenuItem("Pre-Auth Complete", { Icon(Icons.Default.CreditCard, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Pre-Auth Complete") }, + DashboardMenuItem("Pre-Auth Complete Void", { Icon(Icons.Default.SwapHoriz, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Pre-Auth Complete Void") }, + DashboardMenuItem("Cash Out", { Icon(Icons.Default.AccountBalanceWallet, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Cash Out") }, +) + +@Composable +private fun MenuPager( + items: List, + modifier: Modifier = Modifier ) { + val pages = items.chunked(6) + val pagerState = rememberPagerState(pageCount = { pages.size }) + + Column(modifier = modifier) { + HorizontalPager( + state = pagerState, + modifier = Modifier.weight(1f) + ) { pageIndex -> + MenuPage(items = pages[pageIndex]) + } + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + repeat(pages.size) { index -> + val selected = pagerState.currentPage == index + Box( + modifier = Modifier + .padding(horizontal = 4.dp) + .size(if (selected) 8.dp else 6.dp) + .background( + color = if (selected) Color.LegacyRed else Color.Gray.copy(alpha = 0.4f), + shape = CircleShape + ) + ) + } + } + } +} + +@Composable +private fun MenuPage(items: List) { Column( verticalArrangement = Arrangement.spacedBy(10.dp), modifier = Modifier.padding(horizontal = 16.dp) ) { Spacer(Modifier.height(8.dp)) - Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) { - MenuCard(title = "Sale", icon = { - Icon( - painterResource(R.drawable.ic_terminal), - contentDescription = "icon", - modifier = Modifier.size(40.dp), - tint = Color.LegacyRed - ) - }, modifier = Modifier.weight(1f), onClick = { onNavigateAmount("Sale") }) - MenuCard(title = "MMQR", icon = { - Image( - painter = painterResource(R.drawable.ic_mmqr_logo), - contentDescription = "mmqr image", - modifier = Modifier.height(48.dp) - ) - }, modifier = Modifier.weight(1f)) - MenuCard("History", icon = { - Icon( - painterResource(R.drawable.ic_history), - contentDescription = "icon", - modifier = Modifier.size(32.dp), - tint = Color.LegacyRed - ) - }, modifier = Modifier.weight(1f)) - } - - Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) { - MenuCard( - title = "Sign On", icon = { - Icon( - painterResource(R.drawable.ic_sign_on), - contentDescription = "icon", - modifier = Modifier.size(32.dp), - tint = Color.LegacyRed + items.chunked(3).forEach { rowItems -> + Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) { + rowItems.forEach { item -> + MenuCard( + title = item.title, + icon = item.iconContent, + modifier = Modifier.weight(1f), + onClick = item.onClick ) - }, modifier = Modifier.weight(1f), onClick = onNavigateSignOn - ) - MenuCard( - title = "Settlement", icon = { - Icon( - painterResource(R.drawable.ic_settlement), - contentDescription = "icon", - modifier = Modifier.size(32.dp), - tint = Color.LegacyRed - ) - }, modifier = Modifier.weight(1f), onClick = onNavigateSettlement - ) - MenuCard( - title = "See More", icon = { - Icon( - painterResource(R.drawable.ic_see_more), - contentDescription = "icon", - modifier = Modifier.size(32.dp), - tint = Color.LegacyRed - ) - }, modifier = Modifier.weight(1f), onClick = onNavigateSeeMore - ) + } + repeat(3 - rowItems.size) { + Spacer(modifier = Modifier.weight(1f)) + } + } } } } diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt index a88953d..8e0a96b 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt @@ -16,7 +16,6 @@ import com.mob.utsmyanmar.model.ProcessCode import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingScreen import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingViewModel import com.mob.utsmyanmar.ui.dashboard.DashboardScreen2 -import com.mob.utsmyanmar.ui.dashboard.SeeMoreScreen import com.mob.utsmyanmar.ui.device_info.DeviceInfoViewModel import com.mob.utsmyanmar.ui.functions.FunctionsScreen import com.mob.utsmyanmar.ui.input_amount.AmountRoute @@ -92,11 +91,6 @@ fun AppNavGraph( launchSingleTop = true } }, - onNavigateSeeMore = { - navController.navigate(Routes.SeeMore.route) { - launchSingleTop = true - } - }, onNavigateSettlement = { navController.navigate(Routes.Settlement.route) { launchSingleTop = true @@ -109,27 +103,16 @@ fun AppNavGraph( navController.navigate(Routes.Password.createRoute(Routes.Functions.route, PasswordType.SETTING)) { launchSingleTop = true } - } - ) - } - - composable(Routes.SeeMore.route) { - SeeMoreScreen( - onBack = { navController.popBackStack() }, - onNavigateAmount = { action -> - if (action == "Void") { - navController.navigate(Routes.VoidTrace.route) { - launchSingleTop = true - } - } else { - navController.navigate(Routes.Amount.createRoute(action)) { - launchSingleTop = true - } + }, + onNavigateAction = { action -> + when (action) { + "Void" -> navController.navigate(Routes.VoidTrace.route) { launchSingleTop = true } + else -> navController.navigate(Routes.Amount.createRoute(action)) { launchSingleTop = true } } } ) } - + composable(Routes.Version.route){ val deviceInfoViewModel: DeviceInfoViewModel = hiltViewModel(); VersionScreen(