summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
authorsaber safavi <saber.safavi@codic.se>2023-10-03 12:54:46 +0200
committerJonatan Rhodin <jonatan.rhodin@mullvad.net>2023-10-11 10:37:47 +0200
commit03cb890fec0b6d17e05529de832ce075431c2f9f (patch)
tree9356a71b39b0438bbcb7e507f9d2bb31d3493551 /android
parent7b117b624f25299b02762bb962ce6e0304f7c095 (diff)
downloadmullvadvpn-03cb890fec0b6d17e05529de832ce075431c2f9f.tar.xz
mullvadvpn-03cb890fec0b6d17e05529de832ce075431c2f9f.zip
Add MVVM parts
Diffstat (limited to 'android')
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VoucherDialogUiState.kt21
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt8
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModel.kt92
3 files changed, 118 insertions, 3 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VoucherDialogUiState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VoucherDialogUiState.kt
new file mode 100644
index 0000000000..e719bda529
--- /dev/null
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VoucherDialogUiState.kt
@@ -0,0 +1,21 @@
+package net.mullvad.mullvadvpn.compose.state
+
+data class VoucherDialogUiState(
+ val voucherInput: String = "",
+ val voucherViewModelState: VoucherDialogState = VoucherDialogState.Default
+) {
+ companion object {
+ val INITIAL = VoucherDialogUiState()
+ }
+}
+
+sealed interface VoucherDialogState {
+
+ data object Default : VoucherDialogState
+
+ data object Verifying : VoucherDialogState
+
+ data class Success(val addedTime: Long) : VoucherDialogState
+
+ data class Error(val errorMessage: String) : VoucherDialogState
+}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt
index 18e98964e8..63fcf17ad2 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt
@@ -32,6 +32,7 @@ import net.mullvad.mullvadvpn.viewmodel.SelectLocationViewModel
import net.mullvad.mullvadvpn.viewmodel.SettingsViewModel
import net.mullvad.mullvadvpn.viewmodel.SplitTunnelingViewModel
import net.mullvad.mullvadvpn.viewmodel.ViewLogsViewModel
+import net.mullvad.mullvadvpn.viewmodel.VoucherDialogViewModel
import net.mullvad.mullvadvpn.viewmodel.VpnSettingsViewModel
import net.mullvad.mullvadvpn.viewmodel.WelcomeViewModel
import org.apache.commons.validator.routines.InetAddressValidator
@@ -86,14 +87,15 @@ val uiModule = module {
viewModel { DeviceListViewModel(get(), get()) }
viewModel { DeviceRevokedViewModel(get(), get()) }
viewModel { LoginViewModel(get(), get()) }
+ viewModel { OutOfTimeViewModel(get(), get()) }
viewModel { PrivacyDisclaimerViewModel(get()) }
+ viewModel { ReportProblemViewModel(get()) }
viewModel { SelectLocationViewModel(get()) }
viewModel { SettingsViewModel(get(), get()) }
+ viewModel { ViewLogsViewModel(get()) }
+ viewModel { VoucherDialogViewModel(get(), get()) }
viewModel { VpnSettingsViewModel(get(), get(), get(), get()) }
viewModel { WelcomeViewModel(get(), get(), get()) }
- viewModel { ReportProblemViewModel(get()) }
- viewModel { ViewLogsViewModel(get()) }
- viewModel { OutOfTimeViewModel(get(), get()) }
}
const val SELF_PACKAGE_NAME = "SELF_PACKAGE_NAME"
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModel.kt
new file mode 100644
index 0000000000..07c56ff954
--- /dev/null
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModel.kt
@@ -0,0 +1,92 @@
+package net.mullvad.mullvadvpn.viewmodel
+
+import android.content.res.Resources
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import net.mullvad.mullvadvpn.R
+import net.mullvad.mullvadvpn.compose.state.LoginUiState
+import net.mullvad.mullvadvpn.compose.state.VoucherDialogState
+import net.mullvad.mullvadvpn.compose.state.VoucherDialogUiState
+import net.mullvad.mullvadvpn.model.VoucherSubmissionError
+import net.mullvad.mullvadvpn.model.VoucherSubmissionResult
+import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionContainer
+import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager
+import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionState
+import net.mullvad.mullvadvpn.ui.serviceconnection.VoucherRedeemer
+
+class VoucherDialogViewModel(
+ serviceConnectionManager: ServiceConnectionManager,
+ private val resources: Resources
+) : ViewModel() {
+
+ private val vmState = MutableStateFlow<VoucherDialogState>(VoucherDialogState.Default)
+ private val voucherInput = MutableStateFlow(LoginUiState.INITIAL.accountNumberInput)
+
+ private lateinit var voucherRedeemer: VoucherRedeemer
+ private val _shared: SharedFlow<ServiceConnectionContainer> =
+ serviceConnectionManager.connectionState
+ .flatMapLatest { state ->
+ if (state is ServiceConnectionState.ConnectedReady) {
+ flowOf(state.container)
+ } else {
+ emptyFlow()
+ }
+ }
+ .shareIn(viewModelScope, SharingStarted.WhileSubscribed())
+
+ var uiState =
+ _shared
+ .flatMapLatest { serviceConnection ->
+ voucherRedeemer = serviceConnection.voucherRedeemer
+ combine(vmState, voucherInput) { state, input ->
+ VoucherDialogUiState(voucherInput = input, voucherViewModelState = state)
+ }
+ }
+ .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), VoucherDialogUiState.INITIAL)
+
+ fun onRedeem(voucherCode: String) {
+ vmState.update { VoucherDialogState.Verifying }
+ viewModelScope.launch {
+ when (val result = voucherRedeemer.submit(voucherCode)) {
+ is VoucherSubmissionResult.Ok -> handleAddedTime(result.submission.timeAdded)
+ is VoucherSubmissionResult.Error -> setError(result.error)
+ else -> {
+ vmState.update { VoucherDialogState.Default }
+ }
+ }
+ }
+ }
+
+ fun onVoucherInputChange(voucherString: String) {
+ voucherInput.value = voucherString
+ }
+
+ private fun handleAddedTime(timeAdded: Long) {
+ viewModelScope.launch { vmState.update { VoucherDialogState.Success(timeAdded) } }
+ }
+
+ private fun setError(error: VoucherSubmissionError) {
+ viewModelScope.launch {
+ val message =
+ resources.getString(
+ when (error) {
+ VoucherSubmissionError.InvalidVoucher -> R.string.invalid_voucher
+ VoucherSubmissionError.VoucherAlreadyUsed -> R.string.voucher_already_used
+ else -> R.string.error_occurred
+ }
+ )
+ vmState.update { VoucherDialogState.Error(message) }
+ }
+ }
+}