diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..7061a0d
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 64e8382..594a34b 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -21,6 +21,7 @@ android {
buildTypes {
debug {
+ buildConfigField ("String", "ACTIVATION_CODE", "\"436596309\"")
buildConfigField ("String", "APPLICATION_TOKEN", "\"mk_MbQ92RRHEOcGFRIf9/R1A\"")
}
release {
diff --git a/app/src/main/java/com/example/mypos/MainActivity.kt b/app/src/main/java/com/example/mypos/MainActivity.kt
index 9b5e255..e018939 100644
--- a/app/src/main/java/com/example/mypos/MainActivity.kt
+++ b/app/src/main/java/com/example/mypos/MainActivity.kt
@@ -1,25 +1,35 @@
package com.example.mypos
+import android.content.Context
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.viewmodel.viewModelFactory
+import com.example.mypos.models.PaymentViewModel
+import com.example.mypos.screen.PaymentScreen
+import com.example.mypos.services.AditumSdkService
+import com.example.mypos.services.PaymentApplication
import com.example.mypos.ui.theme.POSTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- enableEdgeToEdge()
+ val context = this
+ var paymentApplication = application as PaymentApplication
+ var aditumSdkService = AditumSdkService(paymentApplication)
+ var paymentViewModel = ViewModelProvider(
+ this,
+ PaymentViewModel.provideFactory(paymentApplication, context, aditumSdkService)
+ )[PaymentViewModel::class.java]
setContent {
POSTheme {
-
+ PaymentScreen(paymentViewModel, aditumSdkService)
}
}
}
diff --git a/app/src/main/java/com/example/mypos/data/PaymentRegister.kt b/app/src/main/java/com/example/mypos/data/PaymentRegister.kt
new file mode 100644
index 0000000..c3b13c6
--- /dev/null
+++ b/app/src/main/java/com/example/mypos/data/PaymentRegister.kt
@@ -0,0 +1,12 @@
+package com.example.mypos.data
+
+import br.com.aditum.data.v2.enums.AbecsCommands
+import br.com.aditum.data.v2.enums.TransactionStatus
+
+interface PaymentRegister {
+ fun notification(
+ message: String?,
+ transactionStatus: TransactionStatus?,
+ command: AbecsCommands?
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mypos/models/PaymentViewModel.kt b/app/src/main/java/com/example/mypos/models/PaymentViewModel.kt
index 61a27e8..f50980a 100644
--- a/app/src/main/java/com/example/mypos/models/PaymentViewModel.kt
+++ b/app/src/main/java/com/example/mypos/models/PaymentViewModel.kt
@@ -2,7 +2,12 @@ package com.example.mypos.models
import android.content.Context
import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
+import br.com.aditum.data.v2.enums.AbecsCommands
+import br.com.aditum.data.v2.enums.TransactionStatus
+import com.example.mypos.data.PaymentRegister
+import com.example.mypos.services.AditumSdkService
import com.example.mypos.services.PaymentApplication
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -11,9 +16,10 @@ import kotlinx.coroutines.launch
class PaymentViewModel(
private val application: PaymentApplication,
- private val context: Context
+ private val context: Context,
+ private val aditumSdkService: AditumSdkService
) : ViewModel() {
- private val paymentApplication = application as PaymentApplication
+ private val paymentApplication = application
private val _isServiceConnected = MutableStateFlow(false)
val isServiceConnected: StateFlow = _isServiceConnected.asStateFlow()
@@ -22,10 +28,37 @@ class PaymentViewModel(
paymentApplication.isServiceConnectedFlow.collect { isConnected ->
_isServiceConnected.value = isConnected
}
+ aditumSdkService.register(
+ listener = object : PaymentRegister {
+ override fun notification(
+ message: String?,
+ transactionStatus: TransactionStatus?,
+ command: AbecsCommands?
+ ) {
+ TODO("Not yet implemented")
+ }
+ }
+ )
}
}
fun startService() {
paymentApplication.startAditumSdkService()
}
+
+ companion object {
+ fun provideFactory(
+ paymentApplication: PaymentApplication,
+ context: Context,
+ aditumSdkService: AditumSdkService
+ ): ViewModelProvider.Factory = object : ViewModelProvider.Factory {
+ @Suppress("UNCHECKED_CAST")
+ override fun create(modelClass: Class): T {
+ if (modelClass.isAssignableFrom(PaymentViewModel::class.java)) {
+ return PaymentViewModel(paymentApplication, context, aditumSdkService) as T
+ }
+ throw IllegalArgumentException("Unknown ViewModel class")
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mypos/screen/PaymentScreen.kt b/app/src/main/java/com/example/mypos/screen/PaymentScreen.kt
new file mode 100644
index 0000000..721af53
--- /dev/null
+++ b/app/src/main/java/com/example/mypos/screen/PaymentScreen.kt
@@ -0,0 +1,186 @@
+package com.example.mypos.screen
+
+import androidx.compose.foundation.text.KeyboardOptions
+import android.widget.Toast
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.*
+import androidx.compose.runtime.*
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.unit.dp
+import br.com.aditum.data.v2.enums.PaymentType
+import com.example.mypos.BuildConfig
+import com.example.mypos.models.PaymentViewModel
+import com.example.mypos.services.AditumSdkService
+import com.example.mypos.services.PaymentApplication
+import kotlinx.coroutines.flow.collectLatest
+
+@Composable
+fun PaymentScreen(viewModel: PaymentViewModel, aditumSdkService: AditumSdkService) {
+ val context = LocalContext.current
+ var amount by remember { mutableStateOf("") }
+ var paymentType by remember { mutableStateOf(PaymentType.Credit) }
+ var isServiceConnected by remember { mutableStateOf(false) }
+ var message by remember { mutableStateOf("") }
+ var pinLength by remember { mutableStateOf(0) }
+ var isInitializing by remember { mutableStateOf(false) }
+ var isPaying by remember { mutableStateOf(false) }
+
+
+ LaunchedEffect(Unit) {
+ viewModel.isServiceConnected.collectLatest { connected ->
+ isServiceConnected = connected
+ }
+ }
+
+
+ LaunchedEffect(Unit) {
+ aditumSdkService.messageFlow.collectLatest { msg ->
+ message = msg
+ }
+ }
+
+
+ LaunchedEffect(Unit) {
+ aditumSdkService.pinLengthFlow.collectLatest { length ->
+ pinLength = length
+ }
+ }
+
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(16.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.spacedBy(16.dp)
+ ) {
+ Text(
+ text = "Pagamento",
+ style = MaterialTheme.typography.headlineMedium
+ )
+
+
+ Text(
+ text = if (isServiceConnected) "Serviço Conectado" else "Serviço Desconectado",
+ color = if (isServiceConnected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.error
+ )
+
+
+ Button(
+ onClick = {
+ if (!isServiceConnected) {
+ viewModel.startService()
+ Toast.makeText(context, "Tentando conectar ao serviço...", Toast.LENGTH_SHORT).show()
+ return@Button
+ }
+ if (!isInitializing) {
+ isInitializing = true
+ aditumSdkService.initAditumSdk(
+ applicationName = "MyPOS",
+ applicationVersion = "1.0.0",
+ activationCode = BuildConfig.ACTIVATION_CODE,
+ resolve = { success ->
+ isInitializing = false
+ Toast.makeText(
+ context,
+ if (success) "SDK inicializado com sucesso!" else "Falha na inicialização.",
+ Toast.LENGTH_LONG
+ ).show()
+ },
+ reject = { errorCode, errorMessage ->
+ isInitializing = false
+ Toast.makeText(context, "Erro: $errorMessage", Toast.LENGTH_LONG).show()
+ }
+ )
+ }
+ },
+ enabled = !isInitializing,
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ Text(if (isInitializing) "Inicializando..." else "Inicializar SDK")
+ }
+
+
+ OutlinedTextField(
+ value = amount,
+ onValueChange = { amount = it.filter { char -> char.isDigit() || char == '.' } },
+ label = { Text("Valor (R$)") },
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal),
+ modifier = Modifier.fillMaxWidth()
+ )
+
+
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceEvenly
+ ) {
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ RadioButton(
+ selected = paymentType == PaymentType.Credit,
+ onClick = { paymentType = PaymentType.Credit }
+ )
+ Text("Crédito")
+ }
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ RadioButton(
+ selected = paymentType == PaymentType.Debit,
+ onClick = { paymentType = PaymentType.Debit }
+ )
+ Text("Débito")
+ }
+ }
+
+
+ Button(
+ onClick = {
+ val amountValue = amount.toDoubleOrNull()?.times(100)?.toLong()
+ if (amountValue == null || amountValue <= 0) {
+ Toast.makeText(context, "Insira um valor válido", Toast.LENGTH_SHORT).show()
+ return@Button
+ }
+ if (!isServiceConnected) {
+ Toast.makeText(context, "Serviço não conectado", Toast.LENGTH_SHORT).show()
+ return@Button
+ }
+ if (!isPaying) {
+ isPaying = true
+ aditumSdkService.pay(
+ amount = amountValue,
+ paymentType = paymentType,
+ allowContactless = true,
+ resolve = { response ->
+ isPaying = false
+ Toast.makeText(context, "Pagamento realizado com sucesso!", Toast.LENGTH_LONG).show()
+ },
+ reject = { errorCode, errorMessage ->
+ isPaying = false
+ Toast.makeText(context, "Erro no pagamento: $errorMessage", Toast.LENGTH_LONG).show()
+ }
+ )
+ }
+ },
+ enabled = !isPaying,
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ Text(if (isPaying) "Processando Pagamento..." else "Realizar Pagamento")
+ }
+
+
+ if (message.isNotEmpty()) {
+ Text(
+ text = "Mensagem do PIN pad: $message",
+ style = MaterialTheme.typography.bodyMedium
+ )
+ }
+
+
+ if (pinLength > 0) {
+ Text(
+ text = "Comprimento do PIN: $pinLength",
+ style = MaterialTheme.typography.bodyMedium
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mypos/services/AditumSdkService.kt b/app/src/main/java/com/example/mypos/services/AditumSdkService.kt
index c859e90..821aa21 100644
--- a/app/src/main/java/com/example/mypos/services/AditumSdkService.kt
+++ b/app/src/main/java/com/example/mypos/services/AditumSdkService.kt
@@ -28,6 +28,7 @@ import br.com.aditum.data.v2.model.transactions.ConfirmTransactionCallback
import br.com.aditum.data.v2.model.transactions.PendingTransactionsCallback
import com.example.mypos.BuildConfig
import com.example.mypos.data.AditumError
+import com.example.mypos.data.PaymentRegister
import com.google.gson.Gson
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -52,7 +53,7 @@ class AditumSdkService(private val paymentApplication: PaymentApplication) {
private val _pinLengthFlow = MutableStateFlow(0)
val pinLengthFlow: StateFlow = _pinLengthFlow.asStateFlow()
- fun register() {
+ fun register(listener: PaymentRegister) {
coroutineScope.launch {
val callback = object : IPaymentCallback.Stub() {
override fun notification(
@@ -60,9 +61,15 @@ class AditumSdkService(private val paymentApplication: PaymentApplication) {
transactionStatus: TransactionStatus?,
command: AbecsCommands?
) {
+ Log.d(TAG, "\nnotification - ${ message ?: "" }")
if (message != null) {
_messageFlow.value = message.replace("\\s+".toRegex(), " ").trim()
}
+ listener.notification(
+ message?.replace("\\s+".toRegex(), " ")?.trim(),
+ transactionStatus,
+ command
+ )
}
override fun pinNotification(message: String?, length: Int) {
@@ -88,9 +95,7 @@ class AditumSdkService(private val paymentApplication: PaymentApplication) {
}
}
- paymentApplication.communicationService?.registerPaymentCallback(callback) ?: run {
-
- }
+ paymentApplication.communicationService?.registerPaymentCallback(callback)
}
}
@@ -117,6 +122,7 @@ class AditumSdkService(private val paymentApplication: PaymentApplication) {
this.activationCode = if (BuildConfig.DEBUG) BuildConfig.ACTIVATION_CODE else activationCode
this.applicationName = applicationName
this.applicationVersion = applicationVersion
+ this.useOnlySdk = true
this.applicationToken = BuildConfig.APPLICATION_TOKEN
}
@@ -161,7 +167,7 @@ class AditumSdkService(private val paymentApplication: PaymentApplication) {
fun pay(
amount: Long,
- installments: Int = 0,
+ installments: Int? = null,
paymentType: PaymentType,
allowContactless: Boolean = true,
amountSeasoning: ((Long) -> Long)? = null,
@@ -188,8 +194,13 @@ class AditumSdkService(private val paymentApplication: PaymentApplication) {
this.amount = amount
this.allowContactless = allowContactless
manualEntry = false
- installmentType = if (paymentType == PaymentType.Debit) InstallmentType.None else InstallmentType.Merchant
- installmentNumber = installments
+ installmentType = if (paymentType == PaymentType.Debit) InstallmentType.Undefined else InstallmentType.Merchant
+ this.installmentNumber = when {
+ installments == null -> if (paymentType == PaymentType.Credit) 1 else 0
+ installments > 1 -> installments
+ paymentType == PaymentType.Debit -> 0
+ else -> 1
+ }
}
val callback = object : PaymentResponseCallback.Stub() {