diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt index e616f67449b1..5d3e229a8ba6 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt @@ -35,7 +35,8 @@ class AccountScreenTest { accountNumber = DUMMY_ACCOUNT_NUMBER, accountExpiry = null ), - viewActions = MutableSharedFlow().asSharedFlow() + viewActions = MutableSharedFlow().asSharedFlow(), + enterTransitionEndAction = MutableSharedFlow().asSharedFlow() ) } @@ -60,6 +61,7 @@ class AccountScreenTest { accountExpiry = null ), viewActions = MutableSharedFlow().asSharedFlow(), + enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), onManageAccountClick = mockedClickHandler ) } @@ -85,6 +87,7 @@ class AccountScreenTest { accountExpiry = null ), viewActions = MutableSharedFlow().asSharedFlow(), + enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), onRedeemVoucherClick = mockedClickHandler ) } @@ -110,6 +113,7 @@ class AccountScreenTest { accountExpiry = null ), viewActions = MutableSharedFlow().asSharedFlow(), + enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), onLogoutClick = mockedClickHandler ) } diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreenTest.kt index c7992edf344e..4844177b45ac 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreenTest.kt @@ -8,6 +8,7 @@ import io.mockk.MockKAnnotations import io.mockk.mockk import io.mockk.verify import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.asSharedFlow import net.mullvad.mullvadvpn.compose.state.SelectLocationUiState import net.mullvad.mullvadvpn.compose.test.CIRCULAR_PROGRESS_INDICATOR import net.mullvad.mullvadvpn.lib.theme.AppTheme @@ -37,7 +38,8 @@ class SelectLocationScreenTest { composeTestRule.setContent { SelectLocationScreen( uiState = SelectLocationUiState.Loading, - uiCloseAction = MutableSharedFlow() + uiCloseAction = MutableSharedFlow(), + enterTransitionEndAction = MutableSharedFlow().asSharedFlow() ) } @@ -55,7 +57,8 @@ class SelectLocationScreenTest { countries = DUMMY_RELAY_COUNTRIES, selectedRelay = null ), - uiCloseAction = MutableSharedFlow() + uiCloseAction = MutableSharedFlow(), + enterTransitionEndAction = MutableSharedFlow().asSharedFlow() ) } @@ -85,7 +88,8 @@ class SelectLocationScreenTest { }, selectedRelay = DUMMY_RELAY_COUNTRIES[0].cities[0].relays[0] ), - uiCloseAction = MutableSharedFlow() + uiCloseAction = MutableSharedFlow(), + enterTransitionEndAction = MutableSharedFlow().asSharedFlow() ) } } @@ -114,6 +118,7 @@ class SelectLocationScreenTest { selectedRelay = null ), uiCloseAction = MutableSharedFlow(), + enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), onSearchTermInput = mockedSearchTermInput ) } @@ -138,6 +143,7 @@ class SelectLocationScreenTest { uiState = SelectLocationUiState.NoSearchResultFound(searchTerm = mockSearchString), uiCloseAction = MutableSharedFlow(), + enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), onSearchTermInput = mockedSearchTermInput ) } diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt index 5ed9ac1c8a39..6a163dbbb0b2 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt @@ -4,6 +4,8 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onNodeWithText import io.mockk.MockKAnnotations +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.asSharedFlow import net.mullvad.mullvadvpn.compose.state.SettingsUiState import org.junit.Before import org.junit.Rule @@ -24,7 +26,8 @@ class SettingsScreenTest { composeTestRule.setContent { SettingsScreen( uiState = - SettingsUiState(appVersion = "", isLoggedIn = true, isUpdateAvailable = true) + SettingsUiState(appVersion = "", isLoggedIn = true, isUpdateAvailable = true), + enterTransitionEndAction = MutableSharedFlow().asSharedFlow() ) } // Assert @@ -42,7 +45,8 @@ class SettingsScreenTest { composeTestRule.setContent { SettingsScreen( uiState = - SettingsUiState(appVersion = "", isLoggedIn = false, isUpdateAvailable = true) + SettingsUiState(appVersion = "", isLoggedIn = false, isUpdateAvailable = true), + enterTransitionEndAction = MutableSharedFlow().asSharedFlow() ) } // Assert diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/CollapsingToolbarScaffold.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/CollapsingToolbarScaffold.kt index f4b81826bc02..d1651e542f96 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/CollapsingToolbarScaffold.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/CollapsingToolbarScaffold.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue @@ -38,7 +39,6 @@ fun CollapsingToolbarScaffold( ) { val dynamic = remember { mutableStateOf(0.dp) } val systemUiController = rememberSystemUiController() - systemUiController.setStatusBarColor(backgroundColor) systemUiController.setNavigationBarColor(backgroundColor) var isCollapsable by remember { mutableStateOf(false) } @@ -48,6 +48,7 @@ fun CollapsingToolbarScaffold( state.toolbarState.expand() } } + val totalHeights = remember { mutableStateOf(0.dp) } val localDensity = LocalDensity.current @@ -71,7 +72,7 @@ fun CollapsingToolbarScaffold( enabled = isEnabledWhenCollapsable && isCollapsable, toolbar = { toolbar() } ) { - var bodyHeight by remember { mutableStateOf(0) } + var bodyHeight by remember { mutableIntStateOf(0) } BoxWithConstraints( modifier = diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt index 2cfe0c65d9a0..a83881390dcc 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt @@ -67,7 +67,6 @@ fun CollapsableAwareToolbarScaffold( body: @Composable CollapsingToolbarScaffoldScope.() -> Unit ) { val systemUiController = rememberSystemUiController() - systemUiController.setStatusBarColor(backgroundColor) systemUiController.setNavigationBarColor(backgroundColor) var isCollapsable by remember { mutableStateOf(false) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreen.kt index c9f90b4d53c5..4beaa6fc2072 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreen.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import com.google.accompanist.systemuicontroller.rememberSystemUiController import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.asSharedFlow @@ -54,6 +55,7 @@ private fun PreviewAccountScreen() { accountExpiry = null ), viewActions = MutableSharedFlow().asSharedFlow(), + enterTransitionEndAction = MutableSharedFlow() ) } @@ -62,6 +64,7 @@ private fun PreviewAccountScreen() { fun AccountScreen( uiState: AccountUiState, viewActions: SharedFlow, + enterTransitionEndAction: SharedFlow, onRedeemVoucherClick: () -> Unit = {}, onManageAccountClick: () -> Unit = {}, onLogoutClick: () -> Unit = {}, @@ -70,7 +73,12 @@ fun AccountScreen( val context = LocalContext.current val state = rememberCollapsingToolbarScaffoldState() val progress = state.toolbarState.progress + val backgroundColor = MaterialTheme.colorScheme.background + val systemUiController = rememberSystemUiController() + LaunchedEffect(Unit) { + enterTransitionEndAction.collect { systemUiController.setStatusBarColor(backgroundColor) } + } CollapsingToolbarScaffold( backgroundColor = MaterialTheme.colorScheme.background, modifier = Modifier.fillMaxSize(), diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreen.kt index 162c0317a6c8..6dc1461a6f0b 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreen.kt @@ -18,6 +18,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi @@ -34,6 +35,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.core.text.HtmlCompat +import com.google.accompanist.systemuicontroller.rememberSystemUiController import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow import net.mullvad.mullvadvpn.R @@ -57,7 +59,13 @@ fun PreviewSelectLocationScreen() { countries = listOf(RelayCountry("Country 1", "Code 1", false, emptyList())), selectedRelay = null ) - AppTheme { SelectLocationScreen(uiState = state, uiCloseAction = MutableSharedFlow()) } + AppTheme { + SelectLocationScreen( + uiState = state, + uiCloseAction = MutableSharedFlow(), + enterTransitionEndAction = MutableSharedFlow() + ) + } } @OptIn(ExperimentalComposeUiApi::class) @@ -65,16 +73,21 @@ fun PreviewSelectLocationScreen() { fun SelectLocationScreen( uiState: SelectLocationUiState, uiCloseAction: SharedFlow, + enterTransitionEndAction: SharedFlow, onSelectRelay: (item: RelayItem) -> Unit = {}, onSearchTermInput: (searchTerm: String) -> Unit = {}, onBackClick: () -> Unit = {} ) { + val backgroundColor = MaterialTheme.colorScheme.background + val systemUiController = rememberSystemUiController() + LaunchedEffect(Unit) { uiCloseAction.collect { onBackClick() } } + LaunchedEffect(Unit) { + enterTransitionEndAction.collect { systemUiController.setStatusBarColor(backgroundColor) } + } + val (backFocus, listFocus, searchBarFocus) = remember { FocusRequester.createRefs() } - Column( - modifier = - Modifier.background(MaterialTheme.colorScheme.background).fillMaxWidth().fillMaxHeight() - ) { + Column(modifier = Modifier.background(backgroundColor).fillMaxWidth().fillMaxHeight()) { Row( modifier = Modifier.padding( diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreen.kt index 22edb7a9501e..a9c3aa5ea946 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreen.kt @@ -15,12 +15,16 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import com.google.accompanist.systemuicontroller.rememberSystemUiController +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow import me.onebone.toolbar.ScrollStrategy import me.onebone.toolbar.rememberCollapsingToolbarScaffoldState import net.mullvad.mullvadvpn.BuildConfig @@ -45,7 +49,8 @@ import net.mullvad.mullvadvpn.lib.theme.Dimens private fun PreviewSettings() { SettingsScreen( uiState = - SettingsUiState(appVersion = "2222.22", isLoggedIn = true, isUpdateAvailable = true) + SettingsUiState(appVersion = "2222.22", isLoggedIn = true, isUpdateAvailable = true), + enterTransitionEndAction = MutableSharedFlow() ) } @@ -53,6 +58,7 @@ private fun PreviewSettings() { @Composable fun SettingsScreen( uiState: SettingsUiState, + enterTransitionEndAction: SharedFlow, onVpnSettingCellClick: () -> Unit = {}, onSplitTunnelingCellClick: () -> Unit = {}, onReportProblemCellClick: () -> Unit = {}, @@ -62,6 +68,12 @@ fun SettingsScreen( val lazyListState = rememberLazyListState() val state = rememberCollapsingToolbarScaffoldState() val progress = state.toolbarState.progress + val backgroundColor = MaterialTheme.colorScheme.background + val systemUiController = rememberSystemUiController() + + LaunchedEffect(Unit) { + enterTransitionEndAction.collect { systemUiController.setStatusBarColor(backgroundColor) } + } CollapsableAwareToolbarScaffold( backgroundColor = MaterialTheme.colorScheme.background, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AccountFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AccountFragment.kt index 52e131ed7985..39013f11a868 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AccountFragment.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AccountFragment.kt @@ -33,6 +33,7 @@ class AccountFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter { AccountScreen( uiState = state, viewActions = vm.viewActions, + enterTransitionEndAction = vm.enterTransitionEndAction, onRedeemVoucherClick = { openRedeemVoucherFragment() }, onManageAccountClick = vm::onManageAccountClick, onLogoutClick = vm::onLogoutClick @@ -54,6 +55,10 @@ class AccountFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter { requireMainActivity().leaveSecureScreen(this) } + override fun onEnterTransitionAnimationEnd() { + vm.onTransitionAnimationEnd() + } + private fun openRedeemVoucherFragment() { val transaction = parentFragmentManager.beginTransaction() transaction.addToBackStack(null) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/BaseFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/BaseFragment.kt index bfbe4bdd2562..610f76578a8a 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/BaseFragment.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/BaseFragment.kt @@ -26,15 +26,34 @@ abstract class BaseFragment : Fragment { 0f } ViewCompat.setTranslationZ(requireView(), zAdjustment) - return if (nextAnim != 0 && enter) { - AnimationUtils.loadAnimation(context, nextAnim)?.apply { - transitionFinishedFlow = transitionFinished() + val anim = + if (nextAnim != 0 && enter) { + AnimationUtils.loadAnimation(context, nextAnim)?.apply { + transitionFinishedFlow = transitionFinished() + } + } else { + super.onCreateAnimation(transit, enter, nextAnim) } - } else { - super.onCreateAnimation(transit, enter, nextAnim) + anim?.let { + anim.setAnimationListener( + object : Animation.AnimationListener { + override fun onAnimationStart(animation: Animation?) {} + + override fun onAnimationRepeat(animation: Animation?) {} + + override fun onAnimationEnd(animation: Animation?) { + if (enter) { + onEnterTransitionAnimationEnd() + } + } + }, + ) } + return anim } + open fun onEnterTransitionAnimationEnd() {} + companion object { private val animationsToAdjustZorder = listOf( diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SelectLocationFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SelectLocationFragment.kt index ec7a768b6dea..d56b51850b6d 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SelectLocationFragment.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SelectLocationFragment.kt @@ -4,10 +4,8 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.collectAsState import androidx.compose.ui.platform.ComposeView -import com.google.accompanist.systemuicontroller.rememberSystemUiController import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.screen.SelectLocationScreen import net.mullvad.mullvadvpn.lib.theme.AppTheme @@ -28,20 +26,21 @@ class SelectLocationFragment : BaseFragment(), StatusBarPainter, NavigationBarPa return inflater.inflate(R.layout.fragment_compose, container, false).apply { findViewById(R.id.compose_view).setContent { AppTheme { - val systemUiController = rememberSystemUiController() - systemUiController.setStatusBarColor(MaterialTheme.colorScheme.background) - systemUiController.setNavigationBarColor(MaterialTheme.colorScheme.background) - val state = vm.uiState.collectAsState().value SelectLocationScreen( uiState = state, uiCloseAction = vm.uiCloseAction, + enterTransitionEndAction = vm.enterTransitionEndAction, onSelectRelay = vm::selectRelay, onSearchTermInput = vm::onSearchTermInput, - onBackClick = { activity?.onBackPressedDispatcher?.onBackPressed() } + onBackClick = { activity?.onBackPressedDispatcher?.onBackPressed() }, ) } } } } + + override fun onEnterTransitionAnimationEnd() { + vm.onTransitionAnimationEnd() + } } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SettingsFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SettingsFragment.kt index 1c126c4dab04..64b3e6b425cd 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SettingsFragment.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SettingsFragment.kt @@ -31,6 +31,7 @@ class SettingsFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter val state = vm.uiState.collectAsState().value SettingsScreen( uiState = state, + enterTransitionEndAction = vm.enterTransitionEndAction, onVpnSettingCellClick = { openVpnSettingsFragment() }, onSplitTunnelingCellClick = { openSplitTunnelingFragment() }, onReportProblemCellClick = { openReportProblemFragment() }, @@ -41,6 +42,10 @@ class SettingsFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter } } + override fun onEnterTransitionAnimationEnd() { + vm.onTransitionAnimationEnd() + } + private fun openFragment(fragment: Fragment) { parentFragmentManager.beginTransaction().apply { setCustomAnimations( 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 30c1464a91e9..ba1d6e681844 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 @@ -22,6 +22,7 @@ class AccountViewModel( ) : ViewModel() { private val _viewActions = MutableSharedFlow(extraBufferCapacity = 1) + private val _enterTransitionEndAction = MutableSharedFlow() val viewActions = _viewActions.asSharedFlow() private val vmState: StateFlow = @@ -46,6 +47,8 @@ class AccountViewModel( AccountUiState(deviceName = "", accountNumber = "", accountExpiry = null) ) + val enterTransitionEndAction = _enterTransitionEndAction.asSharedFlow() + fun onManageAccountClick() { viewModelScope.launch { _viewActions.tryEmit( @@ -60,6 +63,10 @@ class AccountViewModel( accountRepository.logout() } + fun onTransitionAnimationEnd() { + viewModelScope.launch { _enterTransitionEndAction.emit(Unit) } + } + sealed class ViewAction { data class OpenAccountView(val token: String) : ViewAction() } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SelectLocationViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SelectLocationViewModel.kt index 31950af0cd98..4b7bca151d69 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SelectLocationViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SelectLocationViewModel.kt @@ -27,6 +27,7 @@ import net.mullvad.mullvadvpn.ui.serviceconnection.relayListListener class SelectLocationViewModel(private val serviceConnectionManager: ServiceConnectionManager) : ViewModel() { private val _closeAction = MutableSharedFlow() + private val _enterTransitionEndAction = MutableSharedFlow() private val _searchTerm = MutableStateFlow(EMPTY_SEARCH_TERM) val uiState = @@ -66,6 +67,7 @@ class SelectLocationViewModel(private val serviceConnectionManager: ServiceConne ) val uiCloseAction = _closeAction.asSharedFlow() + val enterTransitionEndAction = _enterTransitionEndAction.asSharedFlow() fun selectRelay(relayItem: RelayItem?) { serviceConnectionManager.relayListListener()?.selectedRelayLocation = relayItem?.location @@ -73,6 +75,10 @@ class SelectLocationViewModel(private val serviceConnectionManager: ServiceConne viewModelScope.launch { _closeAction.emit(Unit) } } + fun onTransitionAnimationEnd() { + viewModelScope.launch { _enterTransitionEndAction.emit(Unit) } + } + fun onSearchTermInput(searchTerm: String) { viewModelScope.launch { _searchTerm.emit(searchTerm) } } 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 8ef85cfca820..eaeaf33933e8 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 @@ -2,10 +2,13 @@ package net.mullvad.mullvadvpn.viewmodel import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.SettingsUiState import net.mullvad.mullvadvpn.model.DeviceState import net.mullvad.mullvadvpn.repository.DeviceRepository @@ -15,6 +18,7 @@ class SettingsViewModel( deviceRepository: DeviceRepository, serviceConnectionManager: ServiceConnectionManager ) : ViewModel() { + private val _enterTransitionEndAction = MutableSharedFlow() private val vmState: StateFlow = combine(deviceRepository.deviceState, serviceConnectionManager.connectionState) { @@ -40,4 +44,10 @@ class SettingsViewModel( SharingStarted.WhileSubscribed(), SettingsUiState(appVersion = "", isLoggedIn = false, isUpdateAvailable = false) ) + + val enterTransitionEndAction = _enterTransitionEndAction.asSharedFlow() + + fun onTransitionAnimationEnd() { + viewModelScope.launch { _enterTransitionEndAction.emit(Unit) } + } }