pager in dashboard

This commit is contained in:
moon 2026-06-10 22:12:52 +06:30 committed by kizzy
parent b7c04719c7
commit 5283bae462

View File

@ -6,15 +6,59 @@ import androidx.compose.animation.core.tween
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
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.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.* import androidx.compose.material.icons.filled.AccountBalanceWallet
import androidx.compose.material3.* import androidx.compose.material.icons.filled.BarChart
import androidx.compose.runtime.* 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
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalDrawerSheet
import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.NavigationDrawerItem
import androidx.compose.material3.NavigationDrawerItemDefaults
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.VerticalDivider
import androidx.compose.material3.rememberDrawerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -24,6 +68,7 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
@ -36,7 +81,6 @@ import com.mob.utsmyanmar.ui.preview.P3Preview
import com.mob.utsmyanmar.ui.theme.Color import com.mob.utsmyanmar.ui.theme.Color
import com.utsmyanmar.paylibs.sign_on.EchoTestProcess import com.utsmyanmar.paylibs.sign_on.EchoTestProcess
import com.utsmyanmar.paylibs.sign_on.SignOnListener import com.utsmyanmar.paylibs.sign_on.SignOnListener
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -44,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()
@ -217,46 +261,96 @@ fun DashboardScreen2(
} }
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
Text(
text = "Connection Settings",
fontWeight = FontWeight.Medium,
modifier = Modifier.padding(horizontal = 16.dp)
)
Item(
title = "Echo Test", subTitle = "Test Connection Status",
onClick = {
scope.launch { drawerState.close() }
openHostActionDialog("Echo Test")
},
leadingIcon = {
Icon(
painterResource(R.drawable.ic_up_down_arrow),
contentDescription = "icon",
tint = Color.LegacyRed
)
},
trailingIcon = {},
)
Item(
title = "Log-On", subTitle = "Log on to System",
onClick = {
scope.launch { drawerState.close() }
openHostActionDialog("Log-On")
},
leadingIcon = {
Icon(
painterResource(R.drawable.ic_lock),
contentDescription = "icon",
tint = Color.LegacyRed
)
},
trailingIcon = {},
)
Item(
title = "Log-Off", subTitle = "Log off from System",
onClick = {
scope.launch { drawerState.close() }
openHostActionDialog("Log-Off")
},
leadingIcon = {
Icon(
painterResource(R.drawable.ic_cancel_circle),
contentDescription = "icon",
tint = Color.LegacyRed
)
},
trailingIcon = {},
)
DrawerItem("Log-On", Icons.Default.Dashboard) {
scope.launch { drawerState.close() }
openHostActionDialog("Log-On")
}
DrawerItem("Echo Test", Icons.Default.Sync) {
scope.launch { drawerState.close() }
openHostActionDialog("Echo Test")
}
DrawerItem("Log-Off", Icons.Default.Dashboard) {
scope.launch { drawerState.close() }
openHostActionDialog("Log-Off")
}
Text( Text(
text = "System Management", text = "System Management",
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
modifier = Modifier.padding(horizontal = 16.dp) modifier = Modifier.padding(horizontal = 16.dp)
) )
var switchChecked by remember { mutableStateOf(SystemParamsOperation.getInstance().isReversalOn) } Item(
DrawerItem( title = "Functions", subTitle = "System Function Settings",
title = "Reversal On/Off", onClick = {
icon = Icons.Default.Sync, scope.launch { drawerState.close() }
showSwitch = true, onNavigateFunctions()
isChecked = switchChecked,
onCheckedChange = { isChecked ->
switchChecked = isChecked
SystemParamsOperation.getInstance().setReversalFlag(isChecked)
}, },
onClick = {} leadingIcon = {
Icon(
painterResource(R.drawable.ic_four_boxes),
contentDescription = "icon",
tint = Color.LegacyRed,
modifier = Modifier.size(16.dp)
)
},
trailingIcon = {},
) )
DrawerItem("Function", Icons.Default.Dashboard) { Item(
scope.launch { drawerState.close() } title = "Version", subTitle = "View App Version Info",
onNavigateFunctions() onClick = {
} scope.launch { drawerState.close() }
DrawerItem("Version", Icons.Default.Dashboard) { onNavigateVersion()
scope.launch { drawerState.close() } },
onNavigateVersion() leadingIcon = {
} Icon(
painterResource(R.drawable.ic_version),
contentDescription = "icon",
tint = Color.LegacyRed
)
},
trailingIcon = {},
)
} }
}) { }) {
Scaffold( Scaffold(
@ -294,11 +388,14 @@ fun DashboardScreen2(
.weight(1.5f) .weight(1.5f)
.fillMaxWidth(), .fillMaxWidth(),
) { ) {
MenuGrid( MenuPager(
onNavigateAmount = onNavigateAmount, items = buildMenuItems(
onNavigateSignOn = onNavigateSignOn, onNavigateAmount = onNavigateAmount,
onNavigateSeeMore = onNavigateSeeMore, onNavigateSignOn = onNavigateSignOn,
onNavigateSettlement = onNavigateSettlement onNavigateSettlement = onNavigateSettlement,
onNavigateAction = onNavigateAction
),
modifier = Modifier.fillMaxSize()
) )
} }
} }
@ -308,44 +405,21 @@ fun DashboardScreen2(
@Composable @Composable
private fun DrawerItem( private fun DrawerItem(
title: String, title: String, icon: ImageVector, onClick: () -> Unit
icon: ImageVector,
showSwitch: Boolean = false, // New: Flag to enable switch mode
isChecked: Boolean = false, // New: Switch state
onCheckedChange: (Boolean) -> Unit = {}, // New: Switch callback
onClick: () -> Unit
) { ) {
NavigationDrawerItem( NavigationDrawerItem(
label = { label = {
Text( Text(
text = title, text = title, fontWeight = FontWeight.Medium
fontWeight = FontWeight.Medium
) )
}, },
selected = false, selected = false,
// If it's a switch item, clicking the whole row toggles the switch instead of navigating onClick = onClick,
onClick = {
if (showSwitch) {
onCheckedChange(!isChecked)
} else {
onClick()
}
},
icon = { icon = {
Icon( Icon(
imageVector = icon, imageVector = icon, contentDescription = title
contentDescription = title
) )
}, },
badge = {
if (showSwitch) {
Switch(
checked = isChecked,
onCheckedChange = onCheckedChange
)
}
},
modifier = Modifier.padding(horizontal = 12.dp, vertical = 2.dp), modifier = Modifier.padding(horizontal = 12.dp, vertical = 2.dp),
colors = NavigationDrawerItemDefaults.colors( colors = NavigationDrawerItemDefaults.colors(
unselectedContainerColor = androidx.compose.ui.graphics.Color.Transparent, unselectedContainerColor = androidx.compose.ui.graphics.Color.Transparent,
@ -498,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))
Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) { items.chunked(3).forEach { rowItems ->
MenuCard(title = "Sale", icon = { Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
Icon( rowItems.forEach { item ->
painterResource(R.drawable.ic_terminal), MenuCard(
contentDescription = "icon", title = item.title,
modifier = Modifier.size(40.dp), icon = item.iconContent,
tint = Color.LegacyRed modifier = Modifier.weight(1f),
) 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))
}
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
) )
}, modifier = Modifier.weight(1f), onClick = onNavigateSignOn }
) repeat(3 - rowItems.size) {
MenuCard( Spacer(modifier = Modifier.weight(1f))
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
)
} }
} }
} }
@ -636,3 +728,71 @@ fun PreviewDashboardScreen2() {
fun PreviewDashboardScreen3() { fun PreviewDashboardScreen3() {
DashboardScreen2() DashboardScreen2()
} }
@Preview
@Composable
fun PreviewItem() {
Item(
onClick = {},
title = "title",
subTitle = "sub-title"
)
}
@Composable
fun Item(
onClick: () -> Unit,
title: String,
subTitle: String,
leadingIcon: (@Composable () -> Unit)? = null,
trailingIcon: (@Composable () -> Unit)? = null,
) {
Button(
onClick = onClick,
colors = ButtonDefaults.buttonColors(
containerColor = Color.White,
contentColor = Color.Black
),
modifier = Modifier.fillMaxWidth()
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.fillMaxWidth()
) {
// Square icon background
leadingIcon?.let {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(40.dp)
.clip(RoundedCornerShape(16.dp)) // change to RectangleShape for sharp corners
.background(Color.LegacyRed.copy(alpha = 0.1f))
.padding(8.dp)
) {
it()
}
}
Spacer(modifier = Modifier.width(12.dp))
Column(
modifier = Modifier
.weight(1f)
.padding(horizontal = 8.dp)
) {
Text(text = title)
Text(
text = subTitle,
style = MaterialTheme.typography.bodySmall,
color = Color.Gray
)
}
trailingIcon?.invoke()
}
}
}