blob: 8cfc7f9a46a428d8fa390644d6de0907e2473343 (
plain)
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
|
package ch.bfh.habej2.wallee_c2ec.withdrawal
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import ch.bfh.habej2.wallee_c2ec.client.taler.BankIntegrationClient
import ch.bfh.habej2.wallee_c2ec.client.taler.config.TalerBankIntegrationConfig
import ch.bfh.habej2.wallee_c2ec.client.taler.model.PaymentNotification
import ch.bfh.habej2.wallee_c2ec.client.taler.encoding.Base32Encode
import com.wallee.android.till.sdk.data.TransactionCompletionResponse
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import java.io.Closeable
import java.math.BigDecimal
import java.security.SecureRandom
import java.util.Optional
data class Amount(
val value: Int,
val frac: Int
) {
fun toBigDecimal(): BigDecimal = BigDecimal("$value.$frac")
}
@Stable
interface WithdrawalOperationState{
val exchangeBankIntegrationApiUrl: String
val encodedWopid: String
val amount: Amount
val currency: String
val payed: Boolean
val transaction: TransactionCompletionResponse?
}
private class MutableWithdrawalOperationState: WithdrawalOperationState {
override var exchangeBankIntegrationApiUrl: String by mutableStateOf("")
override var encodedWopid: String by mutableStateOf("")
override var amount: Amount by mutableStateOf(Amount(0,0))
override var currency: String by mutableStateOf("")
override var payed: Boolean by mutableStateOf(false)
override var transaction: TransactionCompletionResponse? by mutableStateOf(null)
}
class WithdrawalViewModel(
vararg closeables: Closeable
) : ViewModel(*closeables) {
private var bankIntegrationClient: BankIntegrationClient? = null
private val _uiState = MutableStateFlow(MutableWithdrawalOperationState())
val uiState: StateFlow<WithdrawalOperationState> = _uiState
init {
initializeWopid()
}
fun exchangeUpdated(cfg: TalerBankIntegrationConfig) {
bankIntegrationClient = BankIntegrationClient(cfg)
_uiState.value = MutableWithdrawalOperationState() // reset withdrawal operation
initializeWopid() // initialize new withdrawal operation identifier
}
fun initializeWopid() {
_uiState.value.encodedWopid = Base32Encode(wopid())
}
fun updateAmount(amount: String) {
_uiState.value.amount = parseAmount(amount).orElse(null)
}
fun updateCurrency(currency: String) {
_uiState.value.currency = currency
}
fun updateWalleeTransaction(completion: TransactionCompletionResponse) {
_uiState.value.transaction = completion
}
fun startAuthorizationWhenReadyOrAbort(
onSuccess: () -> Unit,
onFailure: () -> Unit
) {
return
viewModelScope.launch {
onSuccess() // TODO
// val result = bankIntegrationClient!!.retrieveWithdrawalStatus(uiState.value.encodedWopid, 30000)
// if (result.isPresent) {
// onSuccess()
// } else {
// withdrawalOperationFailed()
// onFailure()
// }
}
}
fun withdrawalOperationFailed() {
viewModelScope.launch {
bankIntegrationClient!!.abortWithdrawal(uiState.value.encodedWopid)
}
}
fun confirmPayment() {
viewModelScope.launch{
bankIntegrationClient!!.sendPaymentNotification(PaymentNotification())
}
}
private fun wopid(): ByteArray {
val wopid = ByteArray(32)
val rand = SecureRandom()
rand.nextBytes(wopid) // will seed automatically
return wopid
}
/**
* Format expected X[.X], X an integer
*/
private fun parseAmount(inp: String): Optional<Amount> {
val points = inp.count { it == '.' }
if (points > 1) {
return Optional.empty()
}
if (points == 1) {
val valueStr = inp.split(".")[0]
val fracStr = inp.split(".")[1]
return try {
val value = valueStr.toInt()
val frac = fracStr.toInt()
Optional.of(Amount(value, frac))
} catch (ex: NumberFormatException) {
Optional.empty()
}
}
return try {
val value = inp.toInt()
Optional.of(Amount(value, 0))
} catch (ex: NumberFormatException) {
Optional.empty()
}
}
}
|