diff options
| author | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2025-09-30 14:36:54 +0200 |
|---|---|---|
| committer | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2025-09-30 14:55:13 +0200 |
| commit | 175d837d129ddf3c62b59f2ce6d66439f573c69a (patch) | |
| tree | eb242949de8741b5884c44a57532def613955f01 /android | |
| parent | 2c3f0c3c91b4e750c557f7e89015dd493a7cd4bf (diff) | |
| download | mullvadvpn-175d837d129ddf3c62b59f2ce6d66439f573c69a.tar.xz mullvadvpn-175d837d129ddf3c62b59f2ce6d66439f573c69a.zip | |
Align state in behavior for all view models
Diffstat (limited to 'android')
40 files changed, 203 insertions, 40 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/ViewModelConstant.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/ViewModelConstant.kt new file mode 100644 index 0000000000..3d95be115f --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/ViewModelConstant.kt @@ -0,0 +1,5 @@ +package net.mullvad.mullvadvpn.constant + +import kotlin.time.Duration.Companion.seconds + +val VIEW_MODEL_STOP_TIMEOUT = 5.seconds diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModel.kt index ba7e843c6d..2db89a9ef9 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModel.kt @@ -8,6 +8,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filterIsInstance @@ -16,6 +17,7 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.AccountData import net.mullvad.mullvadvpn.lib.model.AccountNumber import net.mullvad.mullvadvpn.lib.model.DeviceState @@ -55,7 +57,11 @@ class AccountViewModel( .toLc<Unit, AccountUiState>() } .onStart { viewModelScope.launch { updateAccountExpiry() } } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), Lc.Loading(Unit)) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + Lc.Loading(Unit), + ) init { verifyPurchases() diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AddTimeViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AddTimeViewModel.kt index e96162c858..19637aeabe 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AddTimeViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AddTimeViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.viewModelScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull @@ -14,6 +15,7 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.AddTimeUiState import net.mullvad.mullvadvpn.compose.state.PurchaseState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.WebsiteAuthToken import net.mullvad.mullvadvpn.lib.payment.model.ProductId import net.mullvad.mullvadvpn.lib.payment.model.PurchaseResult @@ -51,7 +53,7 @@ class AddTimeViewModel( } .stateIn( scope = viewModelScope, - started = SharingStarted.WhileSubscribed(), + started = SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), initialValue = Lc.Loading(Unit), ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ApiAccessListViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ApiAccessListViewModel.kt index 86d6069c16..68777ab9a4 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ApiAccessListViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ApiAccessListViewModel.kt @@ -3,9 +3,11 @@ package net.mullvad.mullvadvpn.viewmodel import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import net.mullvad.mullvadvpn.compose.state.ApiAccessListUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.repository.ApiAccessRepository class ApiAccessListViewModel(apiAccessRepository: ApiAccessRepository) : ViewModel() { @@ -19,5 +21,9 @@ class ApiAccessListViewModel(apiAccessRepository: ApiAccessRepository) : ViewMod apiAccessMethodSettings = apiAccessMethods ?: emptyList(), ) } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), ApiAccessListUiState()) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + ApiAccessListUiState(), + ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ApiAccessMethodDetailsViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ApiAccessMethodDetailsViewModel.kt index 1e617817af..08a1ba4b61 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ApiAccessMethodDetailsViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ApiAccessMethodDetailsViewModel.kt @@ -11,12 +11,14 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.ApiAccessMethodDetailsUiState import net.mullvad.mullvadvpn.constant.MINIMUM_LOADING_TIME_MILLIS +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodId import net.mullvad.mullvadvpn.lib.model.TestApiAccessMethodError import net.mullvad.mullvadvpn.repository.ApiAccessRepository @@ -54,7 +56,7 @@ class ApiAccessMethodDetailsViewModel( } .stateIn( viewModelScope, - SharingStarted.WhileSubscribed(), + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), ApiAccessMethodDetailsUiState.Loading(apiAccessMethodId = apiAccessMethodId), ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AppInfoViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AppInfoViewModel.kt index db5f499479..d7783502eb 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AppInfoViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AppInfoViewModel.kt @@ -8,11 +8,13 @@ import androidx.lifecycle.viewModelScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.R +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.VersionInfo import net.mullvad.mullvadvpn.ui.serviceconnection.AppVersionInfoRepository import net.mullvad.mullvadvpn.util.Lc @@ -31,7 +33,11 @@ class AppInfoViewModel( val uiState: StateFlow<Lc<Unit, AppInfoUiState>> = appVersionInfoRepository.versionInfo .map { versionInfo -> Lc.Content(AppInfoUiState(versionInfo, isPlayBuild)) } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Lc.Loading(Unit)) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + Lc.Loading(Unit), + ) fun openAppListing() = viewModelScope.launch { diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt index 4ed52d4c63..4b26fde420 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.map @@ -19,6 +20,7 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.state.ConnectUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.common.util.daysFromNow import net.mullvad.mullvadvpn.lib.model.ActionAfterDisconnect import net.mullvad.mullvadvpn.lib.model.ConnectError @@ -116,7 +118,11 @@ class ConnectViewModel( accountRepository.refreshAccountData(ignoreTimeout = false) } } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_0000), ConnectUiState.INITIAL) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + ConnectUiState.INITIAL, + ) init { viewModelScope.launch { diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/CreateCustomListDialogViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/CreateCustomListDialogViewModel.kt index 8cb8cfb012..1a127a5929 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/CreateCustomListDialogViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/CreateCustomListDialogViewModel.kt @@ -8,6 +8,7 @@ import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn @@ -15,6 +16,7 @@ import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.communication.CustomListAction import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData import net.mullvad.mullvadvpn.compose.state.CreateCustomListUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.CustomListId import net.mullvad.mullvadvpn.lib.model.CustomListName import net.mullvad.mullvadvpn.lib.model.GeoLocationId @@ -38,7 +40,11 @@ class CreateCustomListDialogViewModel( val uiState = _error .map { CreateCustomListUiState(it) } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), CreateCustomListUiState()) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + CreateCustomListUiState(), + ) fun createCustomList(name: String) { viewModelScope.launch { diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/CustomListLocationsViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/CustomListLocationsViewModel.kt index 9627dd4c90..26188d625c 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/CustomListLocationsViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/CustomListLocationsViewModel.kt @@ -10,6 +10,7 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.receiveAsFlow @@ -21,6 +22,7 @@ import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData import net.mullvad.mullvadvpn.compose.communication.LocationsChanged import net.mullvad.mullvadvpn.compose.state.CustomListLocationsData import net.mullvad.mullvadvpn.compose.state.CustomListLocationsUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.RelayItem import net.mullvad.mullvadvpn.lib.model.RelayItemId import net.mullvad.mullvadvpn.lib.ui.component.relaylist.CheckableRelayListItem @@ -101,7 +103,7 @@ class CustomListLocationsViewModel( } .stateIn( viewModelScope, - SharingStarted.WhileSubscribed(), + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), CustomListLocationsUiState(newList = navArgs.newList, content = Lce.Loading(Unit)), ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/CustomListsViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/CustomListsViewModel.kt index c30b8ca637..d6a7bdba03 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/CustomListsViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/CustomListsViewModel.kt @@ -3,12 +3,14 @@ package net.mullvad.mullvadvpn.viewmodel import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.communication.CustomListAction import net.mullvad.mullvadvpn.compose.state.CustomListsUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.repository.CustomListsRepository import net.mullvad.mullvadvpn.usecase.customlists.CustomListActionUseCase @@ -23,7 +25,7 @@ class CustomListsViewModel( .map(CustomListsUiState::Content) .stateIn( viewModelScope, - started = SharingStarted.WhileSubscribed(), + started = SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), CustomListsUiState.Loading, ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DaitaViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DaitaViewModel.kt index fdaa9c7eb6..13e05ad091 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DaitaViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DaitaViewModel.kt @@ -5,11 +5,13 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.ramcosta.composedestinations.generated.destinations.DaitaDestination import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.DaitaUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.repository.SettingsRepository import net.mullvad.mullvadvpn.util.Lc import net.mullvad.mullvadvpn.util.isDaitaDirectOnly @@ -36,7 +38,7 @@ class DaitaViewModel( } .stateIn( scope = viewModelScope, - started = SharingStarted.WhileSubscribed(), + started = SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), initialValue = Lc.Loading(navArgs.isModal), ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeleteApiAccessMethodConfirmationViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeleteApiAccessMethodConfirmationViewModel.kt index 6e7d99dc39..96c476db6e 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeleteApiAccessMethodConfirmationViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeleteApiAccessMethodConfirmationViewModel.kt @@ -7,11 +7,13 @@ import com.ramcosta.composedestinations.generated.destinations.DeleteApiAccessMe import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.DeleteApiAccessMethodUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodId import net.mullvad.mullvadvpn.lib.model.RemoveApiAccessMethodError import net.mullvad.mullvadvpn.repository.ApiAccessRepository @@ -34,7 +36,7 @@ class DeleteApiAccessMethodConfirmationViewModel( .map { DeleteApiAccessMethodUiState(it) } .stateIn( viewModelScope, - SharingStarted.WhileSubscribed(), + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), DeleteApiAccessMethodUiState(null), ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeleteCustomListConfirmationViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeleteCustomListConfirmationViewModel.kt index 398325d7ed..89a28a652a 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeleteCustomListConfirmationViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeleteCustomListConfirmationViewModel.kt @@ -7,6 +7,7 @@ import com.ramcosta.composedestinations.generated.destinations.DeleteCustomListD import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn @@ -14,6 +15,7 @@ import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.communication.CustomListAction import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData import net.mullvad.mullvadvpn.compose.state.DeleteCustomListUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.CustomListId import net.mullvad.mullvadvpn.lib.model.CustomListName import net.mullvad.mullvadvpn.usecase.customlists.CustomListActionUseCase @@ -37,7 +39,7 @@ class DeleteCustomListConfirmationViewModel( .map { DeleteCustomListUiState(name, it) } .stateIn( viewModelScope, - SharingStarted.WhileSubscribed(), + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), DeleteCustomListUiState(name, null), ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceListViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceListViewModel.kt index fb94965532..84a2eecef9 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceListViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceListViewModel.kt @@ -10,6 +10,7 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart @@ -19,6 +20,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.DeviceItemUiState import net.mullvad.mullvadvpn.compose.state.DeviceListUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.AccountNumber import net.mullvad.mullvadvpn.lib.model.Device import net.mullvad.mullvadvpn.lib.model.DeviceId @@ -58,7 +60,11 @@ class DeviceListViewModel( } } .onStart { fetchDevices() } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), DeviceListUiState.Loading) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + DeviceListUiState.Loading, + ) fun fetchDevices() = viewModelScope.launch { diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModel.kt index ca503f3ee3..020a384c6c 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModel.kt @@ -7,11 +7,13 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.DeviceRevokedUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.shared.AccountRepository import net.mullvad.mullvadvpn.lib.shared.ConnectionProxy @@ -32,7 +34,7 @@ class DeviceRevokedViewModel( } .stateIn( scope = CoroutineScope(dispatcher), - started = SharingStarted.WhileSubscribed(), + started = SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), initialValue = DeviceRevokedUiState.UNKNOWN, ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DnsDialogViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DnsDialogViewModel.kt index d5d733e8da..d3d16fc89b 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DnsDialogViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DnsDialogViewModel.kt @@ -15,12 +15,14 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.Settings import net.mullvad.mullvadvpn.repository.SettingsRepository import net.mullvad.mullvadvpn.usecase.DeleteCustomDnsUseCase @@ -91,7 +93,7 @@ class DnsDialogViewModel( } .stateIn( viewModelScope, - SharingStarted.Lazily, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), DnsDialogViewState( input = _ipAddressInput.value, validationError = null, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditApiAccessMethodViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditApiAccessMethodViewModel.kt index 48e4ac85ac..197fe80ad3 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditApiAccessMethodViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditApiAccessMethodViewModel.kt @@ -16,6 +16,7 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.receiveAsFlow @@ -26,6 +27,7 @@ import net.mullvad.mullvadvpn.compose.state.ApiAccessMethodTypes import net.mullvad.mullvadvpn.compose.state.EditApiAccessFormData import net.mullvad.mullvadvpn.compose.state.EditApiAccessMethodUiState import net.mullvad.mullvadvpn.constant.MINIMUM_LOADING_TIME_MILLIS +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.ApiAccessMethod import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodId import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodName @@ -66,7 +68,7 @@ class EditApiAccessMethodViewModel( } .stateIn( viewModelScope, - SharingStarted.WhileSubscribed(), + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), EditApiAccessMethodUiState.Loading(editMode = apiAccessMethodId != null), ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListNameDialogViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListNameDialogViewModel.kt index b57d3f3a61..0ef6396114 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListNameDialogViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListNameDialogViewModel.kt @@ -8,6 +8,7 @@ import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn @@ -15,6 +16,7 @@ import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.communication.CustomListAction import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData import net.mullvad.mullvadvpn.compose.state.EditCustomListNameUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.CustomListName import net.mullvad.mullvadvpn.usecase.customlists.CustomListActionUseCase import net.mullvad.mullvadvpn.usecase.customlists.RenameError @@ -37,7 +39,7 @@ class EditCustomListNameDialogViewModel( combine(inputName, _error) { name, error -> EditCustomListNameUiState(name = name, error) } .stateIn( viewModelScope, - SharingStarted.WhileSubscribed(), + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), EditCustomListNameUiState(name = navArgs.initialName.value), ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListViewModel.kt index c736781fcc..3e4d97eb63 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListViewModel.kt @@ -5,9 +5,11 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.ramcosta.composedestinations.generated.destinations.EditCustomListDestination import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import net.mullvad.mullvadvpn.compose.state.EditCustomListUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.CustomListId import net.mullvad.mullvadvpn.repository.CustomListsRepository @@ -33,7 +35,7 @@ class EditCustomListViewModel( } .stateIn( viewModelScope, - SharingStarted.WhileSubscribed(), + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), EditCustomListUiState.Loading, ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/FilterViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/FilterViewModel.kt index 41d98b40fb..dce94490f9 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/FilterViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/FilterViewModel.kt @@ -7,6 +7,7 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.receiveAsFlow @@ -14,6 +15,7 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.RelayFilterUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.Constraint import net.mullvad.mullvadvpn.lib.model.Ownership import net.mullvad.mullvadvpn.lib.model.ProviderId @@ -40,7 +42,11 @@ class FilterViewModel( val uiState: StateFlow<RelayFilterUiState> = combine(providerToOwnershipsUseCase(), selectedOwnership, selectedProviders, ::createState) - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), RelayFilterUiState()) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + RelayFilterUiState(), + ) private fun createState( providerToOwnerships: Map<ProviderId, Set<Ownership>>, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModel.kt index 32004e2852..f1213ea6f6 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModel.kt @@ -11,6 +11,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.mapNotNull @@ -25,6 +26,7 @@ import net.mullvad.mullvadvpn.compose.state.LoginState.Idle import net.mullvad.mullvadvpn.compose.state.LoginState.Loading import net.mullvad.mullvadvpn.compose.state.LoginState.Success import net.mullvad.mullvadvpn.compose.state.LoginUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.common.util.isBeforeNowInstant import net.mullvad.mullvadvpn.lib.model.AccountNumber import net.mullvad.mullvadvpn.lib.model.LoginAccountError @@ -73,7 +75,11 @@ class LoginViewModel( val uiState: StateFlow<LoginUiState> = _uiState .onStart { viewModelScope.launch { accountRepository.fetchAccountHistory() } } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), LoginUiState.INITIAL) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + LoginUiState.INITIAL, + ) fun clearAccountHistory() = viewModelScope.launch { diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ManageDevicesViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ManageDevicesViewModel.kt index b92fd9845b..4e17038fa6 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ManageDevicesViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ManageDevicesViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterIsInstance @@ -13,6 +14,7 @@ import net.mullvad.mullvadvpn.compose.state.DeviceItemUiState import net.mullvad.mullvadvpn.compose.state.DeviceListUiState import net.mullvad.mullvadvpn.compose.state.ManageDevicesItemUiState import net.mullvad.mullvadvpn.compose.state.ManageDevicesUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.Device import net.mullvad.mullvadvpn.lib.model.DeviceId import net.mullvad.mullvadvpn.lib.model.DeviceState @@ -49,7 +51,11 @@ class ManageDevicesViewModel( } } } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Lce.Loading(Unit)) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + Lce.Loading(Unit), + ) fun fetchDevices() = deviceListViewModel.fetchDevices() diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/MtuDialogViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/MtuDialogViewModel.kt index 292ceec717..91e6a25498 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/MtuDialogViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/MtuDialogViewModel.kt @@ -10,10 +10,12 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.Mtu import net.mullvad.mullvadvpn.repository.SettingsRepository @@ -31,7 +33,7 @@ class MtuDialogViewModel( combine(_mtuInput, _isValidMtu, ::createState) .stateIn( viewModelScope, - SharingStarted.WhileSubscribed(), + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), createState(_mtuInput.value, _isValidMtu.value), ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/MultihopViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/MultihopViewModel.kt index 7b5b08a088..187131b848 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/MultihopViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/MultihopViewModel.kt @@ -6,10 +6,12 @@ import androidx.lifecycle.viewModelScope import com.ramcosta.composedestinations.generated.destinations.MultihopDestination import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.repository.WireguardConstraintsRepository import net.mullvad.mullvadvpn.util.Lc @@ -23,7 +25,11 @@ class MultihopViewModel( wireguardConstraintsRepository.wireguardConstraints .filterNotNull() .map { Lc.Content(MultihopUiState(it.isMultihopEnabled, isModal = navArgs.isModal)) } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Lc.Loading(navArgs.isModal)) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + Lc.Loading(navArgs.isModal), + ) fun setMultihop(enable: Boolean) { viewModelScope.launch { wireguardConstraintsRepository.setMultihop(enable) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModel.kt index 1ac414e725..0fecbb65e2 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.delay import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map @@ -13,6 +14,7 @@ import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.OutOfTimeUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.WebsiteAuthToken import net.mullvad.mullvadvpn.lib.shared.AccountRepository import net.mullvad.mullvadvpn.lib.shared.ConnectionProxy @@ -49,7 +51,11 @@ class OutOfTimeViewModel( verificationPending = paymentAvailability.hasPendingPayment(), ) } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), OutOfTimeUiState()) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + OutOfTimeUiState(), + ) init { viewModelScope.launch { diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/PrivacyDisclaimerViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/PrivacyDisclaimerViewModel.kt index 11800791d2..ea23e7e34f 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/PrivacyDisclaimerViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/PrivacyDisclaimerViewModel.kt @@ -5,11 +5,13 @@ import androidx.lifecycle.viewModelScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.repository.UserPreferencesRepository data class PrivacyDisclaimerViewState(val isStartingService: Boolean, val isPlayBuild: Boolean) @@ -31,7 +33,7 @@ class PrivacyDisclaimerViewModel( } .stateIn( viewModelScope, - SharingStarted.WhileSubscribed(), + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), PrivacyDisclaimerViewState(false, isPlayBuild), ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModel.kt index 3b1ce59a70..0f27ea1516 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModel.kt @@ -7,11 +7,13 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.constant.MINIMUM_LOADING_TIME_MILLIS +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.dataproxy.MullvadProblemReport import net.mullvad.mullvadvpn.dataproxy.SendProblemReportResult import net.mullvad.mullvadvpn.dataproxy.UserReport @@ -50,7 +52,11 @@ class ReportProblemViewModel( description = userReport.description, ) } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), ReportProblemUiState()) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + ReportProblemUiState(), + ) private val _uiSideEffect = Channel<ReportProblemSideEffect>() val uiSideEffect = _uiSideEffect.receiveAsFlow() diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ServerIpOverridesViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ServerIpOverridesViewModel.kt index 9d9d0380b3..a0555b6e48 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ServerIpOverridesViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ServerIpOverridesViewModel.kt @@ -10,12 +10,14 @@ import java.io.InputStreamReader import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.SettingsPatchError import net.mullvad.mullvadvpn.repository.RelayOverridesRepository import net.mullvad.mullvadvpn.util.Lc @@ -41,7 +43,11 @@ class ServerIpOverridesViewModel( ) .toLc<Boolean, ServerIpOverridesUiState>() } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Lc.Loading(navArgs.isModal)) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + Lc.Loading(navArgs.isModal), + ) fun importFile(uri: Uri) = viewModelScope.launch { diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SettingsViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SettingsViewModel.kt index b3b09889c3..dad4f1f677 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SettingsViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SettingsViewModel.kt @@ -4,9 +4,11 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import net.mullvad.mullvadvpn.compose.state.SettingsUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.DeviceState import net.mullvad.mullvadvpn.lib.shared.DeviceRepository import net.mullvad.mullvadvpn.repository.SettingsRepository @@ -41,5 +43,9 @@ class SettingsViewModel( ) .toLc<Unit, SettingsUiState>() } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Lc.Loading(Unit)) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + Lc.Loading(Unit), + ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ShadowsocksCustomPortDialogViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ShadowsocksCustomPortDialogViewModel.kt index a3ce03428f..da38dfe201 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ShadowsocksCustomPortDialogViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ShadowsocksCustomPortDialogViewModel.kt @@ -10,10 +10,12 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.Port import net.mullvad.mullvadvpn.lib.model.PortRange import net.mullvad.mullvadvpn.util.inAnyOf @@ -31,7 +33,7 @@ class ShadowsocksCustomPortDialogViewModel( combine(_portInput, _isValidPort, ::createState) .stateIn( viewModelScope, - SharingStarted.WhileSubscribed(), + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), createState(_portInput.value, _isValidPort.value), ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ShadowsocksSettingsViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ShadowsocksSettingsViewModel.kt index c7c9e8d900..c1f95713bd 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ShadowsocksSettingsViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ShadowsocksSettingsViewModel.kt @@ -6,6 +6,7 @@ import co.touchlab.kermit.Logger import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.first @@ -14,6 +15,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.ShadowsocksSettingsUiState import net.mullvad.mullvadvpn.constant.SHADOWSOCKS_PRESET_PORTS +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.Constraint import net.mullvad.mullvadvpn.lib.model.Port import net.mullvad.mullvadvpn.repository.SettingsRepository @@ -38,7 +40,7 @@ class ShadowsocksSettingsViewModel(private val settingsRepository: SettingsRepos } .stateIn( scope = viewModelScope, - started = SharingStarted.WhileSubscribed(), + started = SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), initialValue = Lc.Loading(Unit), ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SplitTunnelingViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SplitTunnelingViewModel.kt index 8743afc308..679f9316f6 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SplitTunnelingViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SplitTunnelingViewModel.kt @@ -8,12 +8,14 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.applist.AppData import net.mullvad.mullvadvpn.applist.ApplicationsProvider +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.AppId import net.mullvad.mullvadvpn.repository.SplitTunnelingRepository import net.mullvad.mullvadvpn.util.Lc @@ -45,7 +47,7 @@ class SplitTunnelingViewModel( } .stateIn( viewModelScope, - SharingStarted.WhileSubscribed(), + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), SplitTunnelingViewModelState(), ) @@ -54,7 +56,7 @@ class SplitTunnelingViewModel( .map { it.toUiState(navArgs.isModal) } .stateIn( viewModelScope, - SharingStarted.WhileSubscribed(), + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), Lc.Loading(Loading(enabled = false, isModal = navArgs.isModal)), ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/Udp2TcpSettingsViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/Udp2TcpSettingsViewModel.kt index 0d7d1293b5..798bf82341 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/Udp2TcpSettingsViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/Udp2TcpSettingsViewModel.kt @@ -5,11 +5,13 @@ import androidx.lifecycle.viewModelScope import co.touchlab.kermit.Logger import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.Udp2TcpSettingsUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.Constraint import net.mullvad.mullvadvpn.lib.model.Port import net.mullvad.mullvadvpn.repository.SettingsRepository @@ -26,7 +28,7 @@ class Udp2TcpSettingsViewModel(private val repository: SettingsRepository) : Vie } .stateIn( scope = viewModelScope, - started = SharingStarted.WhileSubscribed(), + started = SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), initialValue = Lc.Loading(Unit), ) 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 index 23fe12130e..25cac3f132 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModel.kt @@ -5,12 +5,14 @@ import androidx.lifecycle.viewModelScope import arrow.core.raise.either import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.VoucherDialogState import net.mullvad.mullvadvpn.compose.state.VoucherDialogUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.constant.VOUCHER_LENGTH import net.mullvad.mullvadvpn.lib.model.ParseVoucherCodeError import net.mullvad.mullvadvpn.lib.model.RedeemVoucherError @@ -27,7 +29,11 @@ class VoucherDialogViewModel(private val voucherRepository: VoucherRepository) : combine(vmState, voucherInput) { state, input -> VoucherDialogUiState(voucherInput = input, voucherState = state) } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), VoucherDialogUiState.INITIAL) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + VoucherDialogUiState.INITIAL, + ) fun onRedeem(voucherInput: String) { vmState.update { VoucherDialogState.Verifying } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt index 9ba3e00995..19e9ae12ea 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt @@ -15,6 +15,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterNotNull @@ -25,6 +26,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.CustomDnsItem import net.mullvad.mullvadvpn.compose.state.VpnSettingsUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.constant.WIREGUARD_PRESET_PORTS import net.mullvad.mullvadvpn.lib.model.Constraint import net.mullvad.mullvadvpn.lib.model.DefaultDnsOptions @@ -126,7 +128,11 @@ class VpnSettingsViewModel( ) .toLc<Boolean, VpnSettingsUiState>() } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Lc.Loading(navArgs.isModal)) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + Lc.Loading(navArgs.isModal), + ) fun onToggleLocalNetworkSharing(isEnabled: Boolean) { viewModelScope.launch(dispatcher) { diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModel.kt index d8ea161787..e2a2fbb6f5 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.delay import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull @@ -16,6 +17,7 @@ import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.WelcomeUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.common.util.isAfterNowInstant import net.mullvad.mullvadvpn.lib.model.AccountNumber import net.mullvad.mullvadvpn.lib.model.WebsiteAuthToken @@ -55,7 +57,11 @@ class WelcomeViewModel( ) ) } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Lc.Loading(Unit)) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + Lc.Loading(Unit), + ) init { viewModelScope.launch { diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WireguardCustomPortDialogViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WireguardCustomPortDialogViewModel.kt index b98801612e..a3fcfa97f9 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WireguardCustomPortDialogViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WireguardCustomPortDialogViewModel.kt @@ -10,10 +10,12 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.Port import net.mullvad.mullvadvpn.lib.model.PortRange import net.mullvad.mullvadvpn.util.inAnyOf @@ -31,7 +33,7 @@ class WireguardCustomPortDialogViewModel( combine(_portInput, _isValidPort, ::createState) .stateIn( viewModelScope, - SharingStarted.WhileSubscribed(), + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), createState(_portInput.value, _isValidPort.value), ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SearchLocationViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SearchLocationViewModel.kt index fde0b3b94d..4c20dd424b 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SearchLocationViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SearchLocationViewModel.kt @@ -8,6 +8,7 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn @@ -17,6 +18,7 @@ import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData import net.mullvad.mullvadvpn.compose.state.MultihopRelayListType import net.mullvad.mullvadvpn.compose.state.RelayListType import net.mullvad.mullvadvpn.compose.state.SearchLocationUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.Constraint import net.mullvad.mullvadvpn.lib.model.CustomListId import net.mullvad.mullvadvpn.lib.model.Hop @@ -120,7 +122,11 @@ class SearchLocationViewModel( ) ) } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Lce.Loading(Unit)) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + Lce.Loading(Unit), + ) private val _uiSideEffect = Channel<SearchLocationSideEffect>() val uiSideEffect = _uiSideEffect.receiveAsFlow() diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationListViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationListViewModel.kt index bd9929c87d..fa0174ce32 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationListViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationListViewModel.kt @@ -5,11 +5,13 @@ import androidx.lifecycle.viewModelScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import net.mullvad.mullvadvpn.compose.state.MultihopRelayListType import net.mullvad.mullvadvpn.compose.state.RelayListType import net.mullvad.mullvadvpn.compose.state.SelectLocationListUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.CustomListId import net.mullvad.mullvadvpn.lib.model.GeoLocationId import net.mullvad.mullvadvpn.lib.model.RelayItemId @@ -55,7 +57,11 @@ class SelectLocationListViewModel( ) } } - .stateIn(viewModelScope, SharingStarted.Lazily, Lce.Loading(Unit)) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + Lce.Loading(Unit), + ) fun onToggleExpand(item: RelayItemId, parent: CustomListId? = null, expand: Boolean) { _expandedItems.onToggleExpandSet(item, parent, expand) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModel.kt index 0ddb20efa7..8db8da3c35 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModel.kt @@ -6,6 +6,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flatMapLatest @@ -17,6 +18,7 @@ import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData import net.mullvad.mullvadvpn.compose.state.MultihopRelayListType import net.mullvad.mullvadvpn.compose.state.RelayListType import net.mullvad.mullvadvpn.compose.state.SelectLocationUiState +import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT import net.mullvad.mullvadvpn.lib.model.Constraint import net.mullvad.mullvadvpn.lib.model.CustomListId import net.mullvad.mullvadvpn.lib.model.Hop @@ -86,7 +88,11 @@ class SelectLocationViewModel( ) ) } - .stateIn(viewModelScope, SharingStarted.Lazily, Lc.Loading(Unit)) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), + Lc.Loading(Unit), + ) private val _uiSideEffect = Channel<SelectLocationSideEffect>() val uiSideEffect = _uiSideEffect.receiveAsFlow() |
