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)
            }
        }
    }
}
1
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
        }
    }
}
1
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")
                }
            }
        }
    }
}
1
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)
            }
        }
    }
}
1
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")
    }
}
1
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")
    }
}
1
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")
    }
}
1
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)
    }
}
1
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")
            }
        }
    }
}
1
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)
            }
        }
    }
}
1
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)
                }
            }
        }
    }
}
1
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
        )
    }
}
1
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)
    }
}
1
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")
                    }
                }
            }
    }
}
1
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,
                )
            }
        }
    }
}
1
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")
        }
    }
}
1
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)
    }
}
1
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
        )
    }
}
1
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)
    }
}
1
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)
    }
}
1
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
        )
    }
}
1
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)
    }
}
1
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()
        }
    }
}
1
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
        )
    }
}
1
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")
    }
}
1
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()
}
1
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)
    }
}
1
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
        )
    }
}
1
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 = ""
            }
        }
    }
}
1
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
        )
    }
}
1
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
                )
            }
        }
    }
}
1
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,
                )
            }
        }
    }
}
1
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")
        }
    }
}
1
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"
        }
    }
}
1
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)
    }
}
1
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
        )
    }
}
1
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
        }
    }
}
1
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
            )
        }
    }
}
1
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)
                    )
                }
            }
        }
    }
}
1
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)
    }
}
1
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
        )
    }
}
1
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)
    }
}
1
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!!)
    }
}
1
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,
            )
        }
    }
}
1
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")
        }
    }
}
1
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()
}
1
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)
    }
}
1
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"))
                }
            }
        }
    }
}
1
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
        )
    }
}
1
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
        )
    }
}
1
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")
        }
    }
}
1
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()
        }
    }
}
1
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()
    }
}
1
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
        )
    }
}
1
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
                    )
                }
            }
        }
    }
}
1
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
            )
        }
    }
}
1
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)
                )
            }
        }
    }
}
1
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
    }
}
1
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)
        }
    }
}
1
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")
        }
    }
}
1
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 }
            )
        }
    }
}
1
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
                    )
                }
            }
        }
    }
}
1
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
                    )
                }
            }
        }
    }
}
1
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
                )
            }
        }
    }
}
1
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")
                }
            }

        }
    }
}
1
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")
                    }
                }
            }

        }
    }
}
1
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)
                )
            }

        }
    }
}
1
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")
                }
            }

        }
    }
}
1
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)
                )
            }

        }
    }
}
1
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")
                }
            }
        }
    }
}
1
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")
                    }
                }
            }
        }
    }
}
1
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")
                    }
                }
            }
        }
    }
}
1
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")
                }
            }
        }
    }
}
1
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")
                }
            }
        }
    }
}
1
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")
                    }
                }
            }
        }
    }
}
1
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)
            }
        }
    }
}
1
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))
    }
}
1
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)
        }
    }
}
1
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)
        }
    }
}
1
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)
            }
        }
    }
}
1
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
Last Updated:
Contributors: Kittison Apaijit