sidebar profile added

This commit is contained in:
moon 2026-05-21 21:27:13 +06:30
parent 57dcd13c34
commit 675e398aaf
4 changed files with 486 additions and 385 deletions

View File

@ -3,70 +3,78 @@ package com.mob.utsmyanmar.ui.dashboard
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
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.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
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.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.Dashboard import androidx.compose.material.icons.filled.Dashboard
import androidx.compose.material.icons.filled.GridView import androidx.compose.material.icons.filled.GridView
import androidx.compose.material.icons.filled.History import androidx.compose.material.icons.filled.History
import androidx.compose.material.icons.filled.Link import androidx.compose.material.icons.filled.Link
import androidx.compose.material.icons.filled.Menu import androidx.compose.material.icons.filled.Menu
import androidx.compose.material.icons.filled.PointOfSale import androidx.compose.material.icons.filled.PointOfSale
import androidx.compose.material.icons.filled.QrCode import androidx.compose.material.icons.filled.QrCode
import androidx.compose.material.icons.filled.Sync import androidx.compose.material.icons.filled.Sync
import androidx.compose.material.icons.filled.Wallet import androidx.compose.material.icons.filled.Wallet
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults import androidx.compose.material3.CardDefaults
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ModalDrawerSheet import androidx.compose.material3.ModalDrawerSheet
import androidx.compose.material3.ModalNavigationDrawer import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.NavigationDrawerItem import androidx.compose.material3.NavigationDrawerItem
import androidx.compose.material3.NavigationDrawerItemDefaults import androidx.compose.material3.NavigationDrawerItemDefaults
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.VerticalDivider import androidx.compose.material3.VerticalDivider
import androidx.compose.material3.rememberDrawerState import androidx.compose.material3.rememberDrawerState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope 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
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
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.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 coil3.compose.AsyncImage import coil3.compose.AsyncImage
import com.mob.utsmyanmar.R
import com.mob.utsmyanmar.ui.components.appbar.AppBar import com.mob.utsmyanmar.ui.components.appbar.AppBar
import com.mob.utsmyanmar.ui.device_info.DeviceInfoViewModel
import com.mob.utsmyanmar.ui.preview.P2Preview import com.mob.utsmyanmar.ui.preview.P2Preview
import com.mob.utsmyanmar.ui.theme.Color import com.mob.utsmyanmar.ui.theme.Color
import com.sunmi.pay.hardware.aidl.AidlConstants
import com.utsmyanmar.baselib.BaseApplication
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 kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -75,9 +83,16 @@ import kotlinx.coroutines.launch
@Composable @Composable
fun DashboardScreen2( fun DashboardScreen2(
onNavigateAmount: (String) -> Unit = {}, onNavigateAmount: (String) -> Unit = {},
onNavigateSignOn: () -> Unit = {} onNavigateSignOn: () -> Unit = {},
deviceInfoViewModel: DeviceInfoViewModel = viewModel()
) { ) {
val drawerState = rememberDrawerState(initialValue = androidx.compose.material3.DrawerValue.Closed) val deviceInfo by deviceInfoViewModel.uiState.collectAsState()
LaunchedEffect(Unit) {
deviceInfoViewModel.loadDeviceInfo();
}
val drawerState = rememberDrawerState(initialValue = androidx.compose.material3.DrawerValue.Open) //for preview
// val drawerState = rememberDrawerState(initialValue = androidx.compose.material3.DrawerValue.Closed) //for normal usage
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val mainHandler = remember { Handler(Looper.getMainLooper()) } val mainHandler = remember { Handler(Looper.getMainLooper()) }
var showHostActionDialog by remember { mutableStateOf(false) } var showHostActionDialog by remember { mutableStateOf(false) }
@ -85,10 +100,14 @@ fun DashboardScreen2(
var isHostActionRunning by remember { mutableStateOf(false) } var isHostActionRunning by remember { mutableStateOf(false) }
var dialogMessage by remember { mutableStateOf("") } var dialogMessage by remember { mutableStateOf("") }
val isOnline = true;
fun confirmationMessage(action: String) = "Do you want to start ${action.lowercase()}?" fun confirmationMessage(action: String) = "Do you want to start ${action.lowercase()}?"
fun processingMessage(action: String) = "Sending ${action.lowercase()} request to host..." fun processingMessage(action: String) = "Sending ${action.lowercase()} request to host..."
fun successMessage(action: String) = "$action success." fun successMessage(action: String) = "$action success."
fun failureMessage(action: String, resultCode: Int?) = "$action failed. Response code: ${resultCode ?: -1}" fun failureMessage(action: String, resultCode: Int?) =
"$action failed. Response code: ${resultCode ?: -1}"
fun networkFailureMessage(action: String) = "Network error during $action." fun networkFailureMessage(action: String) = "Network error during $action."
fun openHostActionDialog(action: String) { fun openHostActionDialog(action: String) {
activeHostAction = action activeHostAction = action
@ -149,7 +168,8 @@ fun DashboardScreen2(
isHostActionRunning = false isHostActionRunning = false
mainHandler.post { mainHandler.post {
isHostActionRunning = false isHostActionRunning = false
dialogMessage = failureMessage(activeHostAction, resultCode) dialogMessage =
failureMessage(activeHostAction, resultCode)
} }
} }
} }
@ -202,21 +222,48 @@ fun DashboardScreen2(
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(Color.LegacyRed) .background(Color.IvoryBeige)
.padding(horizontal = 20.dp, vertical = 28.dp) .padding(horizontal = 20.dp, vertical = 28.dp)
) { ) {
Row() {
Box(
modifier = Modifier
.size(80.dp)
.clip(CircleShape)
.background(Color.White),
contentAlignment = Alignment.Center
) {
Image(
painter = painterResource(R.drawable.logo_mob),
contentDescription = "mob logo",
modifier = Modifier
.size(100.dp)
.padding(16.dp),
contentScale = ContentScale.Fit
)
}
Column() {
Text( Text(
text = "MOBPOS", text = "MOB Merchant",
color = Color.White, color = Color.CrimsonRed,
fontSize = 22.sp, fontSize = 12.sp,
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold
) )
Spacer(modifier = Modifier.height(6.dp))
Text( Text(
text = "Quick navigation", text = "S/N:${deviceInfo.serialNumber}",
color = Color.White.copy(alpha = 0.85f), color = Color.Black,
fontSize = 13.sp fontSize = 12.sp,
fontWeight = FontWeight.Bold
) )
Text(
text = if(isOnline) "Online" else "Offline",
color = if(isOnline) Color.Success else Color.Error,
fontSize = 12.sp,
fontWeight = FontWeight.Bold
)
}
}
} }
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
@ -229,20 +276,6 @@ fun DashboardScreen2(
scope.launch { drawerState.close() } scope.launch { drawerState.close() }
openHostActionDialog("Log-Off") openHostActionDialog("Log-Off")
} }
DrawerItem("Sale", Icons.Default.PointOfSale) {
scope.launch { drawerState.close() }
onNavigateAmount("Sale")
}
DrawerItem("Sign On", Icons.Default.Link) {
scope.launch { drawerState.close() }
onNavigateSignOn()
}
DrawerItem("Settlement", Icons.Default.Wallet) {
scope.launch { drawerState.close() }
}
DrawerItem("History", Icons.Default.History) {
scope.launch { drawerState.close() }
}
} }
} }
) { ) {
@ -272,14 +305,14 @@ fun DashboardScreen2(
} }
} }
} }
} }
@Composable @Composable
private fun DrawerItem( private fun DrawerItem(
title: String, title: String,
icon: ImageVector, icon: ImageVector,
onClick: () -> Unit onClick: () -> Unit
) { ) {
NavigationDrawerItem( NavigationDrawerItem(
label = { label = {
Text( Text(
@ -302,20 +335,20 @@ fun DashboardScreen2(
unselectedTextColor = Color.Black unselectedTextColor = Color.Black
) )
) )
} }
@Composable @Composable
private fun AdvertisingArea() { private fun AdvertisingArea() {
val imageArray = listOf( val imageArray = listOf(
"https://i.ytimg.com/vi/eRUVxGRp1Ms/maxresdefault.jpg", "https://i.ytimg.com/vi/eRUVxGRp1Ms/maxresdefault.jpg",
"https://sunmi.ua/wp-content/themes/yootheme/cache/04/p6-3-en-04a68bb5.jpeg", "https://sunmi.ua/wp-content/themes/yootheme/cache/04/p6-3-en-04a68bb5.jpeg",
"https://mma.prnewswire.com/media/2080956/SUNMI_3rd_generation_products_T3_PRO_series_V3_MIX.jpg?p=facebook" "https://mma.prnewswire.com/media/2080956/SUNMI_3rd_generation_products_T3_PRO_series_V3_MIX.jpg?p=facebook"
); );
val pageState = rememberPagerState(pageCount = {imageArray.size}) val pageState = rememberPagerState(pageCount = { imageArray.size })
LaunchedEffect(pageState) { LaunchedEffect(pageState) {
while (true){ while (true) {
delay(10000) delay(10000)
val nextPage = (pageState.currentPage + 1) % imageArray.size; val nextPage = (pageState.currentPage + 1) % imageArray.size;
@ -327,7 +360,9 @@ fun DashboardScreen2(
} }
Card( Card(
modifier = Modifier.fillMaxWidth().height(170.dp), modifier = Modifier
.fillMaxWidth()
.height(170.dp),
shape = RoundedCornerShape(0.dp), shape = RoundedCornerShape(0.dp),
colors = CardDefaults.cardColors(containerColor = Color.White), colors = CardDefaults.cardColors(containerColor = Color.White),
) { ) {
@ -344,12 +379,14 @@ fun DashboardScreen2(
) )
} }
} }
} }
@Composable @Composable
private fun SummaryCard() { private fun SummaryCard() {
Card( Card(
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = Color.White), colors = CardDefaults.cardColors(containerColor = Color.White),
elevation = CardDefaults.cardElevation(4.dp) elevation = CardDefaults.cardElevation(4.dp)
@ -405,16 +442,16 @@ fun DashboardScreen2(
} }
} }
} }
} }
@Composable @Composable
private fun SummaryItem( private fun SummaryItem(
title: String, title: String,
value: String, value: String,
subtitle: String, subtitle: String,
icon: ImageVector, icon: ImageVector,
iconBg: androidx.compose.ui.graphics.Color iconBg: androidx.compose.ui.graphics.Color
) { ) {
Row( Row(
verticalAlignment = Alignment.Top, verticalAlignment = Alignment.Top,
modifier = Modifier.padding(6.dp) modifier = Modifier.padding(6.dp)
@ -431,13 +468,13 @@ fun DashboardScreen2(
} }
IconCircle(icon, iconBg) IconCircle(icon, iconBg)
} }
} }
@Composable @Composable
private fun IconCircle( private fun IconCircle(
icon: ImageVector, icon: ImageVector,
color: androidx.compose.ui.graphics.Color color: androidx.compose.ui.graphics.Color
) { ) {
Box( Box(
modifier = Modifier modifier = Modifier
.size(38.dp) .size(38.dp)
@ -452,13 +489,13 @@ fun DashboardScreen2(
modifier = Modifier.size(22.dp) modifier = Modifier.size(22.dp)
) )
} }
} }
@Composable @Composable
private fun MenuGrid( private fun MenuGrid(
onNavigateAmount: (String) -> Unit, onNavigateAmount: (String) -> Unit,
onNavigateSignOn: () -> Unit onNavigateSignOn: () -> Unit
) { ) {
Column( Column(
verticalArrangement = Arrangement.spacedBy(10.dp), verticalArrangement = Arrangement.spacedBy(10.dp),
modifier = Modifier.padding(horizontal = 16.dp) modifier = Modifier.padding(horizontal = 16.dp)
@ -485,15 +522,15 @@ fun DashboardScreen2(
MenuCard("See More", Icons.Default.GridView, Modifier.weight(1f)) MenuCard("See More", Icons.Default.GridView, Modifier.weight(1f))
} }
} }
} }
@Composable @Composable
private fun MenuCard( private fun MenuCard(
title: String, title: String,
icon: ImageVector, icon: ImageVector,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onClick: (() -> Unit)? = null onClick: (() -> Unit)? = null
) { ) {
Card( Card(
modifier = modifier modifier = modifier
.height(100.dp) .height(100.dp)
@ -545,10 +582,10 @@ fun DashboardScreen2(
} }
} }
} }
} }
@P2Preview @P2Preview
@Composable @Composable
fun PreviewDashboardScreen2() { fun PreviewDashboardScreen2() {
DashboardScreen2() DashboardScreen2()
} }

View File

@ -0,0 +1,11 @@
package com.mob.utsmyanmar.ui.device_info
data class DeviceInfoUiState(
val hardwareVersion: String = "",
val firmwareVersion: String = "",
val serialNumber: String = "",
val deviceModel: String = "",
val finalVersion: String = "",
val isLoading: Boolean = false,
val errorMessage: String? = null
)

View File

@ -0,0 +1,52 @@
package com.mob.utsmyanmar.ui.device_info
import androidx.lifecycle.ViewModel
import com.sunmi.pay.hardware.aidl.AidlConstants
import com.utsmyanmar.baselib.BaseApplication
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
class DeviceInfoViewModel : ViewModel() {
private val _uiState = MutableStateFlow(DeviceInfoUiState())
val uiState = _uiState.asStateFlow()
fun loadDeviceInfo() {
_uiState.value = _uiState.value.copy(isLoading = true)
try {
val hardwareVersion = getParams(AidlConstants.SysParam.HARDWARE_VERSION)
val firmwareVersion = getParams(AidlConstants.SysParam.FIRMWARE_VERSION)
val serialNo = getParams(AidlConstants.SysParam.SN)
val deviceModel = getParams(AidlConstants.SysParam.DEVICE_MODEL)
val finalVersion = SystemParamsOperation.getInstance().finalVersion ?: ""
_uiState.value = DeviceInfoUiState(
hardwareVersion = hardwareVersion,
firmwareVersion = firmwareVersion,
serialNumber = serialNo,
deviceModel = deviceModel,
finalVersion = finalVersion,
isLoading = false
)
} catch (e: Exception) {
_uiState.value = _uiState.value.copy(
isLoading = false,
errorMessage = e.message ?: "Failed to load device info"
)
}
}
private fun getParams(name: String): String {
return try {
BaseApplication.getInstance()
.basicOptBinder
?.getSysParam(name)
?: ""
} catch (e: Exception) {
""
}
}
}

View File

@ -22,4 +22,5 @@ object Color {
val Black = Color(0xFF000000) val Black = Color(0xFF000000)
val Gray = Color(0xFF898989) val Gray = Color(0xFF898989)
val Success = Color(0xFF007E33) val Success = Color(0xFF007E33)
val Error = Color(0xFFCD2029)
} }