sign on page
This commit is contained in:
parent
f4fc2fa730
commit
fe6c5ad15e
@ -25,7 +25,8 @@ import com.mob.utsmyanmar.ui.theme.Color
|
||||
|
||||
@Composable
|
||||
fun DashboardScreen2(
|
||||
onNavigateAmount: (String) -> Unit = {}
|
||||
onNavigateAmount: (String) -> Unit = {},
|
||||
onNavigateSignOn: () -> Unit = {}
|
||||
) {
|
||||
Scaffold(
|
||||
containerColor = Color.IvoryBeige,
|
||||
@ -42,7 +43,10 @@ fun DashboardScreen2(
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
SummaryCard()
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
MenuGrid(onNavigateAmount = onNavigateAmount)
|
||||
MenuGrid(
|
||||
onNavigateAmount = onNavigateAmount,
|
||||
onNavigateSignOn = onNavigateSignOn
|
||||
)
|
||||
Spacer(modifier = Modifier.height(18.dp))
|
||||
RecentTransactionHeader()
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
@ -145,7 +149,8 @@ private fun SummaryItem(
|
||||
|
||||
@Composable
|
||||
private fun MenuGrid(
|
||||
onNavigateAmount: (String) -> Unit
|
||||
onNavigateAmount: (String) -> Unit,
|
||||
onNavigateSignOn: () -> Unit
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp)
|
||||
@ -162,7 +167,12 @@ private fun MenuGrid(
|
||||
}
|
||||
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
MenuCard("Sign On", Icons.Default.Link, Modifier.weight(1f))
|
||||
MenuCard(
|
||||
"Sign On",
|
||||
Icons.Default.Link,
|
||||
Modifier.weight(1f),
|
||||
onClick = onNavigateSignOn
|
||||
)
|
||||
MenuCard("Settlement", Icons.Default.Wallet, Modifier.weight(1f))
|
||||
MenuCard("See More", Icons.Default.GridView, Modifier.weight(1f))
|
||||
}
|
||||
|
||||
@ -19,6 +19,8 @@ import com.mob.utsmyanmar.ui.pinpad.PinPadRoute
|
||||
import com.mob.utsmyanmar.ui.processing_card.ProcessingCardRoute
|
||||
import com.mob.utsmyanmar.ui.processing_card.ProcessingCardViewModel
|
||||
import com.mob.utsmyanmar.ui.print_receipt.PrintReceiptScreen
|
||||
import com.mob.utsmyanmar.ui.sign_on.SignOnResultScreen
|
||||
import com.mob.utsmyanmar.ui.sign_on.SignOnRoute
|
||||
import com.mob.utsmyanmar.ui.sending_to_host.SendingToHostRoute
|
||||
import com.mob.utsmyanmar.ui.transaction_result.TransactionResultRoute
|
||||
import com.mob.utsmyanmar.viewmodel.CardReaderViewModel
|
||||
@ -47,6 +49,62 @@ fun AppNavGraph(
|
||||
}
|
||||
launchSingleTop = true
|
||||
}
|
||||
},
|
||||
onNavigateSignOn = {
|
||||
navController.navigate(Routes.SignOn.route) {
|
||||
launchSingleTop = true
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
composable(Routes.SignOn.route) {
|
||||
SignOnRoute(
|
||||
onBack = { navController.popBackStack() },
|
||||
onNavigateResult = { isSuccess, message ->
|
||||
navController.navigate(Routes.SignOnResult.createRoute(isSuccess, message)) {
|
||||
popUpTo(Routes.SignOn.route) {
|
||||
inclusive = true
|
||||
}
|
||||
launchSingleTop = true
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
composable(
|
||||
route = Routes.SignOnResult.route,
|
||||
arguments = listOf(
|
||||
navArgument("isSuccess") {
|
||||
type = NavType.BoolType
|
||||
},
|
||||
navArgument("message") {
|
||||
type = NavType.StringType
|
||||
}
|
||||
)
|
||||
) { backStackEntry ->
|
||||
val isSuccess = backStackEntry.arguments?.getBoolean("isSuccess") ?: false
|
||||
val message = backStackEntry.arguments?.getString("message").orEmpty()
|
||||
|
||||
SignOnResultScreen(
|
||||
isSuccess = isSuccess,
|
||||
message = message,
|
||||
onBack = { navController.popBackStack() },
|
||||
onDone = {
|
||||
navController.navigate(Routes.Dashboard.route) {
|
||||
popUpTo(Routes.Dashboard.route) {
|
||||
inclusive = false
|
||||
}
|
||||
launchSingleTop = true
|
||||
}
|
||||
},
|
||||
onRetry = {
|
||||
navController.navigate(Routes.SignOn.route) {
|
||||
popUpTo(Routes.SignOnResult.route) {
|
||||
inclusive = true
|
||||
}
|
||||
launchSingleTop = true
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,10 +1,18 @@
|
||||
package com.mob.utsmyanmar.ui.navigation
|
||||
|
||||
import android.net.Uri
|
||||
|
||||
sealed class Routes(val route: String) {
|
||||
data object Dashboard : Routes("dashboard")
|
||||
data object Amount : Routes("amount/{action}") {
|
||||
fun createRoute(action: String): String = "amount/$action"
|
||||
}
|
||||
data object SignOn : Routes("sign_on")
|
||||
data object SignOnResult : Routes("sign_on_result/{isSuccess}/{message}") {
|
||||
fun createRoute(isSuccess: Boolean, message: String): String {
|
||||
return "sign_on_result/$isSuccess/${Uri.encode(message)}"
|
||||
}
|
||||
}
|
||||
data object CardWaiting : Routes("card_waiting")
|
||||
data object ProcessingCard : Routes("processing_card")
|
||||
data object PinPad : Routes("pin_pad")
|
||||
|
||||
262
app/src/main/java/com/mob/utsmyanmar/ui/sign_on/SignOnScreen.kt
Normal file
262
app/src/main/java/com/mob/utsmyanmar/ui/sign_on/SignOnScreen.kt
Normal file
@ -0,0 +1,262 @@
|
||||
package com.mob.utsmyanmar.ui.sign_on
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
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.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.CheckCircle
|
||||
import androidx.compose.material.icons.filled.ErrorOutline
|
||||
import androidx.compose.material.icons.filled.Sync
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.mob.utsmyanmar.ui.components.appbar.AppBar
|
||||
import com.mob.utsmyanmar.ui.theme.Color as AppColor
|
||||
|
||||
@Composable
|
||||
fun SignOnRoute(
|
||||
onBack: () -> Unit,
|
||||
onNavigateResult: (Boolean, String) -> Unit,
|
||||
viewModel: SignOnViewModel = viewModel()
|
||||
) {
|
||||
val state by viewModel.uiState.collectAsState()
|
||||
|
||||
LaunchedEffect(viewModel) {
|
||||
viewModel.resultEvents.collect { result ->
|
||||
onNavigateResult(result.isSuccess, result.message)
|
||||
}
|
||||
}
|
||||
|
||||
SignOnScreen(
|
||||
state = state,
|
||||
onBack = onBack,
|
||||
onStartSignOn = viewModel::startSignOn
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SignOnScreen(
|
||||
state: SignOnUiState,
|
||||
onBack: () -> Unit,
|
||||
onStartSignOn: () -> Unit
|
||||
) {
|
||||
Scaffold(
|
||||
containerColor = AppColor.IvoryBeige,
|
||||
topBar = {
|
||||
AppBar(
|
||||
title = "Sign On",
|
||||
icon = Icons.Default.ArrowBack,
|
||||
onIconClick = onBack
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(20.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = AppColor.White),
|
||||
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(20.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Sync,
|
||||
contentDescription = null,
|
||||
tint = AppColor.LegacyRed,
|
||||
modifier = Modifier.height(42.dp)
|
||||
)
|
||||
Text(
|
||||
text = "Host Sign On",
|
||||
fontSize = 22.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = AppColor.LegacyRed
|
||||
)
|
||||
Text(
|
||||
text = "Run sign on and verify immediately whether the host accepted or rejected the terminal.",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = AppColor.Gray
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(20.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = AppColor.White)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(20.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Current Status",
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = AppColor.Black
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = if (state.isLoading) AppColor.GoldenGlow.copy(alpha = 0.18f) else AppColor.SkylineBlue.copy(alpha = 0.12f),
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
)
|
||||
.padding(16.dp)
|
||||
) {
|
||||
if (state.isLoading) {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
CircularProgressIndicator(color = AppColor.LegacyRed)
|
||||
Text(text = state.statusText, color = AppColor.Black)
|
||||
}
|
||||
} else {
|
||||
Text(text = state.statusText, color = AppColor.Black)
|
||||
}
|
||||
}
|
||||
|
||||
Button(
|
||||
onClick = onStartSignOn,
|
||||
enabled = !state.isLoading,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = AppColor.CrimsonRed,
|
||||
disabledContainerColor = AppColor.Gray
|
||||
)
|
||||
) {
|
||||
Text(text = if (state.isLoading) "Processing..." else "Start Sign On")
|
||||
}
|
||||
|
||||
if (state.canRetry) {
|
||||
OutlinedButton(
|
||||
onClick = onStartSignOn,
|
||||
enabled = !state.isLoading,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(text = "Retry")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SignOnResultScreen(
|
||||
isSuccess: Boolean,
|
||||
message: String,
|
||||
onBack: () -> Unit,
|
||||
onDone: () -> Unit,
|
||||
onRetry: () -> Unit
|
||||
) {
|
||||
val accent = if (isSuccess) AppColor.Success else AppColor.LegacyRed
|
||||
val background = if (isSuccess) AppColor.Success.copy(alpha = 0.12f) else AppColor.CrimsonRed.copy(alpha = 0.12f)
|
||||
|
||||
Scaffold(
|
||||
containerColor = AppColor.IvoryBeige,
|
||||
topBar = {
|
||||
AppBar(
|
||||
title = "Sign On Result",
|
||||
icon = Icons.Default.ArrowBack,
|
||||
onIconClick = onBack
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(24.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = AppColor.White)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(24.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(background, RoundedCornerShape(50))
|
||||
.padding(18.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (isSuccess) Icons.Default.CheckCircle else Icons.Default.ErrorOutline,
|
||||
contentDescription = null,
|
||||
tint = accent
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = if (isSuccess) "Sign On Success" else "Sign On Failed",
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = accent
|
||||
)
|
||||
|
||||
Text(
|
||||
text = message,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = Color.Black
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
if (!isSuccess) {
|
||||
Button(
|
||||
onClick = onRetry,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
colors = ButtonDefaults.buttonColors(containerColor = AppColor.CrimsonRed)
|
||||
) {
|
||||
Text(text = "Try Again")
|
||||
}
|
||||
}
|
||||
|
||||
OutlinedButton(
|
||||
onClick = onDone,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(text = "Back To Dashboard")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
package com.mob.utsmyanmar.ui.sign_on
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.utsmyanmar.paylibs.sign_on.SignOnListener
|
||||
import com.utsmyanmar.paylibs.sign_on.SignOnProcess
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
data class SignOnUiState(
|
||||
val isLoading: Boolean = false,
|
||||
val statusText: String = "Ready to start sign on.",
|
||||
val canRetry: Boolean = false
|
||||
)
|
||||
|
||||
data class SignOnResult(
|
||||
val isSuccess: Boolean,
|
||||
val message: String
|
||||
)
|
||||
|
||||
class SignOnViewModel : ViewModel() {
|
||||
|
||||
private val _uiState = MutableStateFlow(SignOnUiState())
|
||||
val uiState: StateFlow<SignOnUiState> = _uiState.asStateFlow()
|
||||
|
||||
private val _resultEvents = MutableSharedFlow<SignOnResult>()
|
||||
val resultEvents: SharedFlow<SignOnResult> = _resultEvents.asSharedFlow()
|
||||
|
||||
fun startSignOn() {
|
||||
if (_uiState.value.isLoading) return
|
||||
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isLoading = true,
|
||||
statusText = "Signing on to host...",
|
||||
canRetry = false
|
||||
)
|
||||
}
|
||||
//
|
||||
// SignOnProcess.getInstance()
|
||||
// .enqueue()
|
||||
// .startSignOn(object : SignOnListener {
|
||||
// override fun onSuccessSignOn() {
|
||||
// dispatchResult(
|
||||
// SignOnResult(
|
||||
// isSuccess = true,
|
||||
// message = "Sign on completed successfully."
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// override fun onFailureSignOn(resultCode: Integer?) {
|
||||
// dispatchResult(
|
||||
// SignOnResult(
|
||||
// isSuccess = false,
|
||||
// message = "Sign on failed. Response code: ${resultCode ?: -1}"
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// override fun onNetworkFailSignOn(message: String?) {
|
||||
// dispatchResult(
|
||||
// SignOnResult(
|
||||
// isSuccess = false,
|
||||
// message = message?.takeIf { it.isNotBlank() } ?: "Network error during sign on."
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
private fun dispatchResult(result: SignOnResult) {
|
||||
viewModelScope.launch {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isLoading = false,
|
||||
statusText = result.message,
|
||||
canRetry = !result.isSuccess
|
||||
)
|
||||
}
|
||||
_resultEvents.emit(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user