card reader setup
This commit is contained in:
parent
32c4bf8fb7
commit
d3a6ddbc37
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="temurin-21" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.kotlin.compose)
|
||||
id("com.google.devtools.ksp")
|
||||
id("com.google.dagger.hilt.android")
|
||||
}
|
||||
|
||||
android {
|
||||
@ -44,10 +46,12 @@ dependencies {
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.compose.foundation)
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.compose.runtime)
|
||||
implementation(libs.androidx.compose.ui)
|
||||
implementation(libs.androidx.compose.ui.graphics)
|
||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
implementation(libs.androidx.core.ktx)
|
||||
implementation(libs.androidx.hilt.navigation.compose)
|
||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||
implementation(libs.androidx.navigation.compose)
|
||||
testImplementation(libs.junit)
|
||||
@ -57,4 +61,18 @@ dependencies {
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
||||
debugImplementation(libs.androidx.compose.ui.tooling)
|
||||
implementation("com.google.dagger:hilt-android:2.59.2")
|
||||
ksp(libs.hilt.android.compiler)
|
||||
implementation(libs.rxjava)
|
||||
implementation(libs.rxandroid)
|
||||
// local libs
|
||||
implementation(project(":baselib"))
|
||||
implementation(project(":mpulib"))
|
||||
implementation(project(":paylibs"))
|
||||
implementation(project(":paysdk-lib"))
|
||||
implementation(project(":qrgen-lib"))
|
||||
implementation(project(":sunmiui-lib"))
|
||||
implementation(project(":ecr"))
|
||||
implementation(project(":xpay"))
|
||||
implementation(project(":cmhl"))
|
||||
}
|
||||
@ -2,7 +2,32 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.telephony"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
android:required="false" />
|
||||
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="com.sunmi.perm.LED" />
|
||||
<uses-permission android:name="com.sunmi.perm.MSR" />
|
||||
<uses-permission android:name="com.sunmi.perm.ICC" />
|
||||
<uses-permission android:name="com.sunmi.perm.PINPAD" />
|
||||
<uses-permission android:name="com.sunmi.perm.SECURITY" />
|
||||
<uses-permission android:name="com.sunmi.perm.CONTACTLESS_CARD" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE"
|
||||
tools:ignore="ProtectedPermissions" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
|
||||
<application
|
||||
android:name="com.mob.utsmyanmar.MyApplication"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
@ -12,7 +37,7 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.MOBPOS">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:name="com.mob.utsmyanmar.MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.MOBPOS">
|
||||
|
||||
@ -7,7 +7,9 @@ import androidx.activity.enableEdgeToEdge
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.mob.utsmyanmar.ui.navigation.AppNavGraph
|
||||
import com.mob.utsmyanmar.ui.theme.MOBPOSTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
13
app/src/main/java/com/mob/utsmyanmar/MyApplication.kt
Normal file
13
app/src/main/java/com/mob/utsmyanmar/MyApplication.kt
Normal file
@ -0,0 +1,13 @@
|
||||
package com.mob.utsmyanmar
|
||||
|
||||
import com.mob.utsmyanmar.utils.AppContextHolder
|
||||
import com.utsmyanmar.baselib.BaseApplication
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
||||
@HiltAndroidApp
|
||||
class MyApplication : BaseApplication() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
AppContextHolder.init(this)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
package com.mob.utsmyanmar.model
|
||||
|
||||
enum class CardTransactionType {
|
||||
MPU, EMV, MAG, FALLBACK
|
||||
}
|
||||
39
app/src/main/java/com/mob/utsmyanmar/model/ProcessCode.kt
Normal file
39
app/src/main/java/com/mob/utsmyanmar/model/ProcessCode.kt
Normal file
@ -0,0 +1,39 @@
|
||||
package com.mob.utsmyanmar.model
|
||||
|
||||
object ProcessCode {
|
||||
const val BALANCE_INQUIRY = "31"
|
||||
|
||||
const val SALE_PURCHASE = "00"
|
||||
|
||||
const val SALE_VOID = "02"
|
||||
|
||||
const val PRE_AUTH_SALE = "30"
|
||||
|
||||
const val PRE_AUTH_VOID = "30"
|
||||
|
||||
const val PRE_AUTH_COMPLETE = "30"
|
||||
|
||||
const val PRE_AUTH_COMPLETE_VOID = "30"
|
||||
|
||||
const val CASH_ADVANCE = "01" // 01-MPU 17-TTIP
|
||||
|
||||
const val FUND_TRANSFER = "61"
|
||||
|
||||
const val PIN_CHANGE = "70"
|
||||
|
||||
const val SETTLEMENT = "92"
|
||||
|
||||
const val SIGN_ON = "95"
|
||||
|
||||
const val CASH_DEPOSIT = "21"
|
||||
|
||||
const val REFUND = "20"
|
||||
|
||||
const val SMART = "00"
|
||||
|
||||
const val SAVING = "10"
|
||||
|
||||
const val CURRENT = "20"
|
||||
|
||||
const val TO_ACCOUNT = "00"
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
package com.mob.utsmyanmar.model
|
||||
|
||||
enum class SettlementType {
|
||||
NORMAL,
|
||||
CUT_OVER
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.mob.utsmyanmar.model
|
||||
|
||||
enum class TransResultStatus {
|
||||
CLICK_CONFIRM,
|
||||
SUCCESS,
|
||||
FAIL,
|
||||
OFFLINE_SUCCESS,
|
||||
OFFLINE_FAILURE,
|
||||
SECONDARY,
|
||||
REVERSAL_PROCESS,
|
||||
REVERSAL_PREPARE,
|
||||
REVERSAL_SECONDARY,
|
||||
REVERSAL_THIRD,
|
||||
REVERSAL_FAIL,
|
||||
REVERSAL_SUCCESS,
|
||||
BEFORE_REVERSAL,
|
||||
PIN_PAD_CANCEL,
|
||||
PIN_PAD_CONFIRM,
|
||||
PIN_PAD_ERROR,
|
||||
PIN_MISMATCH,
|
||||
PIN_MISMATCH_END,
|
||||
REMOVED_CARD,
|
||||
EMV_ERROR,
|
||||
ERROR,
|
||||
RETRY_AGAIN,
|
||||
NEXT_SCREEN,
|
||||
EMPTY_PIN,
|
||||
NETWORK_ERROR
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package com.mob.utsmyanmar.model.ecr
|
||||
|
||||
enum class ECRResultStatus {
|
||||
USER_CANCEL,
|
||||
TIME_OUT,
|
||||
RESPONSE_RECEIVED
|
||||
}
|
||||
@ -137,7 +137,7 @@ fun AmountScreen(
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = "Next",
|
||||
text = "Enter",
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
package com.mob.utsmyanmar.ui.cardwaiting
|
||||
|
||||
sealed interface CardWaitingEvent {
|
||||
data object GoManualEntry : CardWaitingEvent
|
||||
data object GoProcessingCard : CardWaitingEvent
|
||||
data object GoTimeout : CardWaitingEvent
|
||||
data object GoMain : CardWaitingEvent
|
||||
data object GoBack : CardWaitingEvent
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
package com.mob.utsmyanmar.ui.cardwaiting
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.mob.utsmyanmar.ui.theme.White
|
||||
|
||||
@Composable
|
||||
fun CardWaitingScreen(
|
||||
viewModel: CardWaitingViewModel,
|
||||
onManualEntry: () -> Unit,
|
||||
onProcessingCard: () -> Unit,
|
||||
onTimeout: () -> Unit,
|
||||
onBack: () -> Unit,
|
||||
onMain: () -> Unit
|
||||
) {
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
|
||||
LaunchedEffect(viewModel) {
|
||||
viewModel.events.collect { event ->
|
||||
when (event) {
|
||||
CardWaitingEvent.GoManualEntry -> onManualEntry()
|
||||
CardWaitingEvent.GoProcessingCard -> onProcessingCard()
|
||||
CardWaitingEvent.GoTimeout -> onTimeout()
|
||||
CardWaitingEvent.GoMain -> onMain()
|
||||
CardWaitingEvent.GoBack -> onBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(viewModel) {
|
||||
viewModel.onScreenResume()
|
||||
}
|
||||
|
||||
DisposableEffect(viewModel) {
|
||||
onDispose {
|
||||
viewModel.onScreenPause()
|
||||
}
|
||||
}
|
||||
|
||||
BackHandler {
|
||||
viewModel.onBackPressed()
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(White)
|
||||
.padding(24.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text(
|
||||
text = "Card Capture",
|
||||
fontSize = 22.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(40.dp))
|
||||
|
||||
Text(
|
||||
text = uiState.alertMessage,
|
||||
fontSize = 20.sp,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
Button(
|
||||
onClick = viewModel::onManualEntryClick,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text("Manual Entry")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package com.mob.utsmyanmar.ui.cardwaiting
|
||||
|
||||
data class CardWaitingUiState(
|
||||
val alertMessage: String = "Please insert, tap, or swipe card",
|
||||
val isLoading: Boolean = false,
|
||||
val isFallback: Boolean = false
|
||||
)
|
||||
@ -0,0 +1,293 @@
|
||||
package com.mob.utsmyanmar.ui.cardwaiting
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.mob.utsmyanmar.model.CardTransactionType
|
||||
import com.mob.utsmyanmar.model.ecr.ECRResultStatus
|
||||
import com.mob.utsmyanmar.utils.CoreUtils
|
||||
import com.mob.utsmyanmar.viewmodel.CardReaderViewModel
|
||||
import com.mob.utsmyanmar.viewmodel.SharedViewModel
|
||||
import com.sunmi.pay.hardware.aidl.AidlConstants
|
||||
import com.utsmyanmar.checkxread.checkcard.CheckCardResultX
|
||||
import com.utsmyanmar.checkxread.util.CardTypeX
|
||||
import com.utsmyanmar.ecr.ECRHelper
|
||||
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
|
||||
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class CardWaitingViewModel(
|
||||
private val cardReadViewModel: CardReaderViewModel,
|
||||
private val sharedViewModel: SharedViewModel
|
||||
) : ViewModel() {
|
||||
|
||||
companion object {
|
||||
fun provideFactory(
|
||||
cardReadViewModel: CardReaderViewModel,
|
||||
sharedViewModel: SharedViewModel
|
||||
): ViewModelProvider.Factory {
|
||||
return object : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return CardWaitingViewModel(
|
||||
cardReadViewModel = cardReadViewModel,
|
||||
sharedViewModel = sharedViewModel
|
||||
) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val _uiState = MutableStateFlow(CardWaitingUiState())
|
||||
val uiState = _uiState.asStateFlow()
|
||||
|
||||
private val _events = Channel<CardWaitingEvent>()
|
||||
val events = _events.receiveAsFlow()
|
||||
|
||||
private var retryCounter = 0
|
||||
private var fallbackCounter = 0
|
||||
private var fallbackEnabled = false
|
||||
private var readerInitJob: Job? = null
|
||||
|
||||
fun onScreenResume() {
|
||||
retryCounter = 0
|
||||
fallbackCounter = SystemParamsOperation.getInstance().fallbackCounter
|
||||
fallbackEnabled = SystemParamsOperation.getInstance().fallbackEnabled
|
||||
|
||||
if (sharedViewModel.transactionsType.value == TransactionsType.REFUND) {
|
||||
sharedViewModel.enableCardStatusIcon(false, false, false, false)
|
||||
} else {
|
||||
sharedViewModel.enableCardStatusIcon(true, true, true, false)
|
||||
}
|
||||
|
||||
val isFallback = sharedViewModel.getIsFallback().value == true
|
||||
if (isFallback) {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
alertMessage = "Fallback!\nPlease stripe!",
|
||||
isFallback = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
startCardReadWhenReady(isFallback)
|
||||
}
|
||||
|
||||
fun onScreenPause() {
|
||||
readerInitJob?.cancel()
|
||||
stopCardReading()
|
||||
}
|
||||
|
||||
fun onBackPressed() {
|
||||
if (sharedViewModel.isEcr.value == true) {
|
||||
sharedViewModel.isEcr.postValue(false)
|
||||
CoreUtils.getInstance(sharedViewModel).responseRejectMsg("Transaction cancelled")
|
||||
sharedViewModel.isEcrFinished.postValue(true)
|
||||
}
|
||||
|
||||
stopCardReading()
|
||||
|
||||
viewModelScope.launch {
|
||||
_events.send(CardWaitingEvent.GoBack)
|
||||
}
|
||||
}
|
||||
|
||||
fun onManualEntryClick() {
|
||||
viewModelScope.launch {
|
||||
_events.send(CardWaitingEvent.GoManualEntry)
|
||||
}
|
||||
}
|
||||
|
||||
private fun startCardReadWhenReady(isFallback: Boolean) {
|
||||
readerInitJob?.cancel()
|
||||
readerInitJob = viewModelScope.launch {
|
||||
if (cardReadViewModel.isReaderReady()) {
|
||||
setupCardReadProcess(isFallback)
|
||||
return@launch
|
||||
}
|
||||
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
alertMessage = "Initializing card reader...",
|
||||
isLoading = true
|
||||
)
|
||||
}
|
||||
|
||||
repeat(10) {
|
||||
delay(300)
|
||||
if (cardReadViewModel.isReaderReady()) {
|
||||
_uiState.update { state ->
|
||||
state.copy(
|
||||
alertMessage = if (isFallback) {
|
||||
"Fallback!\nPlease stripe!"
|
||||
} else {
|
||||
"Please insert, tap, or swipe card"
|
||||
},
|
||||
isLoading = false
|
||||
)
|
||||
}
|
||||
setupCardReadProcess(isFallback)
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
alertMessage = "Card reader unavailable.\nPlease wait and try again.",
|
||||
isLoading = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCardReadProcess(isFallback: Boolean) {
|
||||
initCheckCard(isFallback)
|
||||
}
|
||||
|
||||
private fun initCheckCard(isFallback: Boolean) {
|
||||
var allType =
|
||||
AidlConstants.CardType.NFC.value or
|
||||
AidlConstants.CardType.IC.value or
|
||||
AidlConstants.CardType.MAGNETIC.value
|
||||
|
||||
if (isFallback) {
|
||||
allType = AidlConstants.CardType.MAGNETIC.value
|
||||
} else if (
|
||||
SystemParamsOperation.getInstance().isMagStripeEnabled &&
|
||||
!SystemParamsOperation.getInstance().isNfcEnabled
|
||||
) {
|
||||
allType =
|
||||
AidlConstants.CardType.IC.value or
|
||||
AidlConstants.CardType.MAGNETIC.value
|
||||
}
|
||||
|
||||
cardReadViewModel.startCheckXProcess(
|
||||
allType,
|
||||
65,
|
||||
object : CheckCardResultX {
|
||||
override fun onSuccess(cardType: CardTypeX, isMPU: Boolean) {
|
||||
when {
|
||||
!isFallback && cardType == CardTypeX.MAG -> {
|
||||
if (SystemParamsOperation.getInstance().isMagStripeEnabled) {
|
||||
cardReadViewModel.setCardTransactionType(CardTransactionType.MAG)
|
||||
} else {
|
||||
_uiState.update {
|
||||
it.copy(alertMessage = "Mag stripe not allowed")
|
||||
}
|
||||
setupCardReadProcess(false)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
isFallback && cardType == CardTypeX.MAG -> {
|
||||
sharedViewModel.setEmvTrans(false)
|
||||
cardReadViewModel.setCardTransactionType(CardTransactionType.FALLBACK)
|
||||
}
|
||||
|
||||
cardType == CardTypeX.IC || cardType == CardTypeX.NFC -> {
|
||||
if (isMPU) {
|
||||
sharedViewModel.setEmvTrans(false)
|
||||
cardReadViewModel.setCardTransactionType(CardTransactionType.MPU)
|
||||
} else {
|
||||
cardReadViewModel.setCardData(cardType.value)
|
||||
cardReadViewModel.setCardTransactionType(CardTransactionType.EMV)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
_events.send(CardWaitingEvent.GoProcessingCard)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(code: Int, message: String) {
|
||||
ecrActionCancel("Transaction cancelled")
|
||||
|
||||
viewModelScope.launch {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
alertMessage = message,
|
||||
isLoading = false
|
||||
)
|
||||
}
|
||||
_events.send(CardWaitingEvent.GoMain)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCommError() {
|
||||
if (fallbackEnabled && retryCounter < fallbackCounter) {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
alertMessage = "Card not detected!\nRemain Attempt - ${fallbackCounter - retryCounter}"
|
||||
)
|
||||
}
|
||||
retryCounter++
|
||||
setupCardReadProcess(false)
|
||||
return
|
||||
}
|
||||
|
||||
if (retryCounter == fallbackCounter) {
|
||||
_uiState.update {
|
||||
it.copy(alertMessage = "Fallback!\nPlease stripe!")
|
||||
}
|
||||
setupCardReadProcess(true)
|
||||
return
|
||||
}
|
||||
|
||||
ecrActionCancel("Transaction cancelled")
|
||||
|
||||
viewModelScope.launch {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
alertMessage = "Chip not detected!",
|
||||
isLoading = false
|
||||
)
|
||||
}
|
||||
_events.send(CardWaitingEvent.GoMain)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun ecrActionCancel(msg: String) {
|
||||
if (sharedViewModel.isEcr.value != true) {
|
||||
return
|
||||
}
|
||||
|
||||
sharedViewModel.isEcr.postValue(false)
|
||||
sharedViewModel.isEcrFinished.postValue(true)
|
||||
|
||||
if (SystemParamsOperation.getInstance().isCMHLEnabled) {
|
||||
ECRHelper.send(
|
||||
CoreUtils.getInstance(sharedViewModel)
|
||||
.generateCMHLResponse(ECRResultStatus.USER_CANCEL)
|
||||
)
|
||||
|
||||
CoreUtils.getInstance(sharedViewModel).responseACKCMHL()
|
||||
return
|
||||
}
|
||||
|
||||
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg)
|
||||
}
|
||||
|
||||
private fun stopCardReading() {
|
||||
sharedViewModel.setIsFallback(false)
|
||||
cardReadViewModel.cancelCheckCard()
|
||||
cardReadViewModel.resetOneTimeFlag()
|
||||
cardReadViewModel.cancelCheckXProcess()
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
readerInitJob?.cancel()
|
||||
stopCardReading()
|
||||
}
|
||||
}
|
||||
@ -1,13 +1,19 @@
|
||||
package com.mob.utsmyanmar.ui.navigation
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.navArgument
|
||||
import com.mob.utsmyanmar.ui.amount.AmountScreen
|
||||
import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingScreen
|
||||
import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingViewModel
|
||||
import com.mob.utsmyanmar.ui.dashboard.DashboardScreen
|
||||
import com.mob.utsmyanmar.viewmodel.CardReaderViewModel
|
||||
import com.mob.utsmyanmar.viewmodel.SharedViewModel
|
||||
|
||||
@Composable
|
||||
fun AppNavGraph(
|
||||
@ -42,7 +48,38 @@ fun AppNavGraph(
|
||||
) { backStackEntry ->
|
||||
AmountScreen(
|
||||
action = backStackEntry.arguments?.getString("action").orEmpty(),
|
||||
onBackClick = { navController.popBackStack() }
|
||||
onBackClick = { navController.popBackStack() },
|
||||
onCancelClick = { navController.popBackStack() },
|
||||
onNextClick = {
|
||||
navController.navigate(Routes.CardWaiting.route)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
composable(Routes.CardWaiting.route) {
|
||||
val sharedViewModel: SharedViewModel = hiltViewModel()
|
||||
val cardReaderViewModel: CardReaderViewModel = hiltViewModel()
|
||||
val cardWaitingViewModel: CardWaitingViewModel = viewModel(
|
||||
factory = CardWaitingViewModel.provideFactory(
|
||||
cardReadViewModel = cardReaderViewModel,
|
||||
sharedViewModel = sharedViewModel
|
||||
)
|
||||
)
|
||||
|
||||
CardWaitingScreen(
|
||||
viewModel = cardWaitingViewModel,
|
||||
onManualEntry = {},
|
||||
onProcessingCard = {},
|
||||
onTimeout = { navController.popBackStack() },
|
||||
onBack = { navController.popBackStack() },
|
||||
onMain = {
|
||||
navController.navigate(Routes.Dashboard.route) {
|
||||
popUpTo(Routes.Dashboard.route) {
|
||||
inclusive = false
|
||||
}
|
||||
launchSingleTop = true
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,4 +5,5 @@ sealed class Routes(val route: String) {
|
||||
data object Amount : Routes("amount/{action}") {
|
||||
fun createRoute(action: String): String = "amount/$action"
|
||||
}
|
||||
data object CardWaiting : Routes("card_waiting")
|
||||
}
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
package com.mob.utsmyanmar.utils
|
||||
|
||||
import android.content.Context
|
||||
|
||||
object AppContextHolder {
|
||||
private lateinit var appContext: Context
|
||||
|
||||
fun init(context: Context) {
|
||||
appContext = context.applicationContext
|
||||
}
|
||||
|
||||
fun get(): Context {
|
||||
return appContext
|
||||
}
|
||||
}
|
||||
1037
app/src/main/java/com/mob/utsmyanmar/utils/CoreUtils.kt
Normal file
1037
app/src/main/java/com/mob/utsmyanmar/utils/CoreUtils.kt
Normal file
File diff suppressed because it is too large
Load Diff
17
app/src/main/java/com/mob/utsmyanmar/utils/ECRSetups.kt
Normal file
17
app/src/main/java/com/mob/utsmyanmar/utils/ECRSetups.kt
Normal file
@ -0,0 +1,17 @@
|
||||
package com.mob.utsmyanmar.utils
|
||||
|
||||
import com.utsmyanmar.ecr.data.model.Transactions
|
||||
|
||||
interface ECRSetups {
|
||||
fun setUpECREchoTest()
|
||||
fun setUpECRSale(trans: Transactions): Boolean
|
||||
fun setUpECRQR(trans: Transactions): Boolean
|
||||
fun setUpECRVoid(trans: Transactions): Boolean
|
||||
fun setUpECRCashAdvance(trans: Transactions): Boolean
|
||||
fun setUpECRPreAuth(trans: Transactions): Boolean
|
||||
fun setUpECRPreAuthVoid(trans: Transactions): Boolean
|
||||
fun setUpECRPreAuthComplete(trans: Transactions): Boolean
|
||||
fun setUpECRPreAuthCompleteVoid(trans: Transactions): Boolean
|
||||
fun setUpECRSettlement()
|
||||
fun setUpECRRefund(trans: Transactions): Boolean
|
||||
}
|
||||
24
app/src/main/java/com/mob/utsmyanmar/utils/ECRSetupsCMHL.kt
Normal file
24
app/src/main/java/com/mob/utsmyanmar/utils/ECRSetupsCMHL.kt
Normal file
@ -0,0 +1,24 @@
|
||||
package com.mob.utsmyanmar.utils
|
||||
|
||||
import com.kizzy.cmhl.models.PingRequest
|
||||
import com.kizzy.cmhl.models.PreAuthCancellationRequest
|
||||
import com.kizzy.cmhl.models.PreAuthCompletionRequest
|
||||
import com.kizzy.cmhl.models.PreAuthRequest
|
||||
import com.kizzy.cmhl.models.QrPaymentRequest
|
||||
import com.kizzy.cmhl.models.SaleRequest
|
||||
import com.kizzy.cmhl.models.SettlementRequest
|
||||
import com.kizzy.cmhl.models.VoidQrPaymentRequest
|
||||
import com.kizzy.cmhl.models.VoidRequest
|
||||
|
||||
interface ECRSetupsCMHL {
|
||||
fun setUpECREchoTest()
|
||||
fun setupPingRequest(trans: PingRequest)
|
||||
fun setUpECRSale(trans: SaleRequest): Boolean
|
||||
fun setUpECRQR(trans: QrPaymentRequest): Boolean
|
||||
fun setUpECRQRVoid(trans: VoidQrPaymentRequest): Boolean
|
||||
fun setUpECRVoid(trans: VoidRequest): Boolean
|
||||
fun setUpECRPreAuth(trans: PreAuthRequest): Boolean
|
||||
fun setUpECRPreAuthVoid(trans: PreAuthCancellationRequest): Boolean
|
||||
fun setUpECRPreAuthComplete(trans: PreAuthCompletionRequest): Boolean
|
||||
fun setUpECRSettlement(trans: SettlementRequest)
|
||||
}
|
||||
14
app/src/main/java/com/mob/utsmyanmar/utils/OldECRSetups.kt
Normal file
14
app/src/main/java/com/mob/utsmyanmar/utils/OldECRSetups.kt
Normal file
@ -0,0 +1,14 @@
|
||||
package com.mob.utsmyanmar.utils
|
||||
|
||||
interface OldECRSetups {
|
||||
fun setUpECRTest()
|
||||
fun setUpECRSale(msg: String): Boolean
|
||||
fun setUpECRVoid(msg: String): Boolean
|
||||
fun setUpECRCashAdvance(msg: String): Boolean
|
||||
fun setUpECRPreAuth(msg: String): Boolean
|
||||
fun setUpECRPreAuthVoid(msg: String): Boolean
|
||||
fun setUpECRPreAuthComplete(msg: String): Boolean
|
||||
fun setUpECRPreAuthCompleteVoid(msg: String): Boolean
|
||||
fun setUpECRSettlement()
|
||||
fun setUpECRRefund(msg: String): Boolean
|
||||
}
|
||||
@ -0,0 +1,152 @@
|
||||
package com.mob.utsmyanmar.viewmodel
|
||||
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.mob.utsmyanmar.model.CardTransactionType
|
||||
import com.utsmyanmar.checkxread.CheckXRead
|
||||
import com.utsmyanmar.checkxread.checkcard.CheckCardResultX
|
||||
import com.utsmyanmar.checkxread.model.CardDataX
|
||||
import com.utsmyanmar.checkxread.readcard.ReadCardResultX
|
||||
import com.utsmyanmar.checkxread.readcard.ReadCardX
|
||||
import com.utsmyanmar.checkxread.sdk.SunmiSDK
|
||||
import com.utsmyanmar.paylibs.model.PayDetail
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class CardReaderViewModel @Inject constructor() : ViewModel() {
|
||||
|
||||
companion object {
|
||||
private val TAG = CardReaderViewModel::class.java.simpleName
|
||||
}
|
||||
|
||||
private val mainThreadHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
private var oneTimeFlag = false
|
||||
|
||||
private var cardTransactionType: CardTransactionType? = null
|
||||
|
||||
/*
|
||||
* UI States
|
||||
*/
|
||||
|
||||
private val _errorCode = MutableStateFlow("")
|
||||
val errorCode = _errorCode.asStateFlow()
|
||||
|
||||
private val _cardData = MutableStateFlow<CardDataX?>(null)
|
||||
val cardData = _cardData.asStateFlow()
|
||||
|
||||
private var _cardTypeData = MutableStateFlow<Int?>(null)
|
||||
val cardTypeData = _cardTypeData.asStateFlow()
|
||||
|
||||
private val _payDetail = MutableStateFlow<PayDetail?>(null)
|
||||
val payDetail = _payDetail.asStateFlow()
|
||||
|
||||
private val _checkCardAlertMsg =
|
||||
MutableStateFlow<String?>(null)
|
||||
val checkCardAlertMsg =
|
||||
_checkCardAlertMsg.asStateFlow()
|
||||
|
||||
/*
|
||||
* Transaction Type
|
||||
*/
|
||||
|
||||
fun setCardTransactionType(
|
||||
cardTransactionType: CardTransactionType
|
||||
) {
|
||||
this.cardTransactionType = cardTransactionType
|
||||
}
|
||||
|
||||
fun getCardTransactionType(): CardTransactionType? {
|
||||
return cardTransactionType
|
||||
}
|
||||
|
||||
/*
|
||||
* Check Card Process
|
||||
*/
|
||||
|
||||
fun startCheckXProcess(
|
||||
allType: Int,
|
||||
timeOut: Int,
|
||||
cardResultX: CheckCardResultX
|
||||
) {
|
||||
CheckXRead.getInstance()
|
||||
.startCheckXProcess(
|
||||
allType,
|
||||
timeOut,
|
||||
cardResultX
|
||||
)
|
||||
}
|
||||
|
||||
fun isReaderReady(): Boolean {
|
||||
return SunmiSDK.getInstance().readCardOptV2 != null
|
||||
}
|
||||
|
||||
fun cancelCheckXProcess() {
|
||||
CheckXRead.getInstance()
|
||||
.cancelCheckXProcess()
|
||||
}
|
||||
|
||||
/*
|
||||
* Read Card Process
|
||||
*/
|
||||
|
||||
fun startReadXProcess(
|
||||
readCardX: ReadCardX,
|
||||
readCardResultX: ReadCardResultX
|
||||
) {
|
||||
CheckXRead.getInstance()
|
||||
.startReadXProcess(
|
||||
readCardX,
|
||||
readCardResultX
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
* Alert Message
|
||||
*/
|
||||
|
||||
fun setCheckCardAlertMsg(
|
||||
msg: String,
|
||||
isAutoHide: Boolean
|
||||
) {
|
||||
_checkCardAlertMsg.value = msg
|
||||
|
||||
if (isAutoHide) {
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
_checkCardAlertMsg.value = null
|
||||
}, 5000)
|
||||
}
|
||||
}
|
||||
|
||||
fun resetUI() {
|
||||
_checkCardAlertMsg.value = null
|
||||
}
|
||||
|
||||
/*
|
||||
* One Time Flag
|
||||
*/
|
||||
|
||||
fun resetOneTimeFlag() {
|
||||
oneTimeFlag = false
|
||||
}
|
||||
|
||||
/*
|
||||
* Cancel Card Checking
|
||||
*/
|
||||
|
||||
fun cancelCheckCard() {
|
||||
if (isReaderReady()) {
|
||||
SunmiSDK.getInstance()
|
||||
.cancelCheckCard()
|
||||
}
|
||||
}
|
||||
|
||||
fun setCardData(value: Int){
|
||||
_cardTypeData.value = value
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.mob.utsmyanmar.viewmodel
|
||||
|
||||
import com.mob.utsmyanmar.model.TransResultStatus
|
||||
import com.utsmyanmar.paylibs.model.PayDetail
|
||||
import com.utsmyanmar.paylibs.system.SingleLiveEvent
|
||||
|
||||
interface ProcessingTransaction {
|
||||
fun resetTransactionStatus()
|
||||
|
||||
fun getTransStatus(): SingleLiveEvent<TransResultStatus>
|
||||
|
||||
fun startOnlineProcess()
|
||||
|
||||
fun insertDB(payResult: PayDetail)
|
||||
|
||||
fun processVoidDB(payResult: PayDetail)
|
||||
|
||||
fun processPreVoidDb(payResult: PayDetail)
|
||||
|
||||
fun processPreCompDb(payResult: PayDetail)
|
||||
|
||||
fun processPreCompVoidDb(payResult: PayDetail)
|
||||
|
||||
fun processRefundDB(payResult: PayDetail)
|
||||
}
|
||||
@ -0,0 +1,476 @@
|
||||
package com.mob.utsmyanmar.viewmodel
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.mob.utsmyanmar.model.SettlementType
|
||||
import com.utsmyanmar.baselib.network.model.sirius.SiriusRequest
|
||||
import com.utsmyanmar.baselib.network.model.sirius.SiriusResponse
|
||||
import com.utsmyanmar.baselib.repo.Repository
|
||||
import com.utsmyanmar.ecr.data.TransType
|
||||
import com.utsmyanmar.ecr.data.model.Transactions
|
||||
import com.utsmyanmar.paylibs.model.PayDetail
|
||||
import com.utsmyanmar.paylibs.print.printx.PrintXReceipt
|
||||
import com.utsmyanmar.paylibs.print.printx.PrintXStatus
|
||||
import com.utsmyanmar.paylibs.system.SingleLiveEvent
|
||||
import com.utsmyanmar.paylibs.utils.AccountType
|
||||
import com.utsmyanmar.paylibs.utils.PrintStatus
|
||||
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
|
||||
import com.utsmyanmar.paylibs.utils.enums.HostType
|
||||
import com.utsmyanmar.paylibs.utils.enums.TransMenu
|
||||
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import sunmi.sunmiui.utils.LogUtil
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class SharedViewModel @Inject constructor(
|
||||
private val repository: Repository
|
||||
) : ViewModel() {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "SharedViewModel"
|
||||
}
|
||||
|
||||
val transactionsType = SingleLiveEvent<TransactionsType>()
|
||||
|
||||
val settlementType = SingleLiveEvent<SettlementType>()
|
||||
|
||||
val accountType = SingleLiveEvent<AccountType>()
|
||||
|
||||
val amount = SingleLiveEvent<String>()
|
||||
|
||||
val totalAmount = SingleLiveEvent<Long>()
|
||||
|
||||
val cardNo = SingleLiveEvent<String>()
|
||||
|
||||
val processCode = SingleLiveEvent<String>()
|
||||
|
||||
val payDetail = SingleLiveEvent<PayDetail>()
|
||||
|
||||
val printStatus = SingleLiveEvent<PrintStatus>()
|
||||
|
||||
val merchantName = SingleLiveEvent<String>()
|
||||
|
||||
val transactionName = SingleLiveEvent<String>()
|
||||
|
||||
val payDetailList = SingleLiveEvent<List<PayDetail>>()
|
||||
|
||||
val isEcr = SingleLiveEvent<Boolean>()
|
||||
|
||||
val traceNo = SingleLiveEvent<String>()
|
||||
|
||||
val rrNNo = SingleLiveEvent<String>()
|
||||
|
||||
val approvalCode = SingleLiveEvent<String>()
|
||||
|
||||
val isEcrFinished = SingleLiveEvent<Boolean>()
|
||||
|
||||
val isEmv = SingleLiveEvent<Boolean>()
|
||||
|
||||
private val settlementStatus = MutableLiveData<Boolean>()
|
||||
|
||||
private val wavePayStatus = MutableLiveData<Boolean>()
|
||||
|
||||
val sendMsg = SingleLiveEvent<String>()
|
||||
|
||||
val qrData = SingleLiveEvent<String>()
|
||||
|
||||
val qrRefNum = SingleLiveEvent<String>()
|
||||
|
||||
val ecrCMD = SingleLiveEvent<TransType>()
|
||||
|
||||
val _transMenu = SingleLiveEvent<TransMenu?>()
|
||||
|
||||
val twoBtnLayout = MutableLiveData(0)
|
||||
|
||||
val oneBtnLayout = MutableLiveData(8)
|
||||
|
||||
private val reprintBtnLayout = MutableLiveData(8)
|
||||
|
||||
val isReprint = SingleLiveEvent<Boolean>()
|
||||
|
||||
var signBitmap: Bitmap? = null
|
||||
|
||||
val hostType = SingleLiveEvent<HostType>()
|
||||
|
||||
private val printReceiptButtons = MutableLiveData(0)
|
||||
|
||||
val printReceiptMsg = SingleLiveEvent<String>()
|
||||
|
||||
val reprintTransTypeMsg = SingleLiveEvent<String>()
|
||||
|
||||
val ecrTrans = SingleLiveEvent<Transactions>()
|
||||
|
||||
val _manualEntryStatus = MutableLiveData<Boolean>()
|
||||
|
||||
val fullVoidPreauthStatus = MutableLiveData<Boolean>()
|
||||
|
||||
val partialVoidPreauthStatus = MutableLiveData<Boolean>()
|
||||
|
||||
val printXStatus = SingleLiveEvent<PrintStatus>()
|
||||
|
||||
private val _errorFragmentMsg = SingleLiveEvent<String>()
|
||||
|
||||
private val _successFragmentMsg = SingleLiveEvent<String>()
|
||||
|
||||
private val _currencyText = SingleLiveEvent<String>()
|
||||
|
||||
val tapCardStatus = MutableLiveData(1)
|
||||
|
||||
val tapDeviceStatus = MutableLiveData(1)
|
||||
|
||||
val insertCardStatus = MutableLiveData(1)
|
||||
|
||||
val swipeCardStatus = MutableLiveData(0)
|
||||
|
||||
val countDownTxt = MutableLiveData<String>()
|
||||
|
||||
val mmqrLoading = MutableLiveData<Int>()
|
||||
|
||||
val isMMPay = MutableLiveData<Int>()
|
||||
|
||||
val isWavePay = MutableLiveData<Int>()
|
||||
|
||||
val mockData = SingleLiveEvent<String>()
|
||||
|
||||
val qrPayVisibility = MutableLiveData<Int>()
|
||||
|
||||
val loadingView = MutableLiveData(8)
|
||||
|
||||
val loadingMsg = SingleLiveEvent<String>()
|
||||
|
||||
private val isFallback = SingleLiveEvent<Boolean>()
|
||||
|
||||
private val _isCardDataExist = SingleLiveEvent<Boolean>()
|
||||
|
||||
private val _isAmountExist = SingleLiveEvent<Boolean>()
|
||||
|
||||
private var mPayDetail = PayDetail()
|
||||
|
||||
init {
|
||||
setPrintStatus(PrintStatus.FIRST_PRINT)
|
||||
isReprint.value = false
|
||||
cardNo.value = ""
|
||||
}
|
||||
|
||||
fun setSettlementStatus(status: Boolean) {
|
||||
settlementStatus.value = status
|
||||
}
|
||||
|
||||
fun getSettlementStatus(): MutableLiveData<Boolean> {
|
||||
return settlementStatus
|
||||
}
|
||||
|
||||
fun setWavePayStatus(status: Boolean) {
|
||||
wavePayStatus.value = status
|
||||
}
|
||||
|
||||
fun getWavePayStatus(): MutableLiveData<Boolean> {
|
||||
return wavePayStatus
|
||||
}
|
||||
|
||||
fun setEmvTrans(status: Boolean) {
|
||||
isEmv.value = status
|
||||
}
|
||||
|
||||
fun isEmvTrans(): SingleLiveEvent<Boolean> {
|
||||
return isEmv
|
||||
}
|
||||
|
||||
private fun getPayDetail(): PayDetail {
|
||||
return mPayDetail
|
||||
}
|
||||
|
||||
private fun cachePayDetail(payDetail: PayDetail) {
|
||||
mPayDetail = payDetail
|
||||
}
|
||||
|
||||
fun setPrintReceiptButtons(visible: Boolean) {
|
||||
printReceiptButtons.value = if (visible) 0 else 8
|
||||
}
|
||||
|
||||
fun postPrintReceiptButtons(visible: Boolean) {
|
||||
printReceiptButtons.postValue(if (visible) 0 else 8)
|
||||
}
|
||||
|
||||
fun getPrintReceiptButtons(): MutableLiveData<Int> {
|
||||
return printReceiptButtons
|
||||
}
|
||||
|
||||
fun getReprintBtnLayout(): MutableLiveData<Int> {
|
||||
return reprintBtnLayout
|
||||
}
|
||||
|
||||
fun setReprintBtnLayout(visible: Boolean) {
|
||||
reprintBtnLayout.value = if (visible) 0 else 8
|
||||
}
|
||||
|
||||
fun setPrintReceiptMsg(msg: String) {
|
||||
printReceiptMsg.value = msg
|
||||
}
|
||||
|
||||
fun postPrintReceiptMsg(msg: String) {
|
||||
printReceiptMsg.postValue(msg)
|
||||
}
|
||||
|
||||
fun setPrintStatus(printStatus: PrintStatus) {
|
||||
this.printStatus.value = printStatus
|
||||
}
|
||||
|
||||
fun postPrintStatus(printStatus: PrintStatus) {
|
||||
this.printStatus.postValue(printStatus)
|
||||
}
|
||||
|
||||
fun getPrintStatusEvent(): SingleLiveEvent<PrintStatus> {
|
||||
return printStatus
|
||||
}
|
||||
|
||||
fun setIsFallback(status: Boolean) {
|
||||
isFallback.value = status
|
||||
}
|
||||
|
||||
fun getIsFallback(): SingleLiveEvent<Boolean> {
|
||||
return isFallback
|
||||
}
|
||||
|
||||
fun setCardDataExist(exist: Boolean) {
|
||||
_isCardDataExist.value = exist
|
||||
}
|
||||
|
||||
fun getCardDataExist(): SingleLiveEvent<Boolean> {
|
||||
return _isCardDataExist
|
||||
}
|
||||
|
||||
fun setAmountExist(exist: Boolean) {
|
||||
_isAmountExist.value = exist
|
||||
}
|
||||
|
||||
fun getAmountExist(): SingleLiveEvent<Boolean> {
|
||||
return _isAmountExist
|
||||
}
|
||||
|
||||
fun getManualEntryStatus(): MutableLiveData<Boolean> {
|
||||
return _manualEntryStatus
|
||||
}
|
||||
|
||||
fun setManualEntryStatus(status: Boolean) {
|
||||
_manualEntryStatus.value = status
|
||||
}
|
||||
|
||||
fun getErrorFragmentMsg(): SingleLiveEvent<String> {
|
||||
return _errorFragmentMsg
|
||||
}
|
||||
|
||||
fun set_errorFragmentMsg(msg: String) {
|
||||
_errorFragmentMsg.value = msg
|
||||
}
|
||||
|
||||
fun getSuccessFragmentMsg(): SingleLiveEvent<String> {
|
||||
return _successFragmentMsg
|
||||
}
|
||||
|
||||
fun set_currencyText(msg: String) {
|
||||
_currencyText.value = msg
|
||||
}
|
||||
|
||||
fun get_currencyText(): SingleLiveEvent<String> {
|
||||
return _currencyText
|
||||
}
|
||||
|
||||
fun set_successFragmentMsg(msg: String) {
|
||||
_successFragmentMsg.value = msg
|
||||
}
|
||||
|
||||
fun getTransMenu(): SingleLiveEvent<TransMenu?> {
|
||||
return _transMenu
|
||||
}
|
||||
|
||||
fun setTransMenu(transMenu: TransMenu?) {
|
||||
_transMenu.value = transMenu
|
||||
}
|
||||
|
||||
fun loadingMsg(msg: String) {
|
||||
loadingView.value = 0
|
||||
loadingMsg.value = msg
|
||||
}
|
||||
|
||||
fun dismissLoadingMsg() {
|
||||
loadingView.value = 8
|
||||
loadingMsg.value = ""
|
||||
}
|
||||
|
||||
fun getParams(siriusRequest: SiriusRequest): Observable<SiriusResponse> {
|
||||
return repository.getParams(siriusRequest)
|
||||
}
|
||||
|
||||
private fun printReceipt(isMerchantCopy: Boolean) {
|
||||
PrintXReceipt.getInstance()
|
||||
.printSmileReceipt(payDetail.value, isMerchantCopy, object : PrintXStatus {
|
||||
|
||||
override fun onSuccess() {
|
||||
|
||||
if (isMerchantCopy) {
|
||||
|
||||
if (!SystemParamsOperation.getInstance().demoStatus) {
|
||||
if (SystemParamsOperation.getInstance().printISOStatus) {
|
||||
PrintXReceipt.getInstance()
|
||||
.printSmileISoReceipt(payDetail.value)
|
||||
}
|
||||
}
|
||||
|
||||
postPrintStatus(PrintStatus.FIRST_PRINT_DONE)
|
||||
|
||||
} else {
|
||||
setPrintStatus(PrintStatus.SECOND_PRINT_DONE)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure() {
|
||||
LogUtil.d(TAG, "Print Status Result Failure!")
|
||||
printXStatus.postValue(PrintStatus.EMPTY_PAPER_ROLL)
|
||||
postPrintReceiptButtons(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun startPrintReceipt(isFirstPrint: Boolean) {
|
||||
|
||||
payDetail.value?.let {
|
||||
cachePayDetail(it)
|
||||
}
|
||||
|
||||
PrintXReceipt.getInstance()
|
||||
.printSmileReceipt(getPayDetail(), isFirstPrint, object : PrintXStatus {
|
||||
|
||||
override fun onSuccess() {
|
||||
|
||||
if (isFirstPrint) {
|
||||
|
||||
if (!SystemParamsOperation.getInstance().demoStatus) {
|
||||
if (SystemParamsOperation.getInstance().printISOStatus) {
|
||||
PrintXReceipt.getInstance()
|
||||
.printSmileISoReceipt(getPayDetail())
|
||||
}
|
||||
}
|
||||
|
||||
postPrintStatus(PrintStatus.FIRST_PRINT_DONE)
|
||||
|
||||
if (isEcr.value == true &&
|
||||
SystemParamsOperation.getInstance()
|
||||
.isAutoPrintCustomerCopy
|
||||
) {
|
||||
printReceiptButtons.postValue(8)
|
||||
} else {
|
||||
printReceiptButtons.postValue(0)
|
||||
}
|
||||
|
||||
} else {
|
||||
postPrintStatus(PrintStatus.SECOND_PRINT_DONE)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure() {
|
||||
LogUtil.d(TAG, "Print Status Result Failure!")
|
||||
|
||||
if (isFirstPrint) {
|
||||
setPrintStatus(PrintStatus.EMPTY_PAPER_ROLL_FIRST)
|
||||
} else {
|
||||
setPrintStatus(PrintStatus.EMPTY_PAPER_ROLL_SECOND)
|
||||
}
|
||||
|
||||
postPrintReceiptButtons(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun startPrintProcess() {
|
||||
|
||||
LogUtil.d(TAG, "Print status : ${getPrintStatusEvent().value}")
|
||||
|
||||
when (getPrintStatusEvent().value) {
|
||||
|
||||
PrintStatus.FIRST_PRINT -> {
|
||||
printReceipt(true)
|
||||
postPrintReceiptMsg("Printing Receipt for Merchant")
|
||||
postPrintReceiptButtons(false)
|
||||
}
|
||||
|
||||
PrintStatus.SECOND_PRINT -> {
|
||||
printReceipt(false)
|
||||
postPrintReceiptMsg("Printing Receipt for Customer")
|
||||
}
|
||||
|
||||
PrintStatus.NOT_PRINT -> {
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
fun startPrintProcessSettlement() {
|
||||
|
||||
val detail = payDetail.value ?: return
|
||||
|
||||
PrintXReceipt.getInstance()
|
||||
.printSmileSettlementReport(detail, object : PrintXStatus {
|
||||
|
||||
override fun onSuccess() {
|
||||
}
|
||||
|
||||
override fun onFailure() {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun getLastThreeTransactions(): LiveData<List<PayDetail>> {
|
||||
return repository.getLastThreeTransactions()
|
||||
}
|
||||
|
||||
fun getReversalTransaction(voucherNo: String): LiveData<PayDetail> {
|
||||
return repository.getReversalTransaction(voucherNo)
|
||||
}
|
||||
|
||||
fun updatePayDetail(payDetail: PayDetail) {
|
||||
repository.updatePayDetail(payDetail)
|
||||
}
|
||||
|
||||
fun insertPayDetail(payDetail: PayDetail) {
|
||||
repository.insertPayDetail(payDetail)
|
||||
}
|
||||
|
||||
fun enableCardStatusIcon(
|
||||
tapCard: Boolean,
|
||||
tapDevice: Boolean,
|
||||
insertCard: Boolean,
|
||||
swipeCard: Boolean
|
||||
) {
|
||||
|
||||
tapCardStatus.value = if (tapCard) 1 else 0
|
||||
tapDeviceStatus.value = if (tapDevice) 1 else 0
|
||||
insertCardStatus.value = if (insertCard) 1 else 0
|
||||
swipeCardStatus.value = if (swipeCard) 1 else 0
|
||||
}
|
||||
|
||||
fun resetParamsMain() {
|
||||
|
||||
isEcrFinished.postValue(true)
|
||||
isEcr.postValue(false)
|
||||
|
||||
setAmountExist(false)
|
||||
setCardDataExist(false)
|
||||
setTransMenu(null)
|
||||
}
|
||||
|
||||
fun updateButtonStatus() {
|
||||
setSettlementStatus(
|
||||
SystemParamsOperation.getInstance().settlementStatus
|
||||
)
|
||||
|
||||
setWavePayStatus(
|
||||
SystemParamsOperation.getInstance().wavePayStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,346 @@
|
||||
package com.mob.utsmyanmar.viewmodel
|
||||
|
||||
import android.text.TextUtils
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.mob.utsmyanmar.model.TransResultStatus
|
||||
import com.utsmyanmar.baselib.repo.Repository
|
||||
import com.utsmyanmar.paylibs.model.PayDetail
|
||||
import com.utsmyanmar.paylibs.model.TradeData
|
||||
import com.utsmyanmar.paylibs.network.ISOSocket
|
||||
import com.utsmyanmar.paylibs.reversal.ReversalAction
|
||||
import com.utsmyanmar.paylibs.reversal.ReversalListener
|
||||
import com.utsmyanmar.paylibs.system.SystemDateTime
|
||||
import com.utsmyanmar.paylibs.transactions.TransactionsOperation
|
||||
import com.utsmyanmar.paylibs.transactions.TransactionsOperationListener
|
||||
import com.utsmyanmar.paylibs.utils.PrintStatus
|
||||
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
|
||||
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class TransProcessViewModel @Inject constructor(
|
||||
private val repository: Repository
|
||||
) : ViewModel(), ProcessingTransaction {
|
||||
|
||||
companion object {
|
||||
private const val RC_APPROVED_V1 = "00"
|
||||
private const val RC_APPROVED_V2 = "000"
|
||||
private const val TRY_SECONDARY = "TRY_SECONDARY"
|
||||
}
|
||||
|
||||
private var pan: String = ""
|
||||
|
||||
private lateinit var tradeData: TradeData
|
||||
|
||||
var payDetail: PayDetail? = null
|
||||
|
||||
private var oldTransPayDetail: PayDetail? = null
|
||||
|
||||
private var isSecondCall = false
|
||||
private var isThirdCall = false
|
||||
|
||||
/*
|
||||
* States
|
||||
*/
|
||||
|
||||
private val _transResultStatus =
|
||||
MutableStateFlow<TransResultStatus?>(null)
|
||||
|
||||
val transResultStatus =
|
||||
_transResultStatus.asStateFlow()
|
||||
|
||||
private val _transType =
|
||||
MutableStateFlow<TransactionsType?>(null)
|
||||
|
||||
val transType =
|
||||
_transType.asStateFlow()
|
||||
|
||||
private val _printStatus =
|
||||
MutableStateFlow(PrintStatus.FIRST_PRINT)
|
||||
|
||||
val printStatus =
|
||||
_printStatus.asStateFlow()
|
||||
|
||||
private val _payDetailResult =
|
||||
MutableStateFlow<PayDetail?>(null)
|
||||
|
||||
val payDetailResult =
|
||||
_payDetailResult.asStateFlow()
|
||||
|
||||
private val _errorMessage =
|
||||
MutableStateFlow<String?>(null)
|
||||
|
||||
val errorMessage =
|
||||
_errorMessage.asStateFlow()
|
||||
|
||||
/*
|
||||
* Setup
|
||||
*/
|
||||
|
||||
fun setTradeData(tradeData: TradeData) {
|
||||
this.tradeData = tradeData
|
||||
payDetail = tradeData.payDetail
|
||||
pan = payDetail?.cardNo ?: ""
|
||||
}
|
||||
|
||||
fun getTradeData(): TradeData {
|
||||
return tradeData
|
||||
}
|
||||
|
||||
fun updatePayDetail(payDetail: PayDetail) {
|
||||
this.payDetail = payDetail
|
||||
|
||||
tradeData = TradeData().apply {
|
||||
this.payDetail = payDetail
|
||||
}
|
||||
}
|
||||
|
||||
fun setOldTransPayDetail(payDetail: PayDetail) {
|
||||
oldTransPayDetail = payDetail
|
||||
}
|
||||
|
||||
/*
|
||||
* Transaction
|
||||
*/
|
||||
|
||||
override fun startOnlineProcess() {
|
||||
|
||||
TransactionsOperation.getInstance()
|
||||
.getStartOperation(
|
||||
tradeData,
|
||||
transType.value
|
||||
)
|
||||
.checkOperation(object : TransactionsOperationListener {
|
||||
|
||||
override fun onSuccess(tradeData: TradeData) {
|
||||
|
||||
val payDetailRes =
|
||||
tradeData.payDetail
|
||||
|
||||
if (
|
||||
TextUtils.equals(
|
||||
payDetailRes.tradeAnswerCode,
|
||||
RC_APPROVED_V1
|
||||
) ||
|
||||
TextUtils.equals(
|
||||
payDetailRes.tradeAnswerCode,
|
||||
RC_APPROVED_V2
|
||||
)
|
||||
) {
|
||||
|
||||
payDetailRes.invoiceNo =
|
||||
SystemParamsOperation
|
||||
.getInstance()
|
||||
.incrementInvoiceNum
|
||||
|
||||
when (transType.value) {
|
||||
|
||||
TransactionsType.VOID -> {
|
||||
processVoidDB(payDetailRes)
|
||||
}
|
||||
|
||||
TransactionsType.REFUND -> {
|
||||
processRefundDB(payDetailRes)
|
||||
}
|
||||
|
||||
TransactionsType.PRE_AUTH_VOID -> {
|
||||
processPreVoidDb(payDetailRes)
|
||||
}
|
||||
|
||||
TransactionsType.PRE_AUTH_COMPLETE -> {
|
||||
processPreCompDb(payDetailRes)
|
||||
}
|
||||
|
||||
TransactionsType.PRE_AUTH_COMPLETE_VOID -> {
|
||||
processPreCompVoidDb(payDetailRes)
|
||||
}
|
||||
|
||||
else -> {
|
||||
insertDB(payDetailRes)
|
||||
}
|
||||
}
|
||||
|
||||
_payDetailResult.value =
|
||||
payDetailRes
|
||||
|
||||
_transResultStatus.value =
|
||||
TransResultStatus.SUCCESS
|
||||
|
||||
} else {
|
||||
|
||||
_payDetailResult.value =
|
||||
payDetailRes
|
||||
|
||||
_transResultStatus.value =
|
||||
TransResultStatus.FAIL
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReversal(
|
||||
tradeData: TradeData
|
||||
) {
|
||||
|
||||
_transResultStatus.value =
|
||||
TransResultStatus.REVERSAL_PREPARE
|
||||
|
||||
callReversal(tradeData)
|
||||
}
|
||||
|
||||
override fun onError(message: String) {
|
||||
|
||||
if (message == TRY_SECONDARY) {
|
||||
|
||||
_transResultStatus.value =
|
||||
TransResultStatus.SECONDARY
|
||||
|
||||
startOnlineProcess()
|
||||
|
||||
} else {
|
||||
|
||||
_errorMessage.value = message
|
||||
|
||||
_transResultStatus.value =
|
||||
TransResultStatus.ERROR
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Database
|
||||
*/
|
||||
|
||||
override fun insertDB(payResult: PayDetail) {
|
||||
|
||||
payDetail?.pinCipher = ""
|
||||
|
||||
repository.insertPayDetail(
|
||||
payDetail
|
||||
)
|
||||
}
|
||||
|
||||
override fun processVoidDB(payResult: PayDetail) {
|
||||
|
||||
payDetail?.isCanceled = true
|
||||
|
||||
payDetail?.let {
|
||||
repository.updatePayDetail(it)
|
||||
}
|
||||
|
||||
repository.insertPayDetail(
|
||||
updateCurrentDateAndTime(payResult)
|
||||
)
|
||||
}
|
||||
|
||||
override fun processRefundDB(payResult: PayDetail) {
|
||||
|
||||
oldTransPayDetail?.apply {
|
||||
isReturnGood = true
|
||||
isCanceled = true
|
||||
|
||||
repository.updatePayDetail(this)
|
||||
}
|
||||
|
||||
repository.insertPayDetail(
|
||||
updateCurrentDateAndTime(payResult)
|
||||
)
|
||||
}
|
||||
|
||||
override fun processPreVoidDb(payResult: PayDetail) {}
|
||||
override fun processPreCompDb(payResult: PayDetail) {}
|
||||
override fun processPreCompVoidDb(payResult: PayDetail) {}
|
||||
|
||||
/*
|
||||
* Reversal
|
||||
*/
|
||||
|
||||
private fun callReversal(tradeData: TradeData) {
|
||||
|
||||
payDetail = tradeData.payDetail
|
||||
|
||||
ReversalAction.getInstance()
|
||||
.setData(tradeData)
|
||||
.enqueue()
|
||||
.startReversal(object : ReversalListener {
|
||||
|
||||
override fun onSuccessReversal() {
|
||||
|
||||
_transResultStatus.value =
|
||||
TransResultStatus.REVERSAL_SUCCESS
|
||||
|
||||
payDetail?.let {
|
||||
repository.insertPayDetail(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNetworkFail(msg: String) {
|
||||
|
||||
SystemParamsOperation
|
||||
.getInstance()
|
||||
.setSecondHostEnable(true)
|
||||
|
||||
if (
|
||||
SystemParamsOperation
|
||||
.getInstance()
|
||||
.isSecondHostEnabled
|
||||
) {
|
||||
|
||||
if (!isSecondCall) {
|
||||
|
||||
_transResultStatus.value =
|
||||
TransResultStatus.REVERSAL_SECONDARY
|
||||
|
||||
ISOSocket.getInstance()
|
||||
.switchIp()
|
||||
|
||||
isSecondCall = true
|
||||
|
||||
callReversal(tradeData)
|
||||
|
||||
} else {
|
||||
|
||||
_transResultStatus.value =
|
||||
TransResultStatus.REVERSAL_FAIL
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
_transResultStatus.value =
|
||||
TransResultStatus.REVERSAL_FAIL
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailReversal(msg: String) {
|
||||
|
||||
_transResultStatus.value =
|
||||
TransResultStatus.REVERSAL_FAIL
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Utils
|
||||
*/
|
||||
|
||||
private fun updateCurrentDateAndTime(
|
||||
payDetail: PayDetail
|
||||
): PayDetail {
|
||||
|
||||
payDetail.tradeDate =
|
||||
SystemDateTime.getMMDD()
|
||||
|
||||
payDetail.tradeTime =
|
||||
SystemDateTime.getHHmmss()
|
||||
|
||||
return payDetail
|
||||
}
|
||||
|
||||
override fun resetTransactionStatus() {
|
||||
_transResultStatus.value = null
|
||||
}
|
||||
|
||||
override fun getTransStatus() = TODO()
|
||||
}
|
||||
@ -98,13 +98,16 @@ public class BaseApplication extends Application {
|
||||
mPinPadOptV2 = sunmiPayKernel.mPinPadOptV2;
|
||||
mReadCardOptV2 = sunmiPayKernel.mReadCardOptV2;
|
||||
mSecurityOptV2 = sunmiPayKernel.mSecurityOptV2;
|
||||
//init
|
||||
|
||||
initTerminal();
|
||||
|
||||
PayLibsUtils.getInstance().initLib(mSecurityOptV2,mEMVOptV2,securityOpt,mReadCardOptV2);
|
||||
SunmiSDK.getInstance().initSDK(mReadCardOptV2,basicOptV2);
|
||||
|
||||
try {
|
||||
initTerminal();
|
||||
} catch (Exception terminalInitException) {
|
||||
terminalInitException.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<color name="colorTextTitle">#222222</color>
|
||||
<color name="colorTextContent">#666666</color>
|
||||
<color name="colorTextHelp">#999999</color>
|
||||
<color name="colorLineColor"># </color>
|
||||
<color name="colorLineColor">#DDDDDD</color>
|
||||
<color name="yellow">#FEE135</color>
|
||||
<color name="red">#D0312D</color>
|
||||
<color name="FD5A52">#FD5A52</color>
|
||||
|
||||
@ -4,6 +4,7 @@ plugins {
|
||||
alias(libs.plugins.android.library) apply false
|
||||
alias(libs.plugins.kotlin.android) apply false
|
||||
alias(libs.plugins.kotlin.compose) apply false
|
||||
alias(libs.plugins.hilt.android) apply false
|
||||
alias(libs.plugins.kotlin.kapt) apply false
|
||||
id("com.google.dagger.hilt.android") version "2.59.2" apply false
|
||||
id("com.google.devtools.ksp") version "2.3.4" apply false
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
[versions]
|
||||
agp = "9.2.0"
|
||||
coreKtx = "1.18.0"
|
||||
hiltAndroidCompiler = "2.59.2"
|
||||
junit = "4.13.2"
|
||||
junitVersion = "1.3.0"
|
||||
espressoCore = "3.7.0"
|
||||
@ -11,10 +12,15 @@ composeBom = "2026.02.01"
|
||||
navigationCompose = "2.9.8"
|
||||
hilt = "2.57.1"
|
||||
foundation = "1.11.1"
|
||||
runtime = "1.11.1"
|
||||
rxandroid = "3.0.2"
|
||||
rxjava = "3.1.12"
|
||||
hiltNavigationCompose = "1.2.0"
|
||||
|
||||
[libraries]
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" }
|
||||
hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hiltAndroidCompiler" }
|
||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||
@ -31,11 +37,14 @@ androidx-compose-material3 = { group = "androidx.compose.material3", name = "mat
|
||||
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
|
||||
hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
|
||||
androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation", version.ref = "foundation" }
|
||||
androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime", version.ref = "runtime" }
|
||||
rxandroid = { module = "io.reactivex.rxjava3:rxandroid", version.ref = "rxandroid" }
|
||||
rxjava = { module = "io.reactivex.rxjava3:rxjava", version.ref = "rxjava" }
|
||||
androidx-hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hiltNavigationCompose" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
android-library = { id = "com.android.library", version.ref = "agp" }
|
||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||
hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
|
||||
kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" }
|
||||
|
||||
@ -0,0 +1 @@
|
||||
o/mpulib-1.2-runtime
|
||||
Binary file not shown.
@ -0,0 +1 @@
|
||||
o/PayLib-release-1.4.64-runtime
|
||||
Binary file not shown.
@ -0,0 +1 @@
|
||||
o/PayLib-release-1.4.64-runtime
|
||||
Binary file not shown.
@ -0,0 +1 @@
|
||||
o/sunmiui-1.1.27-runtime
|
||||
Binary file not shown.
@ -0,0 +1 @@
|
||||
o/sunmiui-1.1.27-runtime
|
||||
Binary file not shown.
@ -2,6 +2,7 @@ package com.kizzy.xpay.util
|
||||
|
||||
import java.security.MessageDigest
|
||||
import java.util.Locale
|
||||
import java.util.Locale.getDefault
|
||||
|
||||
object Sign {
|
||||
|
||||
@ -13,7 +14,7 @@ object Sign {
|
||||
val sorted = filtered.toSortedMap()
|
||||
val stringA = sorted.entries.joinToString("&") {"${it.key}=${it.value}"}
|
||||
val stringToSign = "$stringA&key=$appKey"
|
||||
val hash = stringToSign.hashedWithSha256().toUpperCase()
|
||||
val hash = stringToSign.hashedWithSha256().uppercase(getDefault())
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user