pager in dashboard

This commit is contained in:
moon 2026-06-10 22:12:52 +06:30
parent 3a63c65e8f
commit 36b9d83a40
3 changed files with 101 additions and 88 deletions

View File

@ -1,6 +1,8 @@
## Working agreements ## Working agreements
- use Scaffold and AppBar() in every main Screen - 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 ### Re-usable Screens
- PasswordInput.kt - PasswordInput.kt

View File

@ -22,11 +22,18 @@ import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons 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.BarChart
import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.ChevronRight 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.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.Sync
import androidx.compose.material.icons.filled.Undo
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
@ -81,10 +88,10 @@ import kotlinx.coroutines.launch
fun DashboardScreen2( fun DashboardScreen2(
onNavigateAmount: (String) -> Unit = {}, onNavigateAmount: (String) -> Unit = {},
onNavigateSignOn: () -> Unit = {}, onNavigateSignOn: () -> Unit = {},
onNavigateSeeMore: () -> Unit = {},
onNavigateSettlement: () -> Unit = {}, onNavigateSettlement: () -> Unit = {},
onNavigateVersion: () -> Unit = {}, onNavigateVersion: () -> Unit = {},
onNavigateFunctions: () -> Unit = {}, onNavigateFunctions: () -> Unit = {},
onNavigateAction: (String) -> Unit = {},
deviceInfoViewModel: DeviceInfoViewModel = viewModel() deviceInfoViewModel: DeviceInfoViewModel = viewModel()
) { ) {
val deviceInfo by deviceInfoViewModel.uiState.collectAsState() val deviceInfo by deviceInfoViewModel.uiState.collectAsState()
@ -381,11 +388,14 @@ fun DashboardScreen2(
.weight(1.5f) .weight(1.5f)
.fillMaxWidth(), .fillMaxWidth(),
) { ) {
MenuGrid( MenuPager(
items = buildMenuItems(
onNavigateAmount = onNavigateAmount, onNavigateAmount = onNavigateAmount,
onNavigateSignOn = onNavigateSignOn, onNavigateSignOn = onNavigateSignOn,
onNavigateSeeMore = onNavigateSeeMore, onNavigateSettlement = onNavigateSettlement,
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 @Composable
private fun MenuGrid( private fun buildMenuItems(
onNavigateAmount: (String) -> Unit, onNavigateAmount: (String) -> Unit,
onNavigateSignOn: () -> Unit, onNavigateSignOn: () -> Unit,
onNavigateSeeMore: () -> Unit, onNavigateSettlement: () -> Unit,
onNavigateSettlement: () -> Unit onNavigateAction: (String) -> Unit
): List<DashboardMenuItem> = 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<DashboardMenuItem>,
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<DashboardMenuItem>) {
Column( Column(
verticalArrangement = Arrangement.spacedBy(10.dp), verticalArrangement = Arrangement.spacedBy(10.dp),
modifier = Modifier.padding(horizontal = 16.dp) modifier = Modifier.padding(horizontal = 16.dp)
) { ) {
Spacer(Modifier.height(8.dp)) Spacer(Modifier.height(8.dp))
items.chunked(3).forEach { rowItems ->
Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
MenuCard(title = "Sale", icon = { rowItems.forEach { item ->
Icon( MenuCard(
painterResource(R.drawable.ic_terminal), title = item.title,
contentDescription = "icon", icon = item.iconContent,
modifier = Modifier.size(40.dp), modifier = Modifier.weight(1f),
tint = Color.LegacyRed onClick = item.onClick
) )
}, 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))
} }
repeat(3 - rowItems.size) {
Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) { Spacer(modifier = Modifier.weight(1f))
MenuCard( }
title = "Sign On", icon = { }
Icon(
painterResource(R.drawable.ic_sign_on),
contentDescription = "icon",
modifier = Modifier.size(32.dp),
tint = Color.LegacyRed
)
}, 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
)
} }
} }
} }

View File

@ -16,7 +16,6 @@ import com.mob.utsmyanmar.model.ProcessCode
import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingScreen import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingScreen
import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingViewModel import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingViewModel
import com.mob.utsmyanmar.ui.dashboard.DashboardScreen2 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.device_info.DeviceInfoViewModel
import com.mob.utsmyanmar.ui.functions.FunctionsScreen import com.mob.utsmyanmar.ui.functions.FunctionsScreen
import com.mob.utsmyanmar.ui.input_amount.AmountRoute import com.mob.utsmyanmar.ui.input_amount.AmountRoute
@ -92,11 +91,6 @@ fun AppNavGraph(
launchSingleTop = true launchSingleTop = true
} }
}, },
onNavigateSeeMore = {
navController.navigate(Routes.SeeMore.route) {
launchSingleTop = true
}
},
onNavigateSettlement = { onNavigateSettlement = {
navController.navigate(Routes.Settlement.route) { navController.navigate(Routes.Settlement.route) {
launchSingleTop = true launchSingleTop = true
@ -109,22 +103,11 @@ fun AppNavGraph(
navController.navigate(Routes.Password.createRoute(Routes.Functions.route, PasswordType.SETTING)) { navController.navigate(Routes.Password.createRoute(Routes.Functions.route, PasswordType.SETTING)) {
launchSingleTop = true launchSingleTop = true
} }
} },
) onNavigateAction = { action ->
} when (action) {
"Void" -> navController.navigate(Routes.VoidTrace.route) { launchSingleTop = true }
composable(Routes.SeeMore.route) { else -> navController.navigate(Routes.Amount.createRoute(action)) { launchSingleTop = true }
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
}
} }
} }
) )