summaryrefslogtreecommitdiff
path: root/wallee-c2ec/app/src/main/java/ch/bfh/habej2/wallee_c2ec/withdrawal/WithdrawalViewModel.kt
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()
        }
    }
}