Composable function use be UI Components of application
Main Screen
directory MainActivity.kt
@Composable
fun MainScreen(
navController: NavHostController,
toggleTheme: () -> Unit,
currentTheme: MutableState<Boolean>,
context: Context
) {
val emv = DeviceHelper.me().emv
val scaffoldState = rememberScaffoldState(rememberDrawerState(DrawerValue.Closed))
val scope = rememberCoroutineScope()
val tabIndex = remember { mutableStateOf(0) }
val greetingMSG = remember { mutableStateOf(greeting())}
val checkGreeting = Thread( Runnable(){
run() {
while(true)
{
greetingMSG.value = greeting()
Thread.sleep(10000)
}
}
});
Scaffold(
Modifier.fillMaxWidth(),
backgroundColor = MaterialTheme.colors.background,
scaffoldState = scaffoldState,
topBar = { TopBar(scope = scope, scaffoldState = scaffoldState, tabIndex = tabIndex, greetingMSG.value) },
drawerContent = {
Drawer(
scope = scope,
scaffoldState = scaffoldState,
navController = navController,
toggleTheme,
currentTheme
)
},
) {
LaunchedEffect(Unit) {
// do API call
scope.launch {
checkGreeting.start()
runCardCheck(navController, scope, emv)
}
}
DisposableEffect(Unit) {
onDispose {
scope.launch {
checkGreeting.stop()
emv.stopSearch()
}
}
}
when (tabIndex.value) {
0 -> {
// Home Screen Section
MenuView(navController, context)
}
1 -> {
// Card Entry Menu Screen Section
CardEntry(navController = navController)
}
2 -> {
// Menu Entry Menu Screen Section
MenuEntry(navController = navController)
}
3 -> {
// Use Menu Screen Section
UserMenu(navController = navController)
}
else -> {
// Today Transaction Screen Section
TransactionView(context,navController)
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
Home Screen Section
directory screen/home/Menu.kt use for Main Screen consist of sale card and favorite menu
code
@Composable
fun MenuView(navController: NavHostController, context: Context) {
val scrollState = rememberScrollState()
val data = FavoriteRoute.routeList
val totalSale = getTodaySales()
Column(
modifier = Modifier
.fillMaxSize()
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(10.dp)
) {
SaleCardButton(navController, totalSale) // Sale Card Component
Spacer(modifier = Modifier.height(20.dp))
FavoriteMenu(navController, data) // Favorite Menu Component
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Sale Card Component
Display today total sale and can use to do sale transaction
code
@Composable
fun SaleCardButton(navController: NavHostController, total_sale: String) {
Card(
backgroundColor = CardColor,
shape = RoundedCornerShape(10.dp),
modifier = Modifier
.fillMaxWidth()
.height(120.dp),
elevation = 8.dp,
) {
Box(modifier = Modifier
.clickable {
DeviceHelper.me().emv.stopSearch()
navController.navigate(
"amount/" +
"${
JSONObject(
"{" +
"transaction_type:\"sale\"," +
"title:\"Sale\"" +
"}"
)
}"
)
}) {
Row(
Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Column(
modifier = Modifier
.fillMaxHeight()
.padding(start = 20.dp),
verticalArrangement = Arrangement.Center
) {
Text(
text = "TODAY",
color = Color.White,
fontWeight = FontWeight.Black,
fontSize = 12.sp
)
Spacer(modifier = Modifier.height(10.dp))
Text(
text = "SALE",
color = Color.Black,
fontWeight = FontWeight.SemiBold,
fontSize = 20.sp
)
Text(
text = "TOTAL: $total_sale BAHT",
color = Color.White,
fontWeight = FontWeight.SemiBold,
fontSize = 12.sp
)
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(end = 20.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.End
) {
Image(painterResource(R.drawable.ic_sale), "coin")
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
Favorite Menu Component
Display favorite menu using The Button Component
code
@Composable
fun FavoriteMenu(navController: NavHostController, data: List<Route>) {
Text(
modifier = Modifier,
text = "Favorite Menu",
fontSize = 15.sp,
fontWeight = FontWeight.SemiBold,
color = MaterialTheme.colors.onSurface
)
Spacer(modifier = Modifier.height(5.dp))
Row(
modifier = Modifier.fillMaxWidth()
) {
LazyVerticalGrid(
cells = GridCells.Fixed(3),
contentPadding = PaddingValues(5.dp)
) {
items(data.size) { item ->
TheButton(data[item], navController)
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Card Entry Menu Screen Section
directory screen/home/CardEntry.kt use to display card entry menu using Route Menu List
code
@Composable
fun CardEntry(navController: NavHostController) {
Column(
modifier = Modifier.fillMaxSize()
) {
RouteMenu(navController, CardEntryRoute.routeList, "Card Entry Menu")
}
}
2
3
4
5
6
7
8
Menu Entry Menu Screen Section
directory screen/home/MenuEntry.kt use to display menu entry menu using Route Menu List
code
@Composable
fun MenuEntry(navController: NavHostController) {
Column(
modifier = Modifier.fillMaxSize()
) {
RouteMenu(navController, MenuEntryRoute.routeList, "Menu Entry Menu")
}
}
2
3
4
5
6
7
8
User Menu Screen Section
directory screen/home/UserMenu.kt use to display user menu using Route Menu List
code
@Composable
fun UserMenu(navController: NavHostController) {
Column(
modifier = Modifier.fillMaxSize()
) {
RouteMenu(navController, UserMenuRoute.routeList, "User Menu")
}
}
2
3
4
5
6
7
8
Today Transasction Screen Section
directory screen/home/Transaction.kt use to display transaction list
code
@Composable
fun TransactionView(context: Context, navController: NavController) {
val (totalTransaction, todayTransaction) = getTodayTransaction()
val castType = todayTransaction as (RealmList<TransactionHistoryRO>)
val myList = remember { mutableStateOf(castType)}
val indexItemSelected = remember { mutableStateOf(-1)}
val callback = {
val (newTotalTransaction, newTodayTransaction) = getTodayTransaction()
myList.value = newTodayTransaction as (RealmList<TransactionHistoryRO>)
}
Column(
modifier = Modifier
.fillMaxSize()
) {
TransactionHeader(totalTransaction as String)
TransactionViewDetail(context, navController, myList.value, indexItemSelected, callback)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Transaction Header Component
Display header show today transaction list
code
@Composable
fun TransactionHeader(totalTransaction: String) {
val date = Date()
val today = "${if (date.date < 10) "0${date.date}" else date.date}/" +
"${if (1 + date.month < 10) "0${1 + date.month}" else 1 + date.month}/" +
"${1900 + date.year}"
Card(
shape = RoundedCornerShape(0.dp) ,
modifier = Modifier
.fillMaxWidth()
.height(120.dp),
elevation = 10.dp,
backgroundColor = CardColor
) {
Row(
Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Column(
modifier = Modifier
.fillMaxHeight()
.padding(start = 20.dp),
verticalArrangement = Arrangement.Center
) {
Text(text = "TODAY", color = Color.Black, fontWeight = FontWeight.Black, fontSize = 12.sp)
Text(text = today, color = Color.White, fontWeight = FontWeight.SemiBold, fontSize = 12.sp)
Spacer(modifier = Modifier.height(5.dp))
Text(text = "TRANSACTION", color = Color.Black, fontWeight = FontWeight.Black, fontSize = 15.sp)
Text(text = "TOTAL: $totalTransaction BAHT", color = Color.White, fontWeight = FontWeight.SemiBold, fontSize = 12.sp)
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(end = 20.dp)
,
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.End
) {
Image(painterResource(R.drawable.ic_sale),"coin")
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Transaction Detail Component
Display detail of today transaction list
code
@Composable
fun TransactionViewDetail(
context: Context,
navController: NavController,
todayTransactions: RealmList<TransactionHistoryRO>,
indexItemSelected: MutableState<Int>,
callback: () -> Unit,
) {
if (todayTransactions.size>0) {
LazyColumn {
items(todayTransactions.size) { item ->
TransactionSwipeItem(context, navController,
todayTransactions[item]!!, item, indexItemSelected, callback
)
Divider(color = Color.LightGray, thickness = 1.dp)
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Transaction Item Component
Display transaction item of today transaction list, support swipe event for choose an button can be perform
code
@Composable
fun TransactionSwipeItem(
context: Context,
navController: NavController,
transaction: TransactionHistoryRO,
indexItem: Int,
indexItemSelected: MutableState<Int>,
callback: () -> Unit,
) {
val lastest = remember { mutableStateOf(false) }
val squareSize = 190.dp
val swipeAbleState = rememberSwipeableState(initialValue = 0)
val sizePx = with(LocalDensity.current) { squareSize.toPx() }
val anchors = mapOf(0f to 0, sizePx to 1)
val scope = rememberCoroutineScope()
if (swipeAbleState.isAnimationRunning) {
DisposableEffect(Unit) {
onDispose {
if (swipeAbleState.currentValue==1&&indexItemSelected.value!=indexItem&&!lastest.value) {
indexItemSelected.value = indexItem
lastest.value = true
}
else if (swipeAbleState.currentValue==0&&indexItemSelected.value==indexItem) {
indexItemSelected.value = -1
lastest.value = false
}
scope.launch {
if (swipeAbleState.currentValue==1&&indexItem!=indexItemSelected.value) {
swipeAbleState.animateTo(0)
lastest.value = false
}
else if (indexItem==indexItemSelected.value) {
swipeAbleState.animateTo(1)
}
}
}
}
}
Box(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(0.dp))
.background(MaterialTheme.colors.onBackground)
.swipeable(
state = swipeAbleState,
anchors = anchors,
orientation = Orientation.Horizontal,
reverseDirection = true
)
) {
Row(
modifier = Modifier
.padding(5.dp)
.fillMaxWidth()
.clip(RoundedCornerShape(0.dp)),
horizontalArrangement = Arrangement.End
) {
if (transaction.txn_type in arrayOf("sale","offline_sale")) {
TransactionButton(context,navController,swipeAbleState,indexItemSelected,transaction,"tip_adjust","Tip-Adjust", callback)
}
if (transaction.txn_type in arrayOf("offline_sale")) {
TransactionButton(context,navController,swipeAbleState,indexItemSelected, transaction, "offline_sale", "Offline Sale", callback)
}
if (transaction.txn_type in arrayOf("pre_auth")) {
TransactionButton(context,navController,swipeAbleState,indexItemSelected, transaction, "offline_sale", "Offline Sale", callback)
}
if (transaction.txn_type in arrayOf("pre_auth")) {
TransactionButton(context,navController,swipeAbleState,indexItemSelected, transaction, "sale_complete", "Sale Complete", callback)
}
if (transaction.txn_type in arrayOf("sale","refund")) {
TransactionButton(context,navController,swipeAbleState,indexItemSelected, transaction, "void", "Void", callback)
}
TransactionButton(context,navController,swipeAbleState,indexItemSelected, transaction, "print", "Print", callback)
}
Box(
modifier = Modifier
.offset {
IntOffset(
-swipeAbleState.offset.value.roundToInt(), 0
)
}
.clip(RoundedCornerShape(0.dp))
.fillMaxWidth()
.fillMaxHeight()
.background(MaterialTheme.colors.onBackground)
.align(Alignment.CenterStart)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(5.dp),
verticalAlignment = Alignment.CenterVertically
)
{
Card(
shape = RoundedCornerShape(15.dp),
modifier = Modifier
.width(70.dp)
.height(70.dp),
backgroundColor = CardComingSoonColor
) {
val queryCardScheme = getCardData(transaction.card_record_index!!)
val checkCardBrand =
when (queryCardScheme!!.card_scheme_type!!.lowercase(Locale.getDefault())) {
"visa card" -> R.drawable.ic_visa_inc_small
"mastercard" -> R.drawable.ic_mastercard_logo_small
else -> R.drawable.ic_coin_small
}
Image(
painterResource(checkCardBrand),
"${transaction.id}",
contentScale = ContentScale.Inside,
modifier = Modifier
.size(25.dp)
.padding(10.dp)
)
}
Column(
modifier = Modifier.padding(start = 15.dp)
) {
Text(text = transaction.card_number!!
.uppercase(Locale.getDefault())
.replace("_"," "),
color = MaterialTheme.colors.onSurface,
fontWeight = FontWeight.SemiBold,
fontSize = 12.sp)
Text(
text = "TRACE# : ${transaction.invoice_number}",
color = MaterialTheme.colors.onSurface,
fontWeight = FontWeight.Normal,
fontSize = 10.sp
)
Text(
text = "STAN# : ${transaction.stan}",
color = MaterialTheme.colors.onSurface,
fontWeight = FontWeight.Normal,
fontSize = 10.sp
)
}
Column(
modifier = Modifier
.fillMaxWidth()
.padding(end = 5.dp),
horizontalAlignment = Alignment.End
) {
Text(
text = Utils().convertToTime(transaction.time.toString()),
color = MaterialTheme.colors.onSurface,
fontWeight = FontWeight.Normal,
fontSize = 10.sp
)
Text(text = transaction.txn_type!!
.uppercase(Locale.getDefault())
.replace("_"," "),
color = MaterialTheme.colors.onSurface,
fontWeight = FontWeight.SemiBold,
fontSize = 12.sp)
Text(text = Utils().formatMoney(Utils().formatMoneyD2S(transaction.txn_amount!!)),
color = MaterialTheme.colors.onSurface,
fontWeight = FontWeight.SemiBold,
fontSize = 12.sp)
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
Transaction Button Component
Display transaction button of each transaction item for an action
code
@Composable
fun TransactionButton(
context: Context,
navController: NavController,
swipeAbleState: SwipeableState<Int>,
indexItemSelected: MutableState<Int>,
transaction: TransactionHistoryRO,
transactionType: String,
display: String,
callback: () -> Unit
) {
val popupPrintSlipCustomer = remember { mutableStateOf(false) }
val coroutineScope = rememberCoroutineScope()
val loading = remember { mutableStateOf(false) }
val textLoading = remember { mutableStateOf("") }
val errMessage = remember { mutableStateOf("") }
val errMessageOpenDialog = remember { mutableStateOf(false) }
val popUpContinue = remember { mutableStateOf(false) }
val isCloseButtonShowAlertMessage = remember { mutableStateOf(true) }
val handler = CoroutineExceptionHandler { _, exception ->
Log.e("Transaction Display", exception.toString())
}
if (loading.value) {
ShowLoading(
openDialog = loading,
text = textLoading,
)
}
if (errMessageOpenDialog.value) {
ShowAlertMessage(
description = errMessage,
openDialog = errMessageOpenDialog,
isCloseButton = isCloseButtonShowAlertMessage
)
}
Column(
modifier = Modifier
.fillMaxHeight(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
IconButton(
onClick = {
coroutineScope.launch(handler) {
loading.value = true
val checkProcess = menuEntryProcess(
context, navController, indexItemSelected, errMessage, loading,
textLoading, popupPrintSlipCustomer, popUpContinue,
transaction, transactionType, callback
)
callback()
if (!checkProcess) {
loading.value = false
errMessageOpenDialog.value = true
delay(1_500)
}
else {
loading.value = false
}
}
},
modifier = Modifier
.padding(5.dp)
.size(50.dp)
.clip(CircleShape)
.alpha(0.5F)
.background(Color.Gray)
) {
Icon(
Icons.Filled.Done,
contentDescription = display,
tint = Color.Green
)
}
Text(
text = display,
fontSize = 10.sp,
color = MaterialTheme.colors.onSurface
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
Transaction Process Screen
Use to display each transaction process. Each transaction process screen has called:
- NavController for change and pass data to another screen
- CountDownTimer for count down time of transaction process (current: 60000ms)
directory screen/transaction
Card Display Screen
Use to display card information and confirm transaction
directory screen/transaction/card_display/CardDisplay.kt
code
@Composable
fun CardDisplay(navController: NavHostController, data: String, context: Context) {
val jsonData = JSONObject(data)
val doProcess = remember { mutableStateOf(false) }
val countDownTimer = remember { mutableStateOf("60") }
val timer = object : CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
if (doProcess.value){ cancel() }
countDownTimer.value = ((millisUntilFinished / 1000)).toString()
}
override fun onFinish() {
countDownTimer.value = "0"
navController.popBackStack()
}
}
LaunchedEffect(Unit) {
timer.start()
}
DisposableEffect(Unit) {
onDispose {
timer.cancel()
}
}
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()
) {
TransactionTitleBar(
navController, countDownTimer, timer, jsonData.getString("title").uppercase()
)
// Virtual Card Component
VirtualCard(
jsonData.getString("card_number"),
jsonData.getString("pan_masking"),
jsonData.getString("name")
)
ShowAmount(jsonData.getString("amount"))
Spacer(Modifier.weight(1f))
ButtonSuccessConfirm(jsonData, navController, context, doProcess)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Virtual Card Component
Use to display card information
code
@Composable
private fun VirtualCard(card_number: String, pan_masking: String, name: String) {
val cardMasking = remember { mutableStateOf("") }
if (card_number.length != pan_masking.replace(" ", "").length) {
return
}
cardMasking.value = Utils().cardMasking(card_number, pan_masking)
Card(
backgroundColor = StaticColorText,
shape = RoundedCornerShape(10.dp),
modifier = Modifier
.padding(13.dp)
.height(200.dp)
.padding(bottom = 10.dp),
elevation = 8.dp,
) {
Column(
modifier = Modifier.padding(15.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Column {
Text(
fontWeight = FontWeight.Normal,
text = "EXPIRES",
modifier = Modifier,
fontSize = 8.sp,
color = MenuListTextDark,
letterSpacing = 2.sp,
)
Text(
fontWeight = FontWeight.Normal,
letterSpacing = 2.sp,
text = "XX/XX",
modifier = Modifier,
fontSize = 10.sp,
color = MenuListTextDark
)
Card(
backgroundColor = ChipCard,
shape = RoundedCornerShape(10.dp),
modifier = Modifier
.padding(top = 25.dp, bottom = 25.dp)
.height(40.dp)
.width(50.dp)
) {}
Text(
fontWeight = FontWeight.Normal,
letterSpacing = 4.sp,
text = cardMasking.value,
modifier = Modifier,
fontSize = 15.sp,
color = MenuListTextDark
)
Text(
fontWeight = FontWeight.Bold,
letterSpacing = 4.sp,
text = if (name != "") name else "KEY IN",
modifier = Modifier,
fontSize = 15.sp,
color = MenuListTextDark
)
}
when(Utils().identifyCardScheme(card_number)) {
CardScheme.VISA -> Image(painterResource(R.drawable.ic_visa_inc), "coin")
CardScheme.MASTERCARD -> Image(painterResource(R.drawable.ic_mastercard_logo), "coin")
else -> Image(painterResource(R.drawable.coin), "coin")
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
Display Amount Component
Use to display amount of transaction
code
@Composable
private fun ShowAmount(amount: String) {
Column(
modifier = Modifier.padding(top = 10.dp, start = 10.dp, end = 10.dp)
) {
Text(
fontSize = 15.sp,
text = "AMOUNT",
modifier = Modifier.padding(5.dp),
color = MaterialTheme.colors.onSurface
)
Divider()
Column(
horizontalAlignment = Alignment.End,
modifier = Modifier
.padding(10.dp)
.fillMaxWidth(),
) {
Row(
modifier = Modifier.padding(top = 9.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
modifier = Modifier.padding(end = 5.dp),
fontWeight = FontWeight.Bold,
fontSize = 20.sp,
text = "฿",
color = if (MaterialTheme.colors.isLight) MainText else MainTextDark
)
Text(
overflow = TextOverflow.Clip,
text = amount,
color = StaticColorText,
fontFamily = Prompt,
fontWeight = FontWeight.Bold,
fontSize = 30.sp,
)
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Confirm Button Component
Use to display confirm transaction button
code
@Composable
private fun ButtonSuccessConfirm(
jsonData: JSONObject,
navController: NavHostController,
context: Context,
doProcess: MutableState<Boolean>,
) {
val popupPrintSlipCustomer = remember { mutableStateOf(false) }
val coroutineScope = rememberCoroutineScope()
val loading = remember { mutableStateOf(false) }
val textLoading = remember { mutableStateOf("") }
val errMessage = remember { mutableStateOf("") }
val errMessageOpenDialog = remember { mutableStateOf(false) }
val popUpBalanceInquiry = remember { mutableStateOf(false) }
val balanceInquiryTitle = remember { mutableStateOf("") }
val balanceInquiryAmount = remember { mutableStateOf("") }
val popUpContinue = remember { mutableStateOf(false) }
val isCloseButtonShowAlertMessage = remember { mutableStateOf(false) }
val nextRoute = remember { mutableStateOf("") }
val handler = CoroutineExceptionHandler { _, exception ->
Log.e("Card Display", exception.message.toString())
}
if (popupPrintSlipCustomer.value) {
AskPrintCustomerSlip(
openDialog = popupPrintSlipCustomer,
navController = navController,
jsonData = jsonData,
context = context,
)
}
if (loading.value) {
ShowLoading(
openDialog = loading,
text = textLoading,
)
}
if (errMessageOpenDialog.value) {
ShowAlertMessage(
description = errMessage,
openDialog = errMessageOpenDialog,
isCloseButton = isCloseButtonShowAlertMessage
)
}
if (popUpBalanceInquiry.value) {
ShowInquiryMessage(
title = balanceInquiryTitle,
amount = balanceInquiryAmount,
openDialog = popUpBalanceInquiry,
navController = navController,
)
}
Column(
modifier = Modifier
.padding(20.dp)
.fillMaxWidth()
) {
Button(
onClick = {
loading.value = true
doProcess.value = true
coroutineScope.launch(handler) {
// Function Transaction Of Card Entry
val checkProcess = cardEntryProcess(
jsonData,
errMessage,
context,
popupPrintSlipCustomer,
loading,
textLoading,
popUpBalanceInquiry,
balanceInquiryAmount,
balanceInquiryTitle,
popUpContinue,
nextRoute
)
if (nextRoute.value!=""){
navController.navigate("${nextRoute.value}/$jsonData") {
popUpTo(Route.Home.route)
}
}
else {
if (!checkProcess) {
loading.value = false
errMessageOpenDialog.value = true
delay(1_500)
}
if (!popUpContinue.value) {
navController.popBackStack()
} else {
loading.value = false
}
}
}
},
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
shape = RoundedCornerShape(50),
modifier = Modifier.fillMaxWidth().height(50.dp),
elevation = ButtonDefaults.elevation(
defaultElevation = 6.dp,
pressedElevation = 8.dp,
disabledElevation = 0.dp
)
) {
Text("Confirm")
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
Edit Amount Screen
Use to edit amount sale complete transaction
directory screen/transaction/edit_amount/EditAmount.kt
code
@Composable
fun EditAmountScreen(
context: Context?,
navController: NavHostController,
jsonData: JSONObject
) {
val popupPrintSlipCustomer = remember { mutableStateOf(false) }
val coroutineScope = rememberCoroutineScope()
val loading = remember { mutableStateOf(false) }
val textLoading = remember { mutableStateOf("") }
val errMessage = remember { mutableStateOf("") }
val errMessageOpenDialog = remember { mutableStateOf(false) }
val popUpContinue = remember { mutableStateOf(false) }
val isCloseButtonShowAlertMessage = remember { mutableStateOf(true) }
val handler = CoroutineExceptionHandler { _, exception ->
Log.e("Confirm Amount Display", exception.toString())
}
val countDownTimer = remember{ mutableStateOf("60") }
val preAmount = jsonData.getString("amount")
val amount = remember{ mutableStateOf(jsonData.getString("amount")) }
val rawAmount = remember{ mutableStateOf(jsonData.getString("amount").uppercase().replace(",","").replace(".","")) }
// Numpad Handler Function
val callback = { text: String ->
coroutineScope.launch(handler) {
editAmountHandleButtonClick(
context, text, rawAmount, amount, navController, jsonData, errMessage,
loading, textLoading, popupPrintSlipCustomer, popUpContinue
)
}
}
val timer = object: CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
countDownTimer.value = ((millisUntilFinished / 1000)).toString()
}
override fun onFinish() {
countDownTimer.value = "0"
navController.navigateUp()
}
}
LaunchedEffect(Unit) {
timer.start()
}
DisposableEffect(Unit) {
onDispose {
timer.cancel()
}
}
if (popupPrintSlipCustomer.value) {
AskPrintCustomerSlip(
openDialog = popupPrintSlipCustomer,
navController = navController,
jsonData = jsonData,
context = context!!,
)
}
if (loading.value) {
ShowLoading(
openDialog = loading,
text = textLoading,
)
}
if (errMessageOpenDialog.value) {
ShowAlertMessage(
description = errMessage,
openDialog = errMessageOpenDialog,
isCloseButton = isCloseButtonShowAlertMessage
)
}
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()) {
TransactionTitleBar(navController, countDownTimer, timer, jsonData.getString("transaction_type").uppercase().replace("_"," "))
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.wrapContentSize(Alignment.Center)
.padding(10.dp)
.fillMaxWidth(),
) {
Text(
fontWeight = FontWeight.Light,
fontSize = 12.sp,
color = MaterialTheme.colors.onSurface,
text = "PRE-AUTH AMOUNT",
textAlign = TextAlign.Center,
)
when {
preAmount.replace(",","").replace(".","").length < 6 -> {
Text(
text = preAmount,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colors.onSurface,
textAlign = TextAlign.Center,
fontSize = 60.sp,
)
}
preAmount.replace(",","").replace(".","").length < 8 -> {
Text(
text = preAmount,
fontWeight = FontWeight.Bold,
fontSize = 50.sp,
color = MaterialTheme.colors.onSurface,
textAlign = TextAlign.Center,
)
}
preAmount.replace(",","").replace(".","").length < 10 -> {
Text(
text = preAmount,
fontWeight = FontWeight.Bold,
fontSize = 40.sp,
color = MaterialTheme.colors.onSurface,
textAlign = TextAlign.Center,
)
}
preAmount.replace(",","").replace(".","").length < 12 -> {
Text(
text = preAmount,
fontWeight = FontWeight.Bold,
fontSize = 35.sp,
color = MaterialTheme.colors.onSurface,
textAlign = TextAlign.Center,
)
}
else -> {
Text(
text = preAmount,
fontWeight = FontWeight.Bold,
fontSize = 30.sp,
color = MaterialTheme.colors.onSurface,
textAlign = TextAlign.Center,
)
}
}
Text(
modifier = Modifier.padding(top = 10.dp),
fontWeight = FontWeight.Light,
fontSize = 12.sp,
color = MaterialTheme.colors.onSurface,
text = "CONFIRM AMOUNT",
textAlign = TextAlign.Center,
)
when {
rawAmount.value.length < 6 -> {
Text(
text = amount.value,
fontWeight = FontWeight.Bold,
color = CardColor,
textAlign = TextAlign.Center,
fontSize = 60.sp,
)
}
rawAmount.value.length < 8 -> {
Text(
text = amount.value,
fontWeight = FontWeight.Bold,
fontSize = 50.sp,
color = CardColor,
textAlign = TextAlign.Center,
)
}
rawAmount.value.length < 10 -> {
Text(
text = amount.value,
fontWeight = FontWeight.Bold,
fontSize = 40.sp,
color = CardColor,
textAlign = TextAlign.Center,
)
}
rawAmount.value.length < 12 -> {
Text(
text = amount.value,
fontWeight = FontWeight.Bold,
fontSize = 35.sp,
color = CardColor,
textAlign = TextAlign.Center,
)
}
else -> {
Text(
text = amount.value,
fontWeight = FontWeight.Bold,
fontSize = 30.sp,
color = CardColor,
textAlign = TextAlign.Center,
)
}
}
}
// Numpad Component
Numpad(callback)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
Numpad Component
Use to be numpad for edit number of money amount
code
@Composable
private fun Numpad(callback: (text: String) -> Any) {
Column(
verticalArrangement = Arrangement.Bottom,
modifier = Modifier
.fillMaxSize()
) {
NumpadRow(
listOf("1", "2", "3"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
NumpadRow(
listOf("4", "5", "6"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
NumpadRow(
listOf("7", "8", "9"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
NumpadRow(
listOf("⌫", "0", "✓"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
}
}
@Composable
private fun NumpadRow(
texts: List<String>,
weights: List<Float>,
callback: (text: String) -> Any
) {
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.Gray)
.padding(top = 5.dp, bottom = 5.dp)
) {
for (i in texts.indices) {
NumpadButton(
text = texts[i],
modifier = Modifier.weight(weights[i]),
callback = callback
)
}
}
}
@Composable
private fun NumpadButton(
text: String,
callback: (text: String) -> Any,
modifier: Modifier = Modifier
) {
TextButton(
modifier = modifier,
onClick = {
callback(text)
}
) {
Text(
color=Color.White,
text=text,
fontSize=30.sp
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
Numpad Handler Function
directory screen/transaction/edit_amount/controller.kt
code
suspend fun editAmountHandleButtonClick(
context: Context?,
txt: String,
rawAmount: MutableState<String>,
amount: MutableState<String>,
navController: NavHostController,
jsonData: JSONObject,
errMessage: MutableState<String>,
loading: MutableState<Boolean>,
textLoading: MutableState<String>,
popupPrintSlipCustomer: MutableState<Boolean>,
popUpContinue: MutableState<Boolean>,
) {
if (txt=="✓") {
val preAmount = jsonData.getString("amount").replace(",","").toDouble()
val newAmount = amount.value.replace(",","").toDouble()
val rateTolerances = 0.1
val minTolerances = preAmount * (1-rateTolerances)
val maxTolerances = preAmount * (1+rateTolerances)
if (rawAmount.value.length >= 3){
if (newAmount in minTolerances..maxTolerances) {
textLoading.value = "Preparing Data ..."
loading.value = true
jsonData.put("additional_amount", jsonData.getString("amount"))
jsonData.put("amount", amount.value)
// Function Online Transaction Of Menu Entry
val responeSaleComplete =
sendOnlineTransaction(
jsonData, context!!, errMessage, loading,
textLoading, popupPrintSlipCustomer, popUpContinue
)
}
else {
Toast.makeText(context,
"This amount must more than ${Utils().formatMoney(Utils().formatMoneyD2S(minTolerances))} " +
"and less than ${Utils().formatMoney(Utils().formatMoneyD2S(maxTolerances))}",
Toast.LENGTH_SHORT).show()
}
}
else {
Toast.makeText(context, "This amount is less than 1.00 baht", Toast.LENGTH_SHORT).show()
}
}
else if (txt=="⌫" && rawAmount.value.isNotEmpty()) {
rawAmount.value = rawAmount.value.dropLast(1)
amount.value = Utils().formatMoney(rawAmount.value)
}
else if (txt!="⌫" && txt!="✓" && rawAmount.value.length < 12 &&
!(txt=="0" && rawAmount.value=="0")) {
if (rawAmount.value=="0") {
rawAmount.value = txt
}
else{
rawAmount.value += txt
}
amount.value = Utils().formatMoney(rawAmount.value)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Enter Amount Screen
Use to enter money amount for transaction
directory screen/transaction/amount/Amount.kt
code
@Composable
fun AmountScreen(
context: Context?, navController: NavHostController,
transactionType: String, transactionTitle: String
) {
val countDownTimer = remember{ mutableStateOf("60") }
val amount = remember{ mutableStateOf("0.00") }
val rawAmount = remember{ mutableStateOf("") }
// Numpad Handler Function
val callback = { text: String ->
amountHandleButtonClick(
context, text, rawAmount, amount,
navController, transactionType, transactionTitle
)
}
val timer = object: CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
countDownTimer.value = ((millisUntilFinished / 1000)).toString()
}
override fun onFinish() {
countDownTimer.value = "0"
navController.popBackStack()
}
}
LaunchedEffect(Unit) {
timer.start()
}
DisposableEffect(Unit) {
onDispose {
timer.cancel()
}
}
Column(
modifier = Modifier.fillMaxHeight().fillMaxWidth()
) {
TransactionTitleBar(navController, countDownTimer, timer, transactionTitle.uppercase())
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.wrapContentSize(Alignment.Center)
.padding(10.dp)
.fillMaxWidth(),
) {
Text(
fontWeight = FontWeight.Light,
fontSize = 12.sp,
color = MaterialTheme.colors.onSurface,
text = "AMOUNT",
textAlign = TextAlign.Center,
)
when {
rawAmount.value.length < 6 -> {
Text(
text = amount.value,
fontWeight = FontWeight.Bold,
color = CardColor,
textAlign = TextAlign.Center,
fontSize = 60.sp,
)
}
rawAmount.value.length < 8 -> {
Text(
text = amount.value,
fontWeight = FontWeight.Bold,
fontSize = 50.sp,
color = CardColor,
textAlign = TextAlign.Center,
)
}
rawAmount.value.length < 10 -> {
Text(
text = amount.value,
fontWeight = FontWeight.Bold,
fontSize = 40.sp,
color = CardColor,
textAlign = TextAlign.Center,
)
}
rawAmount.value.length < 12 -> {
Text(
text = amount.value,
fontWeight = FontWeight.Bold,
fontSize = 35.sp,
color = CardColor,
textAlign = TextAlign.Center,
)
}
else -> {
Text(
text = amount.value,
fontWeight = FontWeight.Bold,
fontSize = 30.sp,
color = CardColor,
textAlign = TextAlign.Center,
)
}
}
}
// Numpad Component
Numpad(callback)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
Numpad Component
Use to be numpad for enter number of money amount
code
@Composable
private fun Numpad(callback: (text: String) -> Any) {
Column(
verticalArrangement = Arrangement.Bottom,
modifier = Modifier.fillMaxSize()
) {
NumpadRow(
listOf("1", "2", "3"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
NumpadRow(
listOf("4", "5", "6"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
NumpadRow(
listOf("7", "8", "9"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
NumpadRow(
listOf("⌫", "0", "✓"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
}
}
@Composable
private fun NumpadRow(
texts: List<String>,
weights: List<Float>,
callback: (text: String) -> Any
) {
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.Gray)
.padding(top = 5.dp, bottom = 5.dp)
) {
for (i in texts.indices) {
NumpadButton(
text = texts[i],
modifier = Modifier.weight(weights[i]),
callback = callback
)
}
}
}
@Composable
private fun NumpadButton(
text: String,
callback: (text: String) -> Any,
modifier: Modifier = Modifier
) {
TextButton(
modifier = modifier,
onClick = {
callback(text)
}
) {
Text(
color=Color.White,
text=text,
fontSize=30.sp
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Numpad Handler Function
directory screen/transaction/amount/controller.kt
code
fun amountHandleButtonClick(
context: Context?,
txt: String,
raw_amount: MutableState<String>,
amount: MutableState<String>,
navController: NavHostController,
transactionType: String,
transactionTitle: String
) {
if (txt=="✓") {
if (raw_amount.value.length >= 3){
val data="{" +
"title: \"$transactionTitle\"," +
"amount:\"${Utils().formatMoney(raw_amount.value)}\"," +
"transaction_type: \"$transactionType\"" +
"}"
val jsonData = JSONObject(data)
// go to Select Operation Screen
navController.navigate("${Route.Select.route}/$jsonData") {
popUpTo(Route.Home.route)
}
}
else {
Toast.makeText(context, "This amount is less than 1 baht", Toast.LENGTH_SHORT).show()
}
}
else if (txt=="⌫" && raw_amount.value.isNotEmpty()) {
raw_amount.value = raw_amount.value.dropLast(1)
amount.value = Utils().formatMoney(raw_amount.value)
}
else if (txt!="⌫" && txt!="✓" && raw_amount.value.length < 12 &&
!(txt=="0" && raw_amount.value=="0")) {
if (raw_amount.value=="0") {
raw_amount.value = txt
}
else{
raw_amount.value += txt
}
amount.value = Utils().formatMoney(raw_amount.value)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Enter Approve Code Screen
Use to enter approve code of offline sale transaction
directory screen/transaction/enter_approve_code/EnterApproveCode.kt
code
@Composable
fun EnterApproveCodeScreen(
context: Context?, navController: NavController, jsonData: JSONObject
) {
val popupPrintSlipCustomer = remember { mutableStateOf(false) }
val coroutineScope = rememberCoroutineScope()
val loading = remember { mutableStateOf(false) }
val textLoading = remember { mutableStateOf("") }
val errMessage = remember { mutableStateOf("") }
val errMessageOpenDialog = remember { mutableStateOf(false) }
val popUpContinue = remember { mutableStateOf(false) }
val isCloseButtonShowAlertMessage = remember { mutableStateOf(true) }
val handler = CoroutineExceptionHandler { _, exception ->
Log.e("Approve Code Display", exception.toString())
}
val countDownTimer = remember{ mutableStateOf("60") }
val approveCode = remember { mutableStateOf("") }
val isCorrect = remember { mutableStateOf(false) }
// Approve Code Comfirmation Function
val callback = {
coroutineScope.launch(handler) {
confirmEnterApproveCode(
approveCode, jsonData, navController, errMessage,
errMessageOpenDialog, context!!, popupPrintSlipCustomer, loading,
textLoading, popUpContinue, isCloseButtonShowAlertMessage
)
}
}
val timer = object: CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
countDownTimer.value = ((millisUntilFinished / 1000)).toString()
}
override fun onFinish() {
countDownTimer.value = "0"
navController.navigateUp()
}
}
if (popupPrintSlipCustomer.value) {
AskPrintCustomerSlip(
openDialog = popupPrintSlipCustomer,
navController = navController,
jsonData = jsonData,
context = context!!,
)
}
if (loading.value) {
ShowLoading(
openDialog = loading,
text = textLoading,
)
}
if (errMessageOpenDialog.value) {
ShowAlertMessage(
description = errMessage,
openDialog = errMessageOpenDialog,
isCloseButton = isCloseButtonShowAlertMessage
)
}
Column(
modifier = Modifier.fillMaxHeight().fillMaxWidth())
{
TransactionTitleBar(navController, countDownTimer, timer, jsonData.getString("transaction_type").uppercase().replace("_"," "))
// Input Approve Code Component
ApproveCodeTextField(approveCode, isCorrect, callback)
// Confirm Approve Code Button Component
ButtonConfirmEnterApproveCode(isCorrect, callback)
}
LaunchedEffect(Unit) {
timer.start()
}
DisposableEffect(Unit) {
onDispose {
timer.cancel()
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
Input Approve Code Component
Use to enter approve code
code
@Composable
private fun ApproveCodeTextField(
approveCode: MutableState<String>,
isCorrect: MutableState<Boolean>,
callback: () -> Any
) {
val (focusTextField) = remember { FocusRequester.createRefs() }
val keyboardTextField = LocalSoftwareKeyboardController.current
LaunchedEffect("") {
keyboardTextField?.show()
focusTextField.requestFocus()
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.wrapContentSize(Alignment.Center)
.fillMaxWidth()
.padding(20.dp)
) {
Text(
fontWeight = FontWeight.Light,
fontSize = 12.sp,
color = MaterialTheme.colors.onSurface,
text = "ENTER APPROVE CODE",
textAlign = TextAlign.Center,
)
OutlinedTextField(
modifier = Modifier.fillMaxWidth().padding(10.dp)
.focusRequester(focusTextField),
colors = TextFieldDefaults.textFieldColors(textColor = MaterialTheme.colors.onSurface),
value = approveCode.value,
onValueChange = { data: String ->
handleEnterApproveCode(data, approveCode, isCorrect)
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii),
keyboardActions = KeyboardActions(
onDone = { if (approveCode.value.isNotEmpty()) callback() }
),
placeholder = {
Text(text = "must be Aa-Zz or 0-9")
},
singleLine = true,
isError = !isCorrect.value
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Confirm Approve Code Button Component
Use to be confirm approve code button
code
@Composable
private fun ButtonConfirmEnterApproveCode(
isCorrect: MutableState<Boolean>,
callback: () -> Any
) {
Button(
enabled = isCorrect.value,
onClick = { callback() },
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
shape = RoundedCornerShape(50),
modifier = Modifier
.fillMaxWidth()
.padding(start = 35.dp, end = 35.dp)
.height(50.dp),
elevation = ButtonDefaults.elevation(
defaultElevation = 6.dp,
pressedElevation = 8.dp,
disabledElevation = 0.dp
)
) {
Text("Confirm")
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Approve Code Comfirmation Function
Use to confirm approve code of offline sale transaction
directory screen/transaction/enter_approve_code/controller.kt
code
suspend fun confirmEnterApproveCode(
approveCode: MutableState<String>,
jsonData: JSONObject,
navController: NavController,
errMessage: MutableState<String>,
errMessageOpenDialog: MutableState<Boolean>,
context: Context,
popupPrintSlipCustomer: MutableState<Boolean>,
loading: MutableState<Boolean>,
textLoading: MutableState<String>,
popUpContinue: MutableState<Boolean>,
isCloseButtonShowAlertMessage: MutableState<Boolean>
){
textLoading.value = "..."
loading.value = true
jsonData.put("approve_code",approveCode.value)
withContext(Dispatchers.Default) {
// Function Offline Transaction
saveOfflineTransaction(
jsonData, context, errMessage,
loading, textLoading, popupPrintSlipCustomer, popUpContinue
)
}
navController.popBackStack()
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Enter Password Pin Screen
Use to enter password pin before process menu entry transaction
directory screen/transaction/enter_password_pin/EnterPasswordPin.kt
code
@Composable
fun EnterPasswordPinScreen(
context: Context?, navController: NavHostController,
jsonData: JSONObject, route: String? = null
) {
val popupPrintSlipCustomer = remember { mutableStateOf(false) }
val coroutineScope = rememberCoroutineScope()
val loading = remember { mutableStateOf(false) }
val textLoading = remember { mutableStateOf("") }
val errMessage = remember { mutableStateOf("") }
val errMessageOpenDialog = remember { mutableStateOf(false) }
val popUpContinue = remember { mutableStateOf(false) }
val isCloseButtonShowAlertMessage = remember { mutableStateOf(true) }
val handler = CoroutineExceptionHandler { _, exception ->
Log.e("Confirm Amount Display", exception.toString())
}
val countDownTimer = remember{ mutableStateOf("60") }
val password = remember{ mutableStateOf("") }
val numberPassword = remember{ mutableStateOf(6) }
// Numpad Handler Function
val callback = { text: String ->
coroutineScope.launch(handler) {
enterPasswordPinHandleButtonClick(
context, text, numberPassword, password, navController, jsonData,
errMessage, loading, textLoading, popupPrintSlipCustomer,
popUpContinue, route
)
}
}
val timer = object: CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
countDownTimer.value = ((millisUntilFinished / 1000)).toString()
}
override fun onFinish() {
countDownTimer.value = "0"
navController.navigateUp()
}
}
LaunchedEffect(Unit) {
timer.start()
}
DisposableEffect(Unit) {
onDispose {
timer.cancel()
}
}
if (popupPrintSlipCustomer.value) {
AskPrintCustomerSlip(
openDialog = popupPrintSlipCustomer,
navController = navController,
jsonData = jsonData,
context = context!!,
)
}
if (loading.value) {
ShowLoading(
openDialog = loading,
text = textLoading,
)
}
if (errMessageOpenDialog.value) {
ShowAlertMessage(
description = errMessage,
openDialog = errMessageOpenDialog,
isCloseButton = isCloseButtonShowAlertMessage
)
}
Column(
modifier = Modifier.fillMaxHeight().fillMaxWidth()
) {
TransactionTitleBar(navController, countDownTimer, timer,
jsonData.getString("transaction_title").uppercase())
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(10.dp).fillMaxWidth(),
) {
Text(
fontWeight = FontWeight.Light,
fontSize = 12.sp,
text = "ENTER PASSWORD PIN",
modifier = Modifier.padding(top = 9.dp, bottom = 9.dp),
color = MaterialTheme.colors.onSurface,
textAlign = TextAlign.Center,
)
LazyVerticalGrid(
cells = GridCells.Fixed(numberPassword.value),
contentPadding = PaddingValues(1.dp),
modifier = Modifier.padding(top = 10.dp, start = 80.dp, end = 80.dp)
) {
items(numberPassword.value) { item ->
if (item >= password.value.length) {
Icon(Icons.Outlined.Circle, "Null", tint = MaterialTheme.colors.onSurface, modifier = Modifier.size(22.dp))
}
else{
Icon(Icons.Filled.Circle, "Filled", tint = MaterialTheme.colors.onSurface, modifier = Modifier.size(22.dp))
}
}
}
}
// Numpad Component
Numpad(callback)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
Numpad Component
Use to be numpad for enter password pin
code
@Composable
private fun Numpad(callback: (text: String) -> Any) {
Column(
verticalArrangement = Arrangement.Bottom,
modifier = Modifier
.fillMaxSize()
) {
NumpadRow(
listOf("1", "2", "3"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
NumpadRow(
listOf("4", "5", "6"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
NumpadRow(
listOf("7", "8", "9"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
NumpadRow(
listOf("", "0", "⌫"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
}
}
@Composable
private fun NumpadRow(
texts: List<String>,
weights: List<Float>,
callback: (text: String) -> Any
) {
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.Gray)
.padding(top = 5.dp, bottom = 5.dp)
) {
for (i in texts.indices) {
NumpadButton(
text = texts[i],
modifier = Modifier.weight(weights[i]),
callback = callback
)
}
}
}
@Composable
private fun NumpadButton(
text: String,
callback: (text: String) -> Any,
modifier: Modifier = Modifier
) {
TextButton(
modifier = modifier,
onClick = {
callback(text)
}
) {
Text(
color=Color.White,
text=text,
fontSize=30.sp
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
Numpad Handler Function
directory screen/transaction/enter_password_pin/controller.kt
code
suspend fun enterPasswordPinHandleButtonClick(
context: Context?,
txt: String,
numberPassword: MutableState<Int>,
password: MutableState<String>,
navController: NavHostController,
jsonData: JSONObject,
errMessage: MutableState<String>,
loading: MutableState<Boolean>,
textLoading: MutableState<String>,
popupPrintSlipCustomer: MutableState<Boolean>,
popUpContinue: MutableState<Boolean>,
route: String?
) {
if (txt=="⌫" && password.value.isNotEmpty()) {
password.value = password.value.dropLast(1)
}
else if (txt!="⌫" && txt!="" && password.value.length < numberPassword.value ) {
password.value += txt
if (password.value.length == numberPassword.value){
textLoading.value = "Checking Password..."
loading.value = true
if (checkPasswordApp(password.value)){
if (route != null) {
navController.navigate("$route/$jsonData") {
popUpTo(Route.Home.route)
}
}
else{
// Function Online Transaction Of Menu Entry
val responseTransaction =
sendOnlineTransaction(jsonData, context!!, errMessage, loading,
textLoading, popupPrintSlipCustomer, popUpContinue
)
}
}
else{
loading.value = false
Toast.makeText(context, "Password incorrect", Toast.LENGTH_SHORT).show()
password.value = ""
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Key-In Card Screen
Use to key in data of card information and confirm transaction
directory screen/transaction/key_in/KeyIn.kt
code
@Composable
fun KeyIn(context: Context?, navController: NavController, data: String) {
val jsonData = JSONObject(data)
val cardNumber = remember { mutableStateOf("") }
val month = remember { mutableStateOf("") }
val year = remember { mutableStateOf("") }
val cardError = remember { mutableStateOf(false) }
val monthError = remember { mutableStateOf(false) }
val yearError = remember { mutableStateOf(false) }
val countDownTimer = remember { mutableStateOf("60") }
val timer = object : CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
countDownTimer.value = ((millisUntilFinished / 1000)).toString()
}
override fun onFinish() {
countDownTimer.value = "0"
navController.popBackStack()
}
}
LaunchedEffect(Unit) {
timer.start()
}
DisposableEffect(Unit) {
onDispose {
timer.cancel()
}
}
Column(
modifier = Modifier.fillMaxSize()
) {
TransactionTitleBar(navController, countDownTimer, timer,
jsonData.getString("title").uppercase()
)
VirtualCard(cardNumber, month, year, cardError, monthError, yearError)
if (jsonData.getString("amount") != "") {
ShowAmount(jsonData.getString("amount"))
}
Spacer(Modifier.weight(1f))
ButtonSuccessConfirm(
context,
navController,
jsonData,
cardNumber,
month,
year,
cardError,
monthError,
yearError
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
Virtual Card Component
Use to be text field card informtion (card number, expire date)
code
@Composable
private fun VirtualCard(
card_number: MutableState<String>,
month: MutableState<String>,
year: MutableState<String>,
cardError: MutableState<Boolean>,
monthError: MutableState<Boolean>,
yearError: MutableState<Boolean>
) {
val (card_number_ref, month_ref, year_ref) = remember { FocusRequester.createRefs() }
val inputService = LocalSoftwareKeyboardController.current
val localFocusManager = LocalFocusManager.current
val utils = Utils()
LaunchedEffect("") {
delay(300)
inputService?.show()
card_number_ref.requestFocus()
}
Card(
backgroundColor = StaticColorText,
shape = RoundedCornerShape(10.dp),
modifier = Modifier
.padding(13.dp)
.padding(bottom = 10.dp),
elevation = 8.dp,
) {
Column(
modifier = Modifier.padding(15.dp)
) {
Text(
fontWeight = FontWeight.SemiBold,
text = "Card Number",
modifier = Modifier
.fillMaxWidth()
.padding(top = 5.dp),
fontSize = 15.sp,
color = MenuListTextDark,
letterSpacing = 2.sp,
)
Spacer(modifier = Modifier.height(5.dp))
OutlinedTextField(
modifier = Modifier
.padding(0.dp)
.focusRequester(card_number_ref)
.onKeyEvent {
if (it.nativeKeyEvent.keyCode == KeyEvent.KEYCODE_ENTER) {
month_ref.requestFocus()
}
false
},
value = card_number.value,
onValueChange = {
if (it.length <= 19) {
card_number.value = it
if (it.length < 13) {
cardError.value = true
} else {
when (utils.cardIsValid(it)) {
false -> cardError.value = true
true -> cardError.value = false
}
}
}
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
placeholder = { Text("xxxx xxxx xxxx xxxx xxx") },
singleLine = true,
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = Color.White
),
keyboardActions = KeyboardActions(
onDone = { month_ref.requestFocus() }
),
isError = cardError.value
)
Spacer(modifier = Modifier.height(15.dp))
Text(
fontWeight = FontWeight.SemiBold,
text = "EXPIRES",
modifier = Modifier
.fillMaxWidth()
.focusRequester(card_number_ref)
.padding(top = 5.dp),
fontSize = 15.sp,
color = MenuListTextDark,
letterSpacing = 2.sp,
)
Row {
OutlinedTextField(
modifier = Modifier
.padding(0.dp)
.focusRequester(month_ref)
.width(100.dp)
.onKeyEvent {
if (it.nativeKeyEvent.keyCode == KeyEvent.KEYCODE_ENTER) {
year_ref.requestFocus()
}
false
},
value = month.value,
onValueChange = { data ->
if (data.length <= 2) {
month.value = data
if (data.length < 2) {
monthError.value = true
} else {
val monthCheck = listOf(
"01", "02", "03", "04", "05", "06",
"07", "08", "09", "10", "11", "12"
)
monthError.value = monthCheck.none { it == data }
}
}
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
label = { Text("Month") },
placeholder = { Text("xx") },
singleLine = true,
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = Color.White
),
keyboardActions = KeyboardActions(
onDone = { year_ref.requestFocus() }
),
isError = monthError.value
)
OutlinedTextField(
modifier = Modifier
.padding(start = 30.dp)
.focusRequester(year_ref)
.width(100.dp),
value = year.value,
onValueChange = { data ->
if (data.length <= 2) {
year.value = data
if (data.length < 2) {
yearError.value = true
} else {
val nowYear = Calendar.getInstance().get(Calendar.YEAR) % 100
Log.d("test", nowYear.toString())
Log.d("test", (data.toInt() >= nowYear).toString())
yearError.value = when (data.toInt() >= nowYear) {
true -> false
false -> true
}
}
}
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
label = { Text("Year") },
placeholder = { Text("xx") },
singleLine = true,
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = Color.White
),
keyboardActions = KeyboardActions(
onDone = {
inputService?.hide()
localFocusManager.clearFocus()
}
),
isError = yearError.value
)
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
Display Amount Component
Use to display amount of transaction
code
@Composable
private fun ShowAmount(amount: String) {
Column(
modifier = Modifier.padding(top = 10.dp, start = 10.dp, end = 10.dp)
) {
Text(
fontSize = 15.sp,
text = "AMOUNT",
color = MaterialTheme.colors.onSurface,
modifier = Modifier.padding(5.dp)
)
Divider()
Column(
horizontalAlignment = Alignment.End,
modifier = Modifier
.padding(10.dp)
.fillMaxWidth(),
) {
Row(
modifier = Modifier.padding(top = 9.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
modifier = Modifier.padding(end = 5.dp),
fontWeight = FontWeight.Bold,
fontSize = 20.sp,
text = "฿",
color = if (MaterialTheme.colors.isLight) MainText else MainTextDark
)
Text(
overflow = TextOverflow.Clip,
text = amount,
color = StaticColorText,
fontFamily = Prompt,
fontWeight = FontWeight.Bold,
fontSize = 30.sp,
)
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Confirm Button Component
Use to display confirm transaction button
code
@Composable
private fun ButtonSuccessConfirm(
context: Context?, navController: NavController,
dataJson: JSONObject,
card_number: MutableState<String>,
month: MutableState<String>,
year: MutableState<String>,
cardError: MutableState<Boolean>,
monthError: MutableState<Boolean>,
yearError: MutableState<Boolean>
) {
val checkErrorToContinue = remember { mutableStateOf(false) }
val messageErrorToContinue = remember { mutableStateOf("") }
val hasError = remember { mutableStateOf(false)}
val description = remember { mutableStateOf("")}
val beeper: UBeeper = DeviceHelper.me().beeper
val led: ULed = DeviceHelper.me().getLed(RFDeviceName.INNER)
if (hasError.value) {
beeper.startBeep(500)
led.turnOn(Light.RED);
ShowAlertMessage(
description = description,
openDialog = hasError,
navController = navController
)
if (!hasError.value) {
led.turnOff(Light.RED);
}
}
if (!hasError.value) {
led.turnOff(Light.GREEN);
}
Column(modifier = Modifier
.padding(20.dp)
.fillMaxWidth()) {
Button(
onClick = {
// Key In Confirmation Function
confirmKeyIn(
context,
navController,
dataJson,
card_number,
month,
year,
cardError,
monthError,
yearError,
checkErrorToContinue,
messageErrorToContinue,
hasError,
description
)
if (checkErrorToContinue.value) {
Toast.makeText(context, messageErrorToContinue.value, Toast.LENGTH_SHORT).show()
}
},
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
shape = RoundedCornerShape(50),
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
elevation = ButtonDefaults.elevation(
defaultElevation = 6.dp,
pressedElevation = 8.dp,
disabledElevation = 0.dp
)
) {
Text("Continue")
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
Key In Confirmation Function
Use to confirm card information from key-in for card entry transaction
directory screen/transaction/key_in/controller.kt
code
fun confirmKeyIn(
context: Context?,
navController: NavController,
jsonData: JSONObject,
card_number: MutableState<String>,
month: MutableState<String>,
year: MutableState<String>,
cardError: MutableState<Boolean>,
monthError: MutableState<Boolean>,
yearError: MutableState<Boolean>,
checkErrorToContinue: MutableState<Boolean>,
messageErrorToContinue: MutableState<String>,
hasError: MutableState<Boolean>,
description: MutableState<String>
) {
val getCurrentMonth = Calendar.getInstance().get(Calendar.MONTH) + 1
val getCurrentYear = Calendar.getInstance().get(Calendar.YEAR) % 100
if (card_number.value == "" || month.value == "" || year.value == "") {
messageErrorToContinue.value = "Please check empty field"
cardError.value = true
monthError.value = true
yearError.value = true
checkErrorToContinue.value = true
} else if (cardError.value || monthError.value || yearError.value) {
messageErrorToContinue.value = "Please check error field"
checkErrorToContinue.value = true
} else {
if ( year.value.toInt() <= getCurrentYear) {
if (month.value.toInt() <= getCurrentMonth) {
messageErrorToContinue.value = "Card is expire"
monthError.value = true
yearError.value = true
checkErrorToContinue.value = true
} else {
checkErrorToContinue.value = false
}
} else {
checkErrorToContinue.value = false
}
}
if (!checkErrorToContinue.value) {
checkErrorToContinue.value = false
val cardData = selectCardData(card_number.value)
if (cardData != null) {
val cardControl = getCardControl(cardData.card_control_record_index!!,
jsonData.getString("transaction_type"))
if (cardControl != null) {
if (cardControl.checkAllow(jsonData.getString("transaction_type"))!!) {
jsonData.put("card_exp", year.value + month.value)
jsonData.put("card_number", card_number.value)
jsonData.put("card_label", cardData.card_label)
jsonData.put("card_scheme_type", cardData.card_scheme_type)
jsonData.put("pan_masking", cardControl.pan_masking)
jsonData.put("card_record_index", cardData.card_record_index)
jsonData.put("host_record_index", cardData.host_record_index)
jsonData.put("operation", "key_in")
// go to Card Display Screen
navController.navigate(Route.CardDisplay.route + "/$jsonData") {
popUpTo(Route.Home.route)
}
} else {
hasError.value = true
description.value = "Not allow to ${jsonData.getString("transaction_type")}"
}
}
else{
hasError.value = true
description.value = "Not found card control"
}
}
else{
hasError.value = true
description.value = "Card not support"
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
Search Transaction Screen
Use to enter trace invoice to serach tranasaction directory screen/transaction/search_transaction/SearchTransaction.kt
code
@Composable
fun SearchTransactionScreen(
context: Context?, navController: NavHostController,
transactionType: String, transactionTitle: String
) {
val popupPrintSlipCustomer = remember { mutableStateOf(false) }
val coroutineScope = rememberCoroutineScope()
val loading = remember { mutableStateOf(false) }
val textLoading = remember { mutableStateOf("") }
val errMessage = remember { mutableStateOf("") }
val errMessageOpenDialog = remember { mutableStateOf(false) }
val popUpContinue = remember { mutableStateOf(false) }
val isCloseButtonShowAlertMessage = remember { mutableStateOf(true) }
val handler = CoroutineExceptionHandler { _, exception ->
Log.e("Confirm Amount Display", exception.toString())
}
val countDownTimer = remember{ mutableStateOf("60") }
val invoice = remember{ mutableStateOf("0") }
// Numpad Handler Function
val callback = { text: String ->
coroutineScope.launch(handler) {
searchTransacitionButtonClick(context, text, invoice, navController,
transactionType, transactionTitle, errMessage, loading, textLoading
)
}
}
val timer = object: CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
countDownTimer.value = ((millisUntilFinished / 1000)).toString()
}
override fun onFinish() {
countDownTimer.value = "0"
navController.popBackStack()
}
}
LaunchedEffect(Unit) {
timer.start()
}
DisposableEffect(Unit) {
onDispose {
timer.cancel()
}
}
if (loading.value) {
ShowLoading(
openDialog = loading,
text = textLoading,
)
}
if (errMessageOpenDialog.value) {
ShowAlertMessage(
description = errMessage,
openDialog = errMessageOpenDialog,
isCloseButton = isCloseButtonShowAlertMessage
)
}
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()) {
TransactionTitleBar(navController, countDownTimer, timer, transactionTitle.uppercase())
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.wrapContentSize(Alignment.Center)
.padding(10.dp)
.fillMaxWidth(),
) {
Text(
fontWeight = FontWeight.Light,
fontSize = 12.sp,
color = MaterialTheme.colors.onSurface,
text = "ENTER TRACE INVOICE",
textAlign = TextAlign.Center,
)
Text(
text = invoice.value,
fontWeight = FontWeight.Bold,
color = CardColor,
textAlign = TextAlign.Center,
fontSize = 60.sp,
)
}
// Numpad Component
Numpad(callback)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
Numpad Component
Use to be numpad for enter trace invoice
code
@Composable
private fun Numpad(callback: (text: String) -> Any) {
Column(
verticalArrangement = Arrangement.Bottom,
modifier = Modifier
.fillMaxSize()
) {
NumpadRow(
listOf("1", "2", "3"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
NumpadRow(
listOf("4", "5", "6"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
NumpadRow(
listOf("7", "8", "9"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
NumpadRow(
listOf("⌫", "0", "✓"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
}
}
@Composable
private fun NumpadRow(
texts: List<String>,
weights: List<Float>,
callback: (text: String) -> Any
) {
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.Gray)
.padding(top = 5.dp, bottom = 5.dp)
) {
for (i in texts.indices) {
NumpadButton(
text = texts[i],
modifier = Modifier.weight(weights[i]),
callback = callback
)
}
}
}
@Composable
private fun NumpadButton(
text: String,
callback: (text: String) -> Any,
modifier: Modifier = Modifier
) {
TextButton(
modifier = modifier,
onClick = {
callback(text)
}
) {
Text(
color=Color.White,
text=text,
fontSize=30.sp
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
Numpad Handler Function
directory screen/transaction/search_transaction/controller.kt
code
fun searchTransacitionButtonClick(
context: Context?,
txt: String,
invoice: MutableState<String>,
navController: NavHostController,
transactionType: String,
transactionTitle: String,
errMessage: MutableState<String>,
loading: MutableState<Boolean>,
textLoading: MutableState<String>,
) {
if (txt=="✓") {
if (invoice.value != "0"){
textLoading.value = "Searching Transaction..."
loading.value = true
val transaction = searchTransaction(invoice.value)
if (transaction != null) {
textLoading.value = "Checking Transaction..."
if (checkAllowMenuEntryTransaction(transactionType, transaction.txn_type!!)
|| transactionTitle=="reprint"
){
val jsonData = if (transactionTitle=="reprint") transactionToJson(transaction.txn_type!!, transaction)
else transactionToJson(transactionType, transaction)
val cardData = selectCardData(jsonData.getString("card_number"))
val cardControl = getCardControl(transaction.card_record_index!!, transaction.txn_type!!)
if (cardData != null && cardControl != null) {
jsonData.put("title", transactionTitle)
jsonData.put("menu_entry_txn", transactionType)
jsonData.put("card_label", cardData.card_label)
jsonData.put("card_scheme_type", cardData.card_scheme_type)
jsonData.put("pan_masking", cardControl.pan_masking)
jsonData.put("host_record_index", cardData.host_record_index!!)
jsonData.put("card_number_mask", transaction.card_number)
// go to Transaction Display Screen
navController.navigate("${Route.TransactionDisplay.route}/$jsonData") {
popUpTo(Route.Home.route)
}
}
else{
Toast.makeText(context, "Get transaction data fail", Toast.LENGTH_SHORT).show()
}
}
else{
loading.value = false
Toast.makeText(context, "Transacton at invoice ${invoice.value} can't $transactionType", Toast.LENGTH_SHORT).show()
}
}
else{
loading.value = false
Toast.makeText(context, "Not found invoice ${invoice.value}", Toast.LENGTH_SHORT).show()
}
}
else {
loading.value = false
Toast.makeText(context, "This invoice must more than 0", Toast.LENGTH_SHORT).show()
}
}
else if (txt=="⌫" && invoice.value.isNotEmpty()) {
if (invoice.value.length == 1){
invoice.value = "0"
}
else {
invoice.value = invoice.value.dropLast(1)
}
}
else if (txt!="⌫" && txt!="✓" && invoice.value.length < 9 ){
if (invoice.value == "0"){
invoice.value = txt
}
else {
invoice.value += txt
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
Select Operation Screen
Use to select operation for transaction (Card/QR)
directory screen/transaction/select/Select.kt
code
@Composable
fun SelectOperation(navController: NavController, data: String) {
val jsonData = JSONObject(data)
val countDownTimer = remember { mutableStateOf("60") }
val timer = object : CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
countDownTimer.value = ((millisUntilFinished / 1000)).toString()
}
override fun onFinish() {
countDownTimer.value = "0"
navController.popBackStack()
}
}
LaunchedEffect(Unit) {
timer.start()
}
DisposableEffect(Unit) {
onDispose {
timer.cancel()
}
}
Column(
modifier = Modifier.fillMaxSize()
) {
TitleSelecOperation(navController, countDownTimer, timer, jsonData)
Spacer(Modifier.height(10.dp))
Column(
modifier = Modifier.padding(start = 20.dp, end = 20.dp)
) {
// Select Operation Button Component
SelectOperationButton(
navController, Route.WaitOperation.route,
"CARD", "Credir Card / Debit Card",
R.raw.credit_card, jsonData
)
Spacer(Modifier.height(10.dp))
// Select Operation Button Component
SelectOperationButton(
navController, "",
"QR Code", "THAI QR, Credit QR, Alipay, WeChat",
R.raw.qr, jsonData
)
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Select Operation Button Component
Use to display selection of operation for transaction process
code
@Composable
fun SelectOperationButton(
navController: NavController, route: String,
title: String, subtitle: String, rawAnimate: Int,
jsonData: JSONObject
) {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(rawAnimate))
val progress by animateLottieCompositionAsState(
composition = composition
)
Card(
backgroundColor = CardColor,
shape = RoundedCornerShape(10.dp),
modifier = Modifier
.fillMaxWidth()
.height(120.dp),
elevation = 8.dp,
) {
Box(modifier = Modifier
.clickable {
if (route!="") {
// go to another screen
navController.navigate("$route/$jsonData") {
popUpTo(Route.Home.route)
}
}
}) {
Row(
Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Column(
modifier = Modifier
.fillMaxHeight()
.padding(start = 20.dp),
verticalArrangement = Arrangement.Center
) {
Text(
text = "Sale by",
color = Color.White,
fontWeight = FontWeight.Black,
fontSize = 12.sp
)
Spacer(modifier = Modifier.height(10.dp))
Text(
text = title,
color = Color.Black,
fontWeight = FontWeight.SemiBold,
fontSize = 20.sp
)
Text(
text = subtitle, // "Credir Card / Debit Card",
color = Color.White,
fontWeight = FontWeight.SemiBold,
fontSize = 12.sp
)
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(end = 20.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.End
) {
LottieAnimation(
composition,
progress,
modifier = Modifier.size(100.dp)
)
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
Tip Adjust Screen
Use to enter tip amount for tip adjust transaction
directory screen/transaction/tip_adjust/TipAdjust.kt
code
@Composable
fun TipAmountScreen(
context: Context?, navController: NavHostController, jsonData: JSONObject
) {
val popupPrintSlipCustomer = remember { mutableStateOf(false) }
val coroutineScope = rememberCoroutineScope()
val loading = remember { mutableStateOf(false) }
val textLoading = remember { mutableStateOf("") }
val errMessage = remember { mutableStateOf("") }
val errMessageOpenDialog = remember { mutableStateOf(false) }
val popUpContinue = remember { mutableStateOf(false) }
val isCloseButtonShowAlertMessage = remember { mutableStateOf(true) }
val handler = CoroutineExceptionHandler { _, exception ->
Log.e("Tip Amount Display", exception.toString())
}
val countDownTimer = remember{ mutableStateOf("60") }
val tipAmount = remember{ mutableStateOf("0.00") }
val rawTipAmount = remember{ mutableStateOf("0") }
// Numpad Handler Function
val callback = { text: String ->
coroutineScope.launch(handler) {
tipAmountHandleButtonClick(
context, text, rawTipAmount, tipAmount, navController, jsonData,
errMessage, loading, textLoading,
popupPrintSlipCustomer, popUpContinue
)
}
}
val timer = object: CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
countDownTimer.value = ((millisUntilFinished / 1000)).toString()
}
override fun onFinish() {
countDownTimer.value = "0"
navController.navigateUp()
}
}
LaunchedEffect(Unit) {
timer.start()
}
DisposableEffect(Unit) {
onDispose {
timer.cancel()
}
}
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()) {
TransactionTitleBar(navController, countDownTimer, timer, jsonData.getString("transaction_type").uppercase().replace("_"," "))
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.wrapContentSize(Alignment.Center)
.padding(10.dp)
.fillMaxWidth(),
) {
Text(
modifier = Modifier.padding(top = 10.dp),
fontWeight = FontWeight.Light,
fontSize = 12.sp,
color = MaterialTheme.colors.onSurface,
text = "TIP AMOUNT",
textAlign = TextAlign.Center,
)
when {
rawTipAmount.value.length < 6 -> {
Text(
text = tipAmount.value,
fontWeight = FontWeight.Bold,
color = CardColor,
textAlign = TextAlign.Center,
fontSize = 60.sp,
)
}
rawTipAmount.value.length < 8 -> {
Text(
text = tipAmount.value,
fontWeight = FontWeight.Bold,
fontSize = 50.sp,
color = CardColor,
textAlign = TextAlign.Center,
)
}
rawTipAmount.value.length < 10 -> {
Text(
text = tipAmount.value,
fontWeight = FontWeight.Bold,
fontSize = 40.sp,
color = CardColor,
textAlign = TextAlign.Center,
)
}
rawTipAmount.value.length < 12 -> {
Text(
text = tipAmount.value,
fontWeight = FontWeight.Bold,
fontSize = 35.sp,
color = CardColor,
textAlign = TextAlign.Center,
)
}
else -> {
Text(
text = tipAmount.value,
fontWeight = FontWeight.Bold,
fontSize = 30.sp,
color = CardColor,
textAlign = TextAlign.Center,
)
}
}
}
// Numpad Component
Numpad(callback)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
Numpad Component
Use to be numpad for enter number of tip amount
code
@Composable
private fun Numpad(callback: (text: String) -> Any) {
Column(
verticalArrangement = Arrangement.Bottom,
modifier = Modifier.fillMaxSize()
) {
NumpadRow(
listOf("1", "2", "3"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
NumpadRow(
listOf("4", "5", "6"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
NumpadRow(
listOf("7", "8", "9"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
NumpadRow(
listOf("⌫", "0", "✓"),
listOf(0.33f, 0.34f, 0.33f),
callback
)
}
}
@Composable
private fun NumpadRow(
texts: List<String>,
weights: List<Float>,
callback: (text: String) -> Any
) {
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.Gray)
.padding(top = 5.dp, bottom = 5.dp)
) {
for (i in texts.indices) {
NumpadButton(
text = texts[i],
modifier = Modifier.weight(weights[i]),
callback = callback
)
}
}
}
@Composable
private fun NumpadButton(
text: String,
callback: (text: String) -> Any,
modifier: Modifier = Modifier
) {
TextButton(
modifier = modifier,
onClick = {
callback(text)
}
) {
Text(
color=Color.White,
text=text,
fontSize=30.sp
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Numpad Handler Function
directory screen/transaction/tip_adjust/controller.kt
code
fun tipAmountHandleButtonClick(
context: Context?,
txt: String,
rawTipAmount: MutableState<String>,
tipAmount: MutableState<String>,
navController: NavController,
jsonData: JSONObject,
errMessage: MutableState<String>,
loading: MutableState<Boolean>,
textLoading: MutableState<String>,
popupPrintSlipCustomer: MutableState<Boolean>,
popUpContinue: MutableState<Boolean>,
) {
if (txt=="✓") {
val originalAmount = jsonData.getDouble("amount")
val totalAmount = originalAmount+tipAmount.value.toDouble()
if (tipAmount.value.toDouble() < 1) {
Toast.makeText(context, "This amount is less than 1 baht", Toast.LENGTH_SHORT).show()
}
else if (totalAmount >= 1 && totalAmount < 10000000000){
jsonData.put("original_amount",Utils().formatMoney(Utils().formatMoneyD2S(originalAmount)))
jsonData.put("additional_amount",tipAmount.value)
jsonData.put("amount",Utils().formatMoney(Utils().formatMoneyD2S(totalAmount)))
// go to Tip Adjust Confirmaion Screen
navController.navigate("${Route.ConfirmTipAdjust.route}/$jsonData") {
popUpTo(Route.Home.route)
}
}
else if (totalAmount < 10000000000){
Toast.makeText(context, "Max tip amount is less than " +
Utils().formatMoney(Utils().formatMoneyD2S(10000000000-originalAmount)) +
" baht", Toast.LENGTH_SHORT).show()
}
}
else if (txt=="⌫" && rawTipAmount.value.isNotEmpty()) {
rawTipAmount.value = rawTipAmount.value.dropLast(1)
tipAmount.value = Utils().formatMoney(rawTipAmount.value)
}
else if (txt!="⌫" && txt!="✓" && rawTipAmount.value.length < 12 &&
!(txt=="0" && rawTipAmount.value=="0")) {
if (rawTipAmount.value=="0") {
rawTipAmount.value = txt
}
else{
rawTipAmount.value += txt
}
tipAmount.value = Utils().formatMoney(rawTipAmount.value)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Tip Adjust Confirmaion Screen
Use to confirm tip amount of tip adjust transaction
directory screen/transaction/tip_adjust/ConfirmTipAdjust.kt
code
@Composable
fun ConfirmTipAmountScreen(
context: Context?, navController: NavHostController, jsonData: JSONObject
) {
val countDownTimer = remember{ mutableStateOf("60") }
val originalAmount = jsonData.getString("original_amount")
val tipAmount = jsonData.getString("additional_amount")
val totalAmount = jsonData.getString("amount")
val timer = object: CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
countDownTimer.value = ((millisUntilFinished / 1000)).toString()
}
override fun onFinish() {
countDownTimer.value = "0"
navController.navigateUp()
}
}
LaunchedEffect(Unit) {
timer.start()
}
DisposableEffect(Unit) {
onDispose {
timer.cancel()
}
}
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()) {
TransactionTitleBar(navController, countDownTimer, timer, jsonData.getString("transaction_type").uppercase().replace("_"," "))
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.wrapContentSize(Alignment.Center)
.padding(10.dp)
.fillMaxWidth(),
) {
// Display Amount Component
DisplayAmount("Original Amount",originalAmount,MaterialTheme.colors.onSurface,50)
DisplayAmount("Tip Amount",tipAmount,MaterialTheme.colors.onSurface,50)
DisplayAmount("Total Amount",totalAmount,CardColor,60)
}
Spacer(Modifier.weight(1f))
// Confirm Tip Adjust Button Component
ButtonSuccessConfirm(jsonData, navController, context!!)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
Display Amount Component
Use to display amount of transaction
code
@Composable
private fun DisplayAmount(title: String, amount: String, color: Color, size: Int){
val rawAmount = amount.replace(",","").replace(".","")
Text(
fontWeight = FontWeight.Light,
fontSize = 12.sp,
color = MaterialTheme.colors.onSurface,
text = title,
textAlign = TextAlign.Center,
modifier = Modifier.padding(5.dp)
)
when {
rawAmount.length < 6 -> {
Text(
text = amount,
fontWeight = FontWeight.Bold,
color = color,
textAlign = TextAlign.Center,
fontSize = size.sp,
)
}
rawAmount.length < 8 -> {
Text(
text = amount,
fontWeight = FontWeight.Bold,
fontSize = (size-10).sp,
color = color,
textAlign = TextAlign.Center,
)
}
rawAmount.length < 10 -> {
Text(
text = amount,
fontWeight = FontWeight.Bold,
fontSize = (size-20).sp,
color = color,
textAlign = TextAlign.Center,
)
}
rawAmount.length < 12 -> {
Text(
text = amount,
fontWeight = FontWeight.Bold,
fontSize = (size-25).sp,
color = color,
textAlign = TextAlign.Center,
)
}
else -> {
Text(
text = amount,
fontWeight = FontWeight.Bold,
fontSize = (size-30).sp,
color = color,
textAlign = TextAlign.Center,
)
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Confirm Button Component
Use to be confirm tip adjust button
code
@Composable
private fun ButtonSuccessConfirm(
jsonData: JSONObject,
navController: NavController,
context: Context
) {
val popupPrintSlipCustomer = remember { mutableStateOf(false) }
val coroutineScope = rememberCoroutineScope()
val loading = remember { mutableStateOf(false) }
val textLoading = remember { mutableStateOf("") }
val errMessage = remember { mutableStateOf("") }
val errMessageOpenDialog = remember { mutableStateOf(false) }
val popUpBalanceInquiry = remember { mutableStateOf(false) }
val balanceInquiryTitle = remember { mutableStateOf("") }
val balanceInquiryAmount = remember { mutableStateOf("") }
val popUpContinue = remember { mutableStateOf(false) }
val isCloseButtonShowAlertMessage = remember { mutableStateOf(false) }
val handler = CoroutineExceptionHandler { _, exception ->
Log.e("Tip Adjust", exception.message.toString())
}
if (popupPrintSlipCustomer.value) {
AskPrintCustomerSlip(
openDialog = popupPrintSlipCustomer,
navController = navController,
jsonData = jsonData,
context = context,
)
}
if (loading.value) {
ShowLoading(
openDialog = loading,
text = textLoading,
)
}
if (errMessageOpenDialog.value) {
ShowAlertMessage(
description = errMessage,
openDialog = errMessageOpenDialog,
isCloseButton = isCloseButtonShowAlertMessage
)
}
if (popUpBalanceInquiry.value) {
ShowInquiryMessage(
title = balanceInquiryTitle,
amount = balanceInquiryAmount,
openDialog = popUpBalanceInquiry,
navController = navController,
)
}
Column(
modifier = Modifier
.padding(20.dp)
.fillMaxWidth()
) {
Button(
onClick = {
loading.value = true
coroutineScope.launch(handler) {
confirmTipAmountButtonClick(
context, navController, jsonData, errMessage, loading,
textLoading, popupPrintSlipCustomer, popUpContinue
)
}
},
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
shape = RoundedCornerShape(50),
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
elevation = ButtonDefaults.elevation(
defaultElevation = 6.dp,
pressedElevation = 8.dp,
disabledElevation = 0.dp
)
) {
Text("Confirm")
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
Tip Adjust Comfirmation Function
Use to confirm tip adjust transaction
directory screen/transaction/tip_adjust/controller.kt
code
suspend fun confirmTipAmountButtonClick(
context: Context?,
navController: NavController,
jsonData: JSONObject,
errMessage: MutableState<String>,
loading: MutableState<Boolean>,
textLoading: MutableState<String>,
popupPrintSlipCustomer: MutableState<Boolean>,
popUpContinue: MutableState<Boolean>,
) {
// Function Online Transaction Of Menu Entry
val responeSaleComplete = sendOnlineTransaction(jsonData, context!!, errMessage, loading,
textLoading, popupPrintSlipCustomer, popUpContinue
)
navController.popBackStack()
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Transaction Display Screen
Use to display information of menu entry transaction
directory screen/transaction/transaction_display/TransactionDisplay.kt
code
@Composable
fun TransactionDisplay(navController: NavHostController, data: String, context: Context) {
val jsonData = JSONObject(data)
val countDownTimer = remember { mutableStateOf("60") }
val timer = object : CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
countDownTimer.value = ((millisUntilFinished / 1000)).toString()
}
override fun onFinish() {
countDownTimer.value = "0"
navController.popBackStack()
}
}
LaunchedEffect(Unit) {
timer.start()
}
DisposableEffect(Unit) {
onDispose {
timer.cancel()
}
}
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()
) {
TransactionTitleBar(
navController, countDownTimer, timer,
jsonData.getString("title").uppercase(),
)
// Transaction Display Card Component
DetailTransaction(jsonData)
Spacer(Modifier.weight(1f))
// Confirm Entry Menu Transaction Button Component
ButtonConfirm(jsonData, jsonData.getString("title"), navController, context)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Transaction Display Card Component
Use to be card for display transaction information
code
@Composable
private fun DetailTransaction(jsonData: JSONObject) {
val date = remember { mutableStateOf("") }
val time = remember { mutableStateOf("") }
date.value = Utils().convertToDate(jsonData.getString("date"))
time.value = Utils().convertToTime(jsonData.getString("time"))
Card(
backgroundColor = StaticColorText,
shape = RoundedCornerShape(10.dp),
modifier = Modifier.padding(13.dp),
elevation = 8.dp,
) {
Column(
modifier = Modifier.padding(15.dp).padding(top = 10.dp, bottom = 10.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Column() {
Row(
modifier = Modifier
.fillMaxWidth()
) {
Spacer(Modifier.weight(1f))
Icon(Icons.Filled.EventNote, "date-time", tint = MaterialTheme.colors.onSurface)
Text(
fontWeight = FontWeight.Normal,
text = "${date.value} - ${time.value}",
modifier = Modifier.padding(top = 2.dp),
fontSize = 12.sp,
color = if (MaterialTheme.colors.isLight) MainText else MainTextDark
)
}
// Card Detail Display Component
CardDetail(jsonData.getString("card_scheme_type"),jsonData.getString("card_number_mask"))
// Tranasction Detail Display Component
SubDetailTransaction("Transaction: ",jsonData.getString("transaction_type").replace("_"," ").uppercase())
SubDetailTransaction("Amount: ",jsonData.getString("amount"))
SubDetailTransaction("Invoice: ",jsonData.getString("invoice"))
SubDetailTransaction("STAN: ",jsonData.getString("stan"))
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Card Detail Display Component
Use to display card details (logo, card number)
code
@Composable
private fun CardDetail(cardScheme: String, cardNumber: String){
Row(
modifier = Modifier
.padding(top = 10.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Text(
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
text = "Card: ",
color = if (MaterialTheme.colors.isLight) MainText else MainTextDark
)
Spacer(Modifier.weight(1f))
val checkCardBrand =
when (cardScheme.lowercase(Locale.getDefault())) {
"visa card" -> R.drawable.ic_visa_inc_small
"mastercard" -> R.drawable.ic_mastercard_logo_small
else -> R.drawable.ic_coin_small
}
Image(
painterResource(checkCardBrand),
cardScheme,
contentScale = ContentScale.Inside,
modifier = Modifier.size(30.dp)
)
Text(
fontWeight = FontWeight.Medium,
fontSize = 18.sp,
text = cardNumber,
modifier = Modifier.padding(start = 2.dp),
color = MaterialTheme.colors.onSurface
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Tranasction Detail Display Component
Use to display transacton details (transaction type, amount, trace invoice, STAN)
code
@Composable
private fun SubDetailTransaction(title: String, content: String){
Row(
modifier = Modifier
.padding(top = 10.dp)
.fillMaxWidth()
) {
Text(
fontWeight = FontWeight.Bold,
fontSize = 16.sp,
text = title,
modifier = Modifier.padding(top = 9.dp),
color = if (MaterialTheme.colors.isLight) MainText else MainTextDark
)
Spacer(Modifier.weight(1f))
Text(
fontWeight = FontWeight.Medium,
fontSize = 16.sp,
text = content,
modifier = Modifier.padding(top = 9.dp),
color = MaterialTheme.colors.onSurface
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Confirm Entry Menu Transaction Button Component
Use to be confirm menu entry transaction button
code
@Composable
private fun ButtonConfirm(
jsonData: JSONObject,
transactionType: String,
navController: NavHostController,
context: Context
) {
val popupPrintSlipCustomer = remember { mutableStateOf(false) }
val coroutineScope = rememberCoroutineScope()
val loading = remember { mutableStateOf(false) }
val textLoading = remember { mutableStateOf("") }
val errMessage = remember { mutableStateOf("") }
val errMessageOpenDialog = remember { mutableStateOf(false) }
val popUpContinue = remember { mutableStateOf(false) }
val isCloseButtonShowAlertMessage = remember { mutableStateOf(false) }
val handler = CoroutineExceptionHandler { _, exception ->
Log.e("Transaction Display", exception.message.toString())
}
if (popupPrintSlipCustomer.value) {
AskPrintCustomerSlip(
openDialog = popupPrintSlipCustomer,
navController = navController,
jsonData = jsonData,
context = context,
)
}
if (loading.value) {
ShowLoading(
openDialog = loading,
text = textLoading,
)
}
if (errMessageOpenDialog.value) {
ShowAlertMessage(
description = errMessage,
openDialog = errMessageOpenDialog,
isCloseButton = isCloseButtonShowAlertMessage
)
}
Column(
modifier = Modifier
.padding(20.dp)
.fillMaxWidth()
) {
Button(
onClick = {
coroutineScope.launch(handler) {
// Menu Entry Transaction Comfirmation Function
transactionDisplayConfirm(
jsonData, transactionType, navController,
errMessageOpenDialog, errMessage, context,
popupPrintSlipCustomer, loading, textLoading, popUpContinue
)
}
},
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
shape = RoundedCornerShape(50),
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
elevation = ButtonDefaults.elevation(
defaultElevation = 6.dp,
pressedElevation = 8.dp,
disabledElevation = 0.dp
)
) {
Text("Confirm")
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
Menu Entry Transaction Comfirmation Function
Use to confirm menu entry transaction
directory screen/transaction/transaction_display/controller.kt
code
suspend fun transactionDisplayConfirm(
jsonData: JSONObject,
transactionType: String,
navController: NavHostController,
errMessageOpenDialog: MutableState<Boolean>,
errMessage: MutableState<String>,
context: Context,
popupPrintSlipCustomer: MutableState<Boolean>,
loading: MutableState<Boolean>,
textLoading: MutableState<String>,
popUpContinue: MutableState<Boolean>,
) {
if (jsonData.getString("title") == "reprint") {
textLoading.value = "Printing..."
jsonData.put("ref_num", jsonData.getString("ref_number"))
jsonData.put("auth_id", jsonData.getString("approve_code"))
Printer().printSlip(
jsonData,
context,
"merchant"
)
loading.value = false
textLoading.value = ""
popupPrintSlipCustomer.value = true
popUpContinue.value = true
} else if (jsonData.getString("menu_entry_txn") == "sale_complete") {
// go to Edit Amount Screen
navController.navigate("${Route.EditAmount.route}/$jsonData") {
popUpTo(Route.Home.route)
}
} else {
loading.value = true
// Function Online Transaction Of Menu Entry
val responseTransaction =
sendOnlineTransaction(
jsonData, context, errMessage, loading,
textLoading, popupPrintSlipCustomer, popUpContinue
)
if (responseTransaction.length() == 0) {
loading.value = false
navController.popBackStack()
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Wait Card Operation Screen
Use to display card operation support and waiting card action
directory screen/transaction/wait_operation/WaitOperationDetail.kt
code
@Composable
fun WaitOperation(
navController: NavController, data: String
) {
val jsonData = JSONObject(data)
val amount = jsonData.getString("amount")
val transactionType = jsonData.getString("transaction_type")
val title = jsonData.getString("title")
val hasError = remember { mutableStateOf(false) }
val hasEMVStartAgain = remember { mutableStateOf(false) }
val hasEMVStartAgainConfirm = remember { mutableStateOf(false) }
val description = remember { mutableStateOf("") }
val cardOperation = rememberCoroutineScope()
val beeper: UBeeper = DeviceHelper.me().beeper
val led: ULed = DeviceHelper.me().getLed(RFDeviceName.INNER)
val doProcess = remember { mutableStateOf(false) }
val seletAIDPopup = remember { mutableStateOf(false) }
val aidList : MutableList<String> = remember { mutableStateListOf() }
val aidOriginalList : MutableList<List<CandidateAID>> = remember { mutableStateListOf() }
val countDownTimer = remember { mutableStateOf("60") }
val scope = rememberCoroutineScope()
val timer = object : CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
if (doProcess.value){ cancel() }
countDownTimer.value = ((millisUntilFinished / 1000)).toString()
}
override fun onFinish() {
scope.launch {
countDownTimer.value = "0"
hasError.value = false
DeviceHelper.me().emv.stopEMV()
DeviceHelper.me().emv.stopSearch()
navController.popBackStack()
}
}
}
val callback = {
timer.cancel()
}
BackHandler(enabled = true){
scope.launch {
DeviceHelper.me().emv.stopSearch()
EMVHelper(hasEMVStartAgain = hasEMVStartAgain).stopEMV()
navController.popBackStack()
}
}
LaunchedEffect(Unit) {
timer.start()
scope.launch {
// Wait Operation Strat EMV Function
startEMV(
jsonData,
hasError,
description,
cardOperation,
navController,
seletAIDPopup,
aidList,
aidOriginalList,
doProcess,
hasEMVStartAgain,
hasEMVStartAgainConfirm
)
}
}
DisposableEffect(Unit) {
onDispose {
timer.cancel()
scope.launch {
DeviceHelper.me().emv.stopEMV();
DeviceHelper.me().emv.stopSearch()
}
}
}
if (hasError.value) {
beeper.startBeep(500)
led.turnOn(Light.RED);
ShowAlertMessage(
description = description,
openDialog = hasError,
navController = navController
)
}
if (hasEMVStartAgain.value) {
beeper.startBeep(100)
ShowAlertMessageEMVStartAgain(
description = description,
openDialog = hasEMVStartAgain,
navController = navController,
startAgain = scope.launch {
startTrade(
jsonData,
hasError,
description,
cardOperation,
navController,
seletAIDPopup,
aidList,
aidOriginalList,
doProcess,
hasEMVStartAgain,
hasEMVStartAgainConfirm
)
}
)
}
if (seletAIDPopup.value) {
ShowSelectAIDList("AID Select", seletAIDPopup, aidList, navController, aidOriginalList)
}
Column(
modifier = Modifier.fillMaxSize()
) {
// Title Bar Operation Wait Component
TitleBarOperationWait(navController, countDownTimer, timer, title, scope)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.wrapContentSize(Alignment.Center)
.padding(10.dp)
.fillMaxWidth(),
) {
Text(
fontWeight = FontWeight.Light,
fontSize = 12.sp,
text = "Please Choose One",
color = MaterialTheme.colors.onSurface,
textAlign = TextAlign.Center,
)
}
// Show Amount Component
ShowAmount(amount, transactionType)
// Button Key-in Component
ButtonKeyIn(amount, transactionType, navController, title)
Spacer(modifier = Modifier.height(20.dp))
// Operation Support Info Component
WaitOperationInfo()
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
Title Bar Operation Wait Component
Use to display title bar of operation wait screen. Inside consist countdown time out and stop EMV process
code
@Composable
private fun TitleMenuOperationWait(
navController: NavController,
countDownTimer: MutableState<String>,
timer: CountDownTimer,
title: String,
scope: CoroutineScope,
) {
Row(
modifier = Modifier
.padding(top = 10.dp)
.fillMaxWidth()
) {
IconButton(onClick = {
scope.launch {
timer.cancel()
DeviceHelper.me().emv.stopProcess()
DeviceHelper.me().emv.stopSearch()
DeviceHelper.me().emv.stopEMV()
navController.popBackStack()
}
}) {
Icon(Icons.Default.ArrowBack, "Menu", tint = MaterialTheme.colors.onSurface)
}
Text(
fontWeight = FontWeight.Bold,
fontSize = 20.sp,
text = title.uppercase(Locale.getDefault()),
modifier = Modifier.padding(top = 9.dp),
color = MaterialTheme.colors.onSurface
)
Spacer(Modifier.weight(1f))
Text(
fontWeight = FontWeight.Medium,
fontSize = 20.sp,
text = "${countDownTimer.value} S",
modifier = Modifier.padding(top = 9.dp, end = 20.dp),
color = MaterialTheme.colors.onSurface
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Show Amount Component
Use to display card details (logo, card number)
code
@Composable
private fun ShowAmount(amount: String, transactionType: String) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
if (transactionType == "balance_inquiry") {
Text(
text = "Balance Inquiry",
color = MaterialTheme.colors.onSurface,
fontWeight = FontWeight.Bold,
fontSize = 25.sp
)
} else {
when {
amount.length < 9 -> {
Text(
text = "฿ $amount",
color = MaterialTheme.colors.onSurface,
fontWeight = FontWeight.Bold,
fontSize = 45.sp
)
}
else -> {
Text(
text = "฿ $amount",
color = MaterialTheme.colors.onSurface,
fontWeight = FontWeight.Bold,
fontSize = 35.sp
)
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Button Key-in Component
Use to be button go to Key-in Card Screen. Inside consist prepare some transaction data
code
@Composable
private fun ButtonKeyIn(
amount: String, transactionType: String,
navController: NavController,
title: String
) {
val jsonData = JSONObject()
if (amount != "") {
jsonData.put("amount", amount)
} else {
jsonData.put("amount", "")
}
jsonData.put("name", " ")
jsonData.put("transaction_type", transactionType)
jsonData.put("operation", "key_in")
jsonData.put("title", title)
Column(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(
onClick = {
DeviceHelper.me().emv.stopSearch()
navController.navigate("key_in/$jsonData") {
popUpTo(Route.Home.route)
}
},
colors = ButtonDefaults.buttonColors(backgroundColor = CardColor),
shape = RoundedCornerShape(50),
elevation = ButtonDefaults.elevation(
defaultElevation = 6.dp,
pressedElevation = 8.dp,
disabledElevation = 0.dp
)
) {
Text(
text = "Manual Input Card Number", fontSize = 10.sp,
color = Color.White, fontWeight = FontWeight.Normal
)
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Operation Support Info Component
Use to display operation support info
code
@Composable
private fun WaitOperationInfo() {
val compositionCardSwipe by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.swipe))
val progressCardSwipe by animateLottieCompositionAsState(
composition = compositionCardSwipe,
iterations = LottieConstants.IterateForever
)
Column(
modifier = Modifier
.fillMaxSize()
.background(
color = if (isSystemInDarkTheme()) infoDark else infoLight
),
) {
Row(
modifier = Modifier.padding(30.dp)
) {
Column(
modifier = Modifier.width(150.dp)
) {
Text(
text = "Magstripe Card",
color = CardColor,
fontWeight = FontWeight.SemiBold,
fontSize = 18.sp
)
Text(
text = "Please swipe the card downward",
color = MaterialTheme.colors.onSurface,
fontWeight = FontWeight.Normal,
fontSize = 14.sp
)
}
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End
) {
LottieAnimation(
compositionCardSwipe,
progressCardSwipe,
modifier = Modifier.size(100.dp)
)
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Wait Operation Strat EMV Function
Use to start EMV process by using EMVHelper
directory screen/transaction/wait_operation/operation.controller/card.kt
code
fun startEMV(
jsonData: JSONObject,
hasError: MutableState<Boolean>,
description: MutableState<String>,
cardOperation: CoroutineScope,
navController: NavController,
seletAIDPopup: MutableState<Boolean>,
aidList: MutableList<String>,
aidOriginalList: MutableList<List<CandidateAID>>,
doProcess: MutableState<Boolean>,
hasEMVStartAgain: MutableState<Boolean>,
hasEMVStartAgainConfirm: MutableState<Boolean>,
) {
try {
val emvHelper = EMVHelper(
jsonData,
hasError,
description,
cardOperation,
navController,
seletAIDPopup,
aidList,
aidOriginalList,
doProcess,
hasEMVStartAgain
)
emvHelper.startEMV()
} catch (e: Exception) {
description.value = "Error swipe card: $e"
hasError.value = true
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Setting Screen
Setting consist terminal setting and host config
directory screen/administrator/Setting.kt
code
@Composable
fun Setting(navController: NavController) {
val inputService = LocalSoftwareKeyboardController.current
val localFocusManager = LocalFocusManager.current
val dataHostList = getHostList()
val dataSetting = getDataSetting()
val enablePrintBitmap = remember { mutableStateOf(dataSetting?.enable_print_test ?: false) }
val hostListExpand = remember { mutableStateOf(false) }
val scrollState = rememberScrollState()
val selectedIndexHostList = remember { mutableStateOf(0) }
val invoice = remember { mutableStateOf(getTraceInvoice().toString()) }
val invoiceError = remember { mutableStateOf(false) }
val hostRecordIndex = remember { mutableStateOf(if (dataHostList.size>0) dataHostList[0]!!.host_record_index else null)}
val stan = remember { mutableStateOf(if (dataHostList.size>0) dataHostList[0]!!.stan.toString() else "")}
val stanError = remember { mutableStateOf(false) }
val batch = remember { mutableStateOf(if (dataHostList.size>0) dataHostList[0]!!.last_batch_number.toString() else "" ) }
val batchError = remember { mutableStateOf(false) }
val reverseFlag = remember { mutableStateOf(dataHostList[0]?.reversal_flag ?: false ) }
val reverseFlagError = remember { mutableStateOf(false) }
val allowSwipeCard = remember { mutableStateOf(dataSetting?.enable_swipe_card ?: true) }
val allowInsertCard = remember { mutableStateOf(dataSetting?.enable_insert_card ?: true) }
val allowPassCard = remember { mutableStateOf(dataSetting?.enable_pass_card ?: true) }
Column(
modifier = Modifier.fillMaxSize()
) {
// Title Bar Setting Component
ButtonTitleSetting(
navController, "Settings",
hostRecordIndex, enablePrintBitmap, invoice, stan, batch, reverseFlag,
allowSwipeCard, allowInsertCard, allowPassCard
)
Spacer(Modifier.height(10.dp))
Column(
modifier = Modifier.verticalScroll(scrollState)
) {
Text(
modifier = Modifier.padding(start = 15.dp),
text = "Terminal",
fontWeight = FontWeight.Medium,
fontSize = 15.sp,
color = MaterialTheme.colors.onSurface
)
Spacer(Modifier.height(5.dp))
Divider(
color = Color.LightGray,
thickness = 1.dp,
modifier = Modifier.padding(start = 10.dp, end = 10.dp)
)
Spacer(Modifier.height(10.dp))
// Checkbox Setting Component
CheckboxSetting("Print Bitmap",enablePrintBitmap)
Spacer(Modifier.height(1.dp))
CheckboxSetting("Allow Swipe Card",allowSwipeCard)
Spacer(Modifier.height(1.dp))
CheckboxSetting("Allow Insert Card",allowInsertCard)
Spacer(Modifier.height(1.dp))
CheckboxSetting("Allow Pass Card",allowPassCard)
Spacer(Modifier.height(1.dp))
// Text Input Setting Component
TextInputSetting(
"Invoice", invoice, invoiceError,
inputService!!, localFocusManager
)
Spacer(Modifier.height(30.dp))
// Text Input Setting Component
Text(
modifier = Modifier.padding(start = 15.dp),
text = "Host Config",
fontWeight = FontWeight.Medium,
fontSize = 15.sp,
color = MaterialTheme.colors.onSurface
)
Spacer(Modifier.height(10.dp))
Divider(
color = Color.LightGray,
thickness = 1.dp,
modifier = Modifier.padding(start = 10.dp, end = 10.dp)
)
Spacer(Modifier.height(10.dp))
// Selection Host Setting Component
SelectionHostSetting(
hostListExpand,
dataHostList,
selectedIndexHostList,
hostRecordIndex,
stan,
batch
)
// Text Input Setting Component
TextInputSetting(
"STAN", stan, stanError,
inputService, localFocusManager
)
Spacer(Modifier.height(10.dp))
// Text Input Setting Component
TextInputSetting(
"Batch Numbe", batch, batchError,
inputService, localFocusManager
)
Spacer(Modifier.height(5.dp))
// Reversal Host Setting Component
ReversalSetting(reverseFlag)
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
Title Bar Setting Component
Use to display title bar of setting screen. consist save setting data button and back to main screen button
code
@Composable
private fun ButtonTitleSetting(
navController: NavController,
title: String,
hostRecordIndex: MutableState<Int?>,
enablePrintBitmap: MutableState<Boolean>,
invoice: MutableState<String>,
stan: MutableState<String>,
batch: MutableState<String>,
reverseFlag: MutableState<Boolean>,
allowSwipCard: MutableState<Boolean>,
allowInsertCard: MutableState<Boolean>,
allowPassCard: MutableState<Boolean>,
) {
val askToSave = remember {
mutableStateOf(false)
}
if (askToSave.value) {
AskToSave(
askToSave, navController,
hostRecordIndex, enablePrintBitmap, invoice, stan, batch, reverseFlag,
allowSwipCard, allowInsertCard, allowPassCard
)
}
Row(
modifier = Modifier
.padding(top = 10.dp)
.fillMaxWidth()
) {
IconButton(onClick = {
navController.popBackStack()
}) {
Icon(Icons.Default.ArrowBack, "Menu", tint = MaterialTheme.colors.onSurface)
}
Text(
fontWeight = FontWeight.Bold,
fontSize = 20.sp,
text = title.uppercase(Locale.getDefault()),
modifier = Modifier.padding(top = 9.dp),
color = MaterialTheme.colors.onSurface
)
Spacer(Modifier.weight(1f))
Button(
onClick = {
askToSave.value = true
},
enabled = (hostRecordIndex!=null),
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
shape = RoundedCornerShape(25),
modifier = Modifier
.padding(top = 9.dp, end = 20.dp)
.width(100.dp)
.height(40.dp),
elevation = ButtonDefaults.elevation(
defaultElevation = 6.dp,
pressedElevation = 8.dp,
disabledElevation = 0.dp
)
) {
Text("Save")
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
Checkbox Setting Component
Use to config value by using checkbox
code
@Composable
private fun CheckboxSetting(title: String, checked: MutableState<Boolean>) {
Row(
modifier = Modifier.padding(start = 20.dp, end = 20.dp)
) {
Icon(Icons.Outlined.Info, "", tint = MaterialTheme.colors.onSurface)
Spacer(
modifier = Modifier
.width(15.dp)
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = title,
fontWeight = FontWeight.Medium,
fontSize = 15.sp,
color = MaterialTheme.colors.onSurface
)
Checkbox(
checked = checked.value,
onCheckedChange = { checked.value = it }
)
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Text Input Setting Component
Use to config value by using text field for enter value
code
@Composable
private fun TextInputSetting(
title: String, text: MutableState<String>,
handleError: MutableState<Boolean>,
inputService: SoftwareKeyboardController,
localFocusManager: FocusManager
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(start = 20.dp, end = 20.dp)
) {
Row(
) {
Icon(Icons.Outlined.Info, "", tint = MaterialTheme.colors.onSurface)
Spacer(
modifier = Modifier.width(15.dp)
)
Column(
modifier = Modifier.fillMaxWidth()
) {
Text(
text = title,
fontWeight = FontWeight.Medium,
fontSize = 15.sp,
color = MaterialTheme.colors.onSurface
)
Spacer(Modifier.height(10.dp))
OutlinedTextField(
modifier = Modifier
.padding(0.dp)
.fillMaxWidth(),
value = text.value,
onValueChange = { data ->
text.value = data
handleError.value = data.isEmpty()
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
placeholder = { Text("Please enter invoice") },
singleLine = true,
keyboardActions = KeyboardActions(
onDone = {
inputService.hide()
localFocusManager.clearFocus()
}
),
colors = TextFieldDefaults.outlinedTextFieldColors(
textColor = MaterialTheme.colors.onSurface,
focusedBorderColor = Color.White
),
isError = handleError.value
)
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
Selection Host Setting Component
Use to select host to config value by using dropdown
code
@Composable
private fun SelectionHostSetting(
hostListExpand: MutableState<Boolean>,
dataHostList: RealmList<ConfigHostRO>,
selectedIndexHostList: MutableState<Int>,
hostRecordIndex: MutableState<Int?>,
stan: MutableState<String>,
batch: MutableState<String>
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.padding(start = 20.dp, end = 20.dp)
.height(50.dp)
.clickable(onClick = {
hostListExpand.value = true
})
) {
Icon(Icons.Outlined.Info, "", tint = MaterialTheme.colors.onSurface)
Spacer(
modifier = Modifier.width(15.dp)
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = "Select Host",
fontWeight = FontWeight.Medium,
fontSize = 15.sp,
color = MaterialTheme.colors.onSurface
)
Row() {
if (dataHostList.size > 0) {
Text(
dataHostList[selectedIndexHostList.value]!!.host_label_name!!,
color = MaterialTheme.colors.onSurface
)
DropdownMenu(
expanded = hostListExpand.value,
onDismissRequest = { hostListExpand.value = false },
Modifier.background(infoDark)
) {
dataHostList.forEachIndexed { index, host ->
DropdownMenuItem(onClick = {
selectedIndexHostList.value = index
hostRecordIndex.value = host.host_record_index
stan.value = host.stan.toString()
batch.value = host.last_batch_number.toString()
hostListExpand.value = false
}) {
Text(text = host.host_label_name!!)
}
}
}
} else {
Text(
"- no host -",
color = MaterialTheme.colors.onSurface
)
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
Reversal Host Setting Component
Use to reset reverse flag of host selected by using click event
code
@Composable
private fun ReversalSetting(reverseFlag: MutableState<Boolean>){
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.padding(start = 20.dp, end = 20.dp)
.height(50.dp)
.clickable(onClick = {
reverseFlag.value = false
})
) {
Icon(Icons.Outlined.Info, "", tint = MaterialTheme.colors.onSurface)
Spacer(
modifier = Modifier
.width(15.dp)
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = "Reverse Flag: ${reverseFlag.value}",
fontWeight = FontWeight.Medium,
fontSize = 15.sp,
color = MaterialTheme.colors.onSurface
)
Row() {
Text(
modifier = Modifier.alpha(0.5F),
text = "reset",
fontWeight = FontWeight.Medium,
fontSize = 15.sp,
color = MaterialTheme.colors.onSurface
)
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Helpful Components
Alert Dialog
Use to be popup dialog for explain current process or display error message
directory components/AlertDialog.kt
Alert Dialog Component
Use to popup dialog for display process error message
function 1 handle back to home event
code
@Composable
fun ShowAlertMessage(
description: MutableState<String>,
openDialog: MutableState<Boolean>,
navController: NavController
) {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.failed_lottie))
val progress by animateLottieCompositionAsState(composition)
Dialog(
onDismissRequest = {
openDialog.value = true
},
) {
Card(
shape = RoundedCornerShape(10.dp)
) {
Column(
modifier = Modifier
.padding(20.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
textAlign = TextAlign.Center,
fontWeight = FontWeight.SemiBold,
fontSize = 15.sp,
text = description.value,
color = MaterialTheme.colors.onSurface
)
Spacer(Modifier.height(15.dp))
LottieAnimation(
composition,
progress,
modifier = Modifier.size(100.dp)
)
Spacer(Modifier.height(15.dp))
Button(
shape = RoundedCornerShape(25.dp),
modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
onClick = {
openDialog.value = false
navController.popBackStack()
}) {
Text("Back")
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
function 2 handle close popup event
code
@Composable
fun ShowAlertMessage(
description: MutableState<String>,
openDialog: MutableState<Boolean>,
isCloseButton: MutableState<Boolean>
) {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.failed_lottie))
val progress by animateLottieCompositionAsState(composition)
Dialog(
onDismissRequest = {
openDialog.value = true
},
) {
Card(
shape = RoundedCornerShape(10.dp)
) {
Column(
modifier = Modifier
.padding(20.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
textAlign = TextAlign.Center,
fontWeight = FontWeight.SemiBold,
fontSize = 15.sp,
text = description.value,
color = MaterialTheme.colors.onSurface
)
Spacer(Modifier.height(15.dp))
LottieAnimation(
composition,
progress,
modifier = Modifier.size(100.dp)
)
Spacer(Modifier.height(15.dp))
if (isCloseButton.value) {
Button(
shape = RoundedCornerShape(25.dp),
modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
onClick = {
openDialog.value = false
}) {
Text("Close")
}
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
Success Dialog Component
Use to popup dialog for part of process success
code
@Composable
fun ShowSuccessMessage(
description: MutableState<String>,
openDialog: MutableState<Boolean>
) {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.success))
val progress by animateLottieCompositionAsState(composition)
Dialog(
onDismissRequest = {
openDialog.value = true
},
) {
Card(
shape = RoundedCornerShape(10.dp)
) {
Column(
modifier = Modifier
.padding(20.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
textAlign = TextAlign.Center,
fontWeight = FontWeight.SemiBold,
fontSize = 15.sp,
text = description.value,
color = MaterialTheme.colors.onSurface
)
Spacer(Modifier.height(15.dp))
LottieAnimation(
composition,
progress,
modifier = Modifier.size(100.dp)
)
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Inquiry Dialog Component
Use to popup dialog for display balance inquiry of payment card
code
@Composable
fun ShowInquiryMessage(
title: MutableState<String>,
amount: MutableState<String>,
openDialog: MutableState<Boolean>,
navController: NavController
) {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.success))
val progress by animateLottieCompositionAsState(composition)
Dialog(
onDismissRequest = {
openDialog.value = true
},
) {
Card(
shape = RoundedCornerShape(10.dp)
) {
Column(
modifier = Modifier
.padding(20.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
textAlign = TextAlign.Center,
fontWeight = FontWeight.SemiBold,
fontSize = 20.sp,
text = title.value,
color = MaterialTheme.colors.onSurface
)
Spacer(Modifier.height(15.dp))
Text(
textAlign = TextAlign.Center,
fontWeight = FontWeight.SemiBold,
fontSize = 15.sp,
text = "Balance is",
color = MaterialTheme.colors.onSurface
)
Spacer(Modifier.height(5.dp))
Card(
shape = RoundedCornerShape(10.dp),
elevation = 0.dp,
backgroundColor = ComingSoonColor
) {
Text(
modifier = Modifier
.padding(10.dp),
textAlign = TextAlign.Center,
fontWeight = FontWeight.SemiBold,
fontSize = 30.sp,
text = amount.value,
color = MaterialTheme.colors.onSurface
)
}
Spacer(Modifier.height(15.dp))
LottieAnimation(
composition,
progress,
modifier = Modifier.size(100.dp)
)
Button(
shape = RoundedCornerShape(25.dp),
modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
onClick = {
openDialog.value = false
navController.popBackStack()
}) {
Text("Back")
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
Loading Dialog Component
Use to popup dialog for display loading progress
code
@Composable
fun ShowLoading(
openDialog: MutableState<Boolean>,
text: MutableState<String>
) {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.loading))
val progress by animateLottieCompositionAsState(
composition = composition,
iterations = LottieConstants.IterateForever
)
Dialog(
onDismissRequest = {
openDialog.value = true
},
) {
Card(
shape = RoundedCornerShape(10.dp)
) {
Column(
modifier = Modifier
.padding(20.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
textAlign = TextAlign.Center,
fontWeight = FontWeight.SemiBold,
fontSize = 15.sp,
text = text.value,
color = MaterialTheme.colors.onSurface
)
Spacer(Modifier.height(15.dp))
LottieAnimation(
composition,
progress,
modifier = Modifier.size(100.dp)
)
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Test Host Dialog Component
Use to popup dialog for display host list and can select host to echo host using Function Test Host
code
fun ShowTestHostList(
title: String,
openDialog: MutableState<Boolean>,
) {
val openLoading = remember { mutableStateOf(false) }
val openLoadingMessage = remember { mutableStateOf("") }
val openErrDialog = remember { mutableStateOf(false) }
val withCloseAlertDialogButton = remember { mutableStateOf(false) }
val openErrDialogMessage = remember { mutableStateOf("") }
val openSuccessDialog = remember { mutableStateOf(false) }
val openSuccessDialogMessage = remember { mutableStateOf("") }
val currentCoroutine = rememberCoroutineScope()
val handler = CoroutineExceptionHandler { _, exception ->
Log.e("TCP Test", exception.message.toString())
}
if (openLoading.value) {
ShowLoading(
openLoading,
openLoadingMessage
)
}
if (openErrDialog.value) {
ShowAlertMessage(
openErrDialogMessage,
openErrDialog,
withCloseAlertDialogButton
)
}
if (openSuccessDialog.value) {
ShowSuccessMessage(
openSuccessDialogMessage,
openSuccessDialog
)
}
Dialog(
onDismissRequest = {
openDialog.value = true
},
) {
Card(
shape = RoundedCornerShape(10.dp)
) {
Column(
Modifier.padding(10.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(modifier = Modifier.height(5.dp))
Text(
textAlign = TextAlign.Center,
fontWeight = FontWeight.SemiBold,
fontSize = 20.sp,
text = title, color = MaterialTheme.colors.onSurface
)
Divider()
LazyColumn(
modifier = Modifier.height(300.dp)
) {
val hostList = getHostList()
if (hostList != null) {
items(hostList.size) { item ->
Card(
backgroundColor = Color(
red = Random.nextInt(0, 255),
green = Random.nextInt(0, 255),
blue = Random.nextInt(0, 255)
),
shape = RoundedCornerShape(10.dp),
modifier = Modifier
.padding(
top = 5.dp,
bottom = 5.dp
)
.height(50.dp)
.fillMaxWidth(),
) {
Box(
modifier = Modifier.clickable {
val ip = hostList[item]!!.ip_address1!!
val port = hostList[item]!!.port1!!
currentCoroutine.launch(handler) {
openLoading.value = true
openLoadingMessage.value = "Conecting.."
// Function Test Host
val echoIsSuccess = testHost(
ip,
port,
openLoadingMessage,
openErrDialogMessage
)
if (echoIsSuccess) {
openSuccessDialogMessage.value = "Echo is success"
openSuccessDialog.value = true
} else {
openErrDialog.value = true
}
delay(2_500)
openSuccessDialog.value = false
openErrDialog.value = false
openLoading.value = false
openDialog.value = false
}
},
contentAlignment = Alignment.CenterStart
) {
Text(
modifier = Modifier.padding(start = 20.dp),
color = MaterialTheme.colors.onSurface,
text = "Index: ${hostList[item]!!.host_record_index}"
)
}
}
}
}
}
Spacer(modifier = Modifier.height(5.dp))
Button(
shape = RoundedCornerShape(25.dp),
modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
onClick = {
openDialog.value = false
}) {
Text("Cancel")
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
Ask To Print Customer Slip Dialog Component
Use to popup dialog for ask question want to print customer or not
code
@Composable
fun AskPrintCustomerSlip(
openDialog: MutableState<Boolean>,
navController: NavController,
jsonData: JSONObject?,
context: Context
) {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.printing))
val progress by animateLottieCompositionAsState(
composition = composition,
iterations = LottieConstants.IterateForever
)
Dialog(
onDismissRequest = {
// Dismiss the dialog when the user clicks outside the dialog or on the back
// button. If you want to disable that functionality, simply use an empty
// onCloseRequest.
openDialog.value = true
},
) {
Card(
shape = RoundedCornerShape(10.dp)
) {
Column(
modifier = Modifier
.padding(20.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
fontWeight = FontWeight.SemiBold,
fontSize = 15.sp,
text = "Do you want to print customer copy?",
color = MaterialTheme.colors.onSurface
)
Spacer(Modifier.height(15.dp))
LottieAnimation(
composition,
progress,
modifier = Modifier
.size(100.dp)
.fillMaxWidth()
)
Spacer(Modifier.height(20.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Button(
shape = RoundedCornerShape(25.dp),
modifier = Modifier.width(100.dp),
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
onClick = {
openDialog.value = false
if (jsonData != null) {
Printer().printSlip(
jsonData,
context,
"customer"
)
}
else {
val lastTransaction = getLastTransaction()
if (lastTransaction != null) {
val lastTransactionJson = transactionToJson(lastTransaction.txn_type!!,lastTransaction)
Printer().printSlip(
lastTransactionJson,
context,
"customer"
)
Log.v("TEST", "Last transaction json: $lastTransactionJson")
}
}
navController.popBackStack()
}) {
Text("YES")
}
Button(
shape = RoundedCornerShape(25.dp),
modifier = Modifier.width(100.dp),
colors = ButtonDefaults.textButtonColors(
backgroundColor = MainText,
contentColor = BgColor
),
onClick = {
navController.popBackStack()
}) {
Text("NO")
}
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
Ask To Save Setting Dialog Component
Use to popup dialog for ask question want to save setting config or not
code
@Composable
fun AskToSave(
openDialog: MutableState<Boolean>,
navController: NavController,
hostRecordIndex: MutableState<Int?>,
enablePrintBitmap: MutableState<Boolean>,
invoice: MutableState<String>,
stan: MutableState<String>,
batch: MutableState<String>,
reverseFlag: MutableState<Boolean>,
allowSwipeCard: MutableState<Boolean>,
allowInsertCard: MutableState<Boolean>,
allowPassCard: MutableState<Boolean>,
) {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.save))
val progress by animateLottieCompositionAsState(
composition = composition,
iterations = LottieConstants.IterateForever
)
Dialog(
onDismissRequest = {
openDialog.value = true
},
) {
Card(
shape = RoundedCornerShape(10.dp)
) {
Column(
modifier = Modifier
.padding(20.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
fontWeight = FontWeight.SemiBold,
fontSize = 15.sp,
text = "Do you want to save settings?",
color = MaterialTheme.colors.onSurface
)
Spacer(Modifier.height(15.dp))
LottieAnimation(
composition,
progress,
modifier = Modifier
.size(100.dp)
.fillMaxWidth()
)
Spacer(Modifier.height(20.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Button(
shape = RoundedCornerShape(25.dp),
modifier = Modifier.width(100.dp),
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
onClick = {
val host = selectHost(hostRecordIndex.value!!)
if (host != null) {
host.stan = stan.value.toInt()
host.last_batch_number = batch.value.toInt()
host.reversal_flag = reverseFlag.value
if (!reverseFlag.value){
host.reversal_msg = null
}
updateHost(host)
}
val dataSetting = getDataSetting()
if (dataSetting != null) {
dataSetting.enable_print_test = enablePrintBitmap.value
dataSetting.enable_swipe_card = allowSwipeCard.value
dataSetting.enable_insert_card = allowInsertCard.value
dataSetting.enable_pass_card = allowPassCard.value
editDataSetting(dataSetting)
}
updateInvoice(invoice.value.toInt())
openDialog.value = false
}) {
Text("YES")
}
Button(
shape = RoundedCornerShape(25.dp),
modifier = Modifier.width(100.dp),
colors = ButtonDefaults.textButtonColors(
backgroundColor = MainText,
contentColor = BgColor
),
onClick = {
openDialog.value = false
}) {
Text("NO")
}
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
AID Selection Dialog Component
Use to popup dialog for display AID list and select AID for EMV process
code
@Composable
fun ShowSelectAIDList(
title: String,
openDialog: MutableState<Boolean>,
aidList: MutableList<String>,
navController: NavController,
aidOriginalList: MutableList<List<CandidateAID>>
) {
val currentCoroutine = rememberCoroutineScope()
val emv: UEMV? = DeviceHelper.me().emv;
val handler = CoroutineExceptionHandler { _, exception ->
Log.e("TCP Test", exception.message.toString())
}
Dialog(
onDismissRequest = {
openDialog.value = true
},
) {
Card(
shape = RoundedCornerShape(10.dp)
) {
Column(
Modifier.padding(10.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(modifier = Modifier.height(5.dp))
Text(
textAlign = TextAlign.Center,
fontWeight = FontWeight.SemiBold,
fontSize = 20.sp,
text = title, color = MaterialTheme.colors.onSurface
)
Divider()
LazyColumn(
modifier = Modifier.height(300.dp)
) {
Log.v("TEST", "host list: $aidList")
if (aidList.size > 0) {
items(aidList.size) { item ->
Card(
backgroundColor = Color(
red = Random.nextInt(0, 255),
green = Random.nextInt(0, 255),
blue = Random.nextInt(0, 255)
),
shape = RoundedCornerShape(10.dp),
modifier = Modifier
.padding(
top = 5.dp,
bottom = 5.dp
)
.height(50.dp)
.fillMaxWidth(),
) {
Box(
modifier = Modifier.clickable {
currentCoroutine.launch(handler) {
EMVHelper().selectedAID(item, aidOriginalList)
openDialog.value = false
}
},
contentAlignment = Alignment.CenterStart
) {
Text(
modifier = Modifier.padding(start = 20.dp),
color = MaterialTheme.colors.onSurface,
text = "Index: ${aidList[item]}"
)
}
}
}
}
}
Spacer(modifier = Modifier.height(5.dp))
Button(
shape = RoundedCornerShape(25.dp),
modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
onClick = {
emv!!.stopEMV()
emv.stopSearch()
openDialog.value = false
navController.popBackStack()
}) {
Text("Cancel")
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
AID Selection Dialog Component
Use to popup dialog for display AID list and select AID for EMV process
code
@Composable
fun ShowSelectAIDList(
title: String,
openDialog: MutableState<Boolean>,
aidList: MutableList<String>,
navController: NavController,
aidOriginalList: MutableList<List<CandidateAID>>
) {
val currentCoroutine = rememberCoroutineScope()
val emv: UEMV? = DeviceHelper.me().emv;
val handler = CoroutineExceptionHandler { _, exception ->
Log.e("TCP Test", exception.message.toString())
}
Dialog(
onDismissRequest = {
openDialog.value = true
},
) {
Card(
shape = RoundedCornerShape(10.dp)
) {
Column(
Modifier.padding(10.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(modifier = Modifier.height(5.dp))
Text(
textAlign = TextAlign.Center,
fontWeight = FontWeight.SemiBold,
fontSize = 20.sp,
text = title, color = MaterialTheme.colors.onSurface
)
Divider()
LazyColumn(
modifier = Modifier.height(300.dp)
) {
Log.v("TEST", "host list: $aidList")
if (aidList.size > 0) {
items(aidList.size) { item ->
Card(
backgroundColor = Color(
red = Random.nextInt(0, 255),
green = Random.nextInt(0, 255),
blue = Random.nextInt(0, 255)
),
shape = RoundedCornerShape(10.dp),
modifier = Modifier
.padding(
top = 5.dp,
bottom = 5.dp
)
.height(50.dp)
.fillMaxWidth(),
) {
Box(
modifier = Modifier.clickable {
currentCoroutine.launch(handler) {
EMVHelper().selectedAID(item, aidOriginalList)
openDialog.value = false
}
},
contentAlignment = Alignment.CenterStart
) {
Text(
modifier = Modifier.padding(start = 20.dp),
color = MaterialTheme.colors.onSurface,
text = "Index: ${aidList[item]}"
)
}
}
}
}
}
Spacer(modifier = Modifier.height(5.dp))
Button(
shape = RoundedCornerShape(25.dp),
modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
onClick = {
emv!!.stopEMV()
emv.stopSearch()
openDialog.value = false
navController.popBackStack()
}) {
Text("Cancel")
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
Repeat EMV Process Dialog Component
Use to popup dialog for ask question want to start EMV process again or not
code
@Composable
fun ShowAlertMessageEMVStartAgain(
description: MutableState<String>,
openDialog: MutableState<Boolean>,
navController: NavController,
startAgain: Job
) {
val currentCoroutine = rememberCoroutineScope()
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.alert))
val progress by animateLottieCompositionAsState(composition)
val handler = CoroutineExceptionHandler { _, exception ->
Log.e("TCP Test", exception.message.toString())
}
Dialog(
onDismissRequest = {
openDialog.value = true
},
) {
Card(
shape = RoundedCornerShape(10.dp)
) {
Column(
modifier = Modifier
.padding(20.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
textAlign = TextAlign.Center,
fontWeight = FontWeight.SemiBold,
fontSize = 15.sp,
text = description.value,
color = MaterialTheme.colors.onSurface
)
Spacer(Modifier.height(15.dp))
LottieAnimation(
composition,
progress,
modifier = Modifier.size(100.dp)
)
Spacer(Modifier.height(15.dp))
Row(modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Button(
shape = RoundedCornerShape(25.dp),
modifier = Modifier.width(100.dp),
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
onClick = {
openDialog.value = false
EMVHelper().stopEMV()
navController.popBackStack()
}) {
Text("Back")
}
Button(
shape = RoundedCornerShape(25.dp),
modifier = Modifier.width(100.dp),
colors = ButtonDefaults.textButtonColors(
backgroundColor = StaticColorText,
contentColor = BgColor
),
onClick = {
openDialog.value = false
startAgain.start()
}) {
Text("Confirm")
}
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
Route Menu List
Use to display many menu and can select menu to action using list menu data for (Card Entry Menu Screen Section, Menu Entry Menu Screen Section, User Menu Screen Section) and The Button Component
code
@Composable
fun RouteMenu(navController: NavHostController, data: List<Route>, title: String) {
Text(
modifier = Modifier,
text = title,
fontSize = 15.sp,
fontWeight = FontWeight.SemiBold,
color = MaterialTheme.colors.onSurface
)
Spacer(modifier = Modifier.height(5.dp))
Row(
modifier = Modifier.fillMaxWidth()
) {
LazyVerticalGrid(
cells = GridCells.Fixed(3),
contentPadding = PaddingValues(5.dp)
) {
items(data.size) { item ->
// The Button Component
TheButton(data[item], navController)
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
The Button
Use to be button for process transaction
code
@Composable
fun TheButton(dataRoute: Route, navController: NavController ) {
val context = LocalContext.current
val openDialog = remember { mutableStateOf(false) }
val titleDialog = remember { mutableStateOf("") }
if (openDialog.value) {
if (titleDialog.value == "Echo Test") {
ShowTestHostList(title = titleDialog.value, openDialog = openDialog)
}
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Card(
shape = RoundedCornerShape(15.dp),
modifier = Modifier
.width(90.dp)
.height(90.dp),
backgroundColor = CardComingSoonColor
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.clickable {
when (dataRoute.group) {
"card_entry" -> {
// Function Event Of Card Entry Menu
getRouteCardEntry(
navController,
dataRoute
)
}
"menu_entry" -> {
// Function Event Of Menu Entry Menu
getRouteMenuEntry(
navController,
dataRoute,
openDialog,
titleDialog
)
}
"user_entry" -> {
// Function Event Of User Menu
getRouteUserMenu(
context,
navController,
dataRoute,
openDialog,
titleDialog
)
}
}
}
) {
Image(
painterResource( dataRoute.image),
dataRoute.title,
contentScale = ContentScale.Inside
)
}
}
Spacer(modifier = Modifier.height(5.dp))
Text(
text = dataRoute.title,
fontSize = 10.sp,
color = MaterialTheme.colors.onSurface
)
Spacer(modifier = Modifier.height(5.dp))
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
- Function Event Of Card Entry Menu
code
private fun eventRouteCardEntry(
navController: NavController,
dataRoute: Route
) {
DeviceHelper.me().emv.stopSearch()
if (dataRoute.path == th.emerchant.terminal.edc_pos.Route.WaitOperation.route) {
if (dataRoute.txnType == "balance_inquiry") {
val data =
"{" +
"title: \"${dataRoute.title}\"," +
"amount:\"\"," +
"transaction_type: \"${dataRoute.txnType}\"," +
"operation: \"magnetic\"" +
"}"
val jsonData = JSONObject(data)
navController.navigate("${dataRoute.path}/$jsonData") {
popUpTo(th.emerchant.terminal.edc_pos.Route.Home.route)
}
}
} else if (dataRoute.path == "amount") {
val jsonData = JSONObject()
jsonData.put("title", dataRoute.title)
jsonData.put("transaction_type", dataRoute.txnType)
navController.navigate("${dataRoute.path}/$jsonData") {
popUpTo(th.emerchant.terminal.edc_pos.Route.Home.route)
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
- Function Event Of Menu Entry Menu
code
private fun eventRouteMenuEntry(
navController: NavController,
dataRoute: Route,
openDialog: MutableState<Boolean>,
titleDialog: MutableState<String>
) {
if (dataRoute.popup) {
openDialog.value = dataRoute.popup
titleDialog.value = dataRoute.title
}
else {
DeviceHelper.me().emv.stopSearch()
val jsonData = JSONObject()
jsonData.put("route", th.emerchant.terminal.edc_pos.Route.SearchTransaction.route)
jsonData.put("transaction_title", dataRoute.title)
jsonData.put("transaction_type", dataRoute.txnType)
navController.navigate("${dataRoute.path}/$jsonData") {
popUpTo(th.emerchant.terminal.edc_pos.Route.Home.route)
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- Function Event Of User Menu
code
private fun eventRouteUserMenu(
context: Context,
navController: NavController,
dataRoute: Route,
openDialog: MutableState<Boolean>,
titleDialog: MutableState<String>
) {
if (dataRoute.popup) {
openDialog.value = dataRoute.popup
titleDialog.value = dataRoute.title
} else {
if (dataRoute.title == "Print Latest"){
Utils().reprintLastTransaction(context)
}
else if (dataRoute.path != ""){
DeviceHelper.me().emv.stopSearch()
val jsonData = JSONObject()
jsonData.put("route", th.emerchant.terminal.edc_pos.Route.SearchTransaction.route)
jsonData.put("transaction_title",dataRoute.txnType)
jsonData.put("transaction_type", dataRoute.txnType)
navController.navigate("${dataRoute.path}/$jsonData") {
popUpTo(th.emerchant.terminal.edc_pos.Route.Home.route)
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27