diff options
| author | saber safavi <saber.safavi@codic.se> | 2023-08-24 10:51:29 +0200 |
|---|---|---|
| committer | saber safavi <saber.safavi@codic.se> | 2023-09-28 14:51:15 +0200 |
| commit | aae59ac285b264fb163fba1470a6e83df8892eb7 (patch) | |
| tree | 8b99d589a1bd445802163b0e653cb0e1ae1ea4b6 | |
| parent | 34758da9ee93e22dce2bac98722d322414195d14 (diff) | |
| download | mullvadvpn-aae59ac285b264fb163fba1470a6e83df8892eb7.tar.xz mullvadvpn-aae59ac285b264fb163fba1470a6e83df8892eb7.zip | |
Add info dialog for device name
8 files changed, 82 insertions, 53 deletions
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 5d3e229a8b..c4d2fab62e 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 @@ -9,7 +9,7 @@ import io.mockk.mockk import io.mockk.verify import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.asSharedFlow -import net.mullvad.mullvadvpn.compose.state.AccountUiState +import net.mullvad.mullvadvpn.viewmodel.AccountUiState import net.mullvad.mullvadvpn.viewmodel.AccountViewModel import org.junit.Before import org.junit.Rule diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DeviceNameInfoDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DeviceNameInfoDialog.kt new file mode 100644 index 0000000000..39e82bc57d --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DeviceNameInfoDialog.kt @@ -0,0 +1,20 @@ +package net.mullvad.mullvadvpn.compose.dialog + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import net.mullvad.mullvadvpn.R + +@Composable +fun DeviceNameInfoDialog(onDismiss: () -> Unit) { + InfoDialog( + message = + buildString { + appendLine(stringResource(id = R.string.device_name_info_first_paragraph)) + appendLine() + appendLine(stringResource(id = R.string.device_name_info_second_paragraph)) + appendLine() + append(stringResource(id = R.string.device_name_info_third_paragraph)) + }, + onDismiss = onDismiss + ) +} 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 22dfc34269..b3bc9e7f3b 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 @@ -1,9 +1,9 @@ package net.mullvad.mullvadvpn.compose.screen import androidx.compose.animation.animateContentSize -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -11,14 +11,21 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import com.google.accompanist.systemuicontroller.rememberSystemUiController @@ -35,12 +42,13 @@ import net.mullvad.mullvadvpn.compose.component.CopyableObfuscationView import net.mullvad.mullvadvpn.compose.component.InformationView import net.mullvad.mullvadvpn.compose.component.MissingPolicy import net.mullvad.mullvadvpn.compose.component.drawVerticalScrollbar -import net.mullvad.mullvadvpn.compose.state.AccountUiState +import net.mullvad.mullvadvpn.compose.dialog.DeviceNameInfoDialog import net.mullvad.mullvadvpn.constant.IS_PLAY_BUILD import net.mullvad.mullvadvpn.lib.common.util.capitalizeFirstCharOfEachWord import net.mullvad.mullvadvpn.lib.common.util.openAccountPageInBrowser import net.mullvad.mullvadvpn.lib.theme.Dimens import net.mullvad.mullvadvpn.util.toExpiryDateString +import net.mullvad.mullvadvpn.viewmodel.AccountUiState import net.mullvad.mullvadvpn.viewmodel.AccountViewModel @OptIn(ExperimentalMaterial3Api::class) @@ -76,9 +84,15 @@ fun AccountScreen( val backgroundColor = MaterialTheme.colorScheme.background val systemUiController = rememberSystemUiController() + var showDeviceNameInfoDialog by remember { mutableStateOf(false) } + LaunchedEffect(Unit) { enterTransitionEndAction.collect { systemUiController.setStatusBarColor(backgroundColor) } } + if (showDeviceNameInfoDialog) { + DeviceNameInfoDialog { showDeviceNameInfoDialog = false } + } + CollapsingToolbarScaffold( backgroundColor = MaterialTheme.colorScheme.background, modifier = Modifier.fillMaxSize(), @@ -127,10 +141,22 @@ fun AccountScreen( modifier = Modifier.padding(start = Dimens.sideMargin, end = Dimens.sideMargin) ) - InformationView( - content = uiState.deviceName.capitalizeFirstCharOfEachWord(), - whenMissing = MissingPolicy.SHOW_SPINNER - ) + Row(verticalAlignment = Alignment.CenterVertically) { + InformationView( + content = uiState.deviceName?.capitalizeFirstCharOfEachWord() ?: "", + whenMissing = MissingPolicy.SHOW_SPINNER + ) + IconButton( + modifier = Modifier.align(Alignment.CenterVertically), + onClick = { showDeviceNameInfoDialog = true } + ) { + Icon( + painter = painterResource(id = R.drawable.icon_info), + contentDescription = null, + tint = MaterialTheme.colorScheme.inverseSurface + ) + } + } Text( style = MaterialTheme.typography.labelMedium, @@ -142,9 +168,7 @@ fun AccountScreen( top = Dimens.smallPadding ) ) - - CopyableObfuscationView(content = uiState.accountNumber) - + CopyableObfuscationView(content = uiState.accountNumber ?: "") Text( style = MaterialTheme.typography.labelMedium, text = stringResource(id = R.string.paid_until), diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreen.kt index b78f767f76..140b9824df 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreen.kt @@ -38,7 +38,7 @@ import net.mullvad.mullvadvpn.compose.button.SitePaymentButton import net.mullvad.mullvadvpn.compose.component.CopyAnimatedIconButton import net.mullvad.mullvadvpn.compose.component.ScaffoldWithTopBar import net.mullvad.mullvadvpn.compose.component.drawVerticalScrollbar -import net.mullvad.mullvadvpn.compose.dialog.InfoDialog +import net.mullvad.mullvadvpn.compose.dialog.DeviceNameInfoDialog import net.mullvad.mullvadvpn.compose.state.WelcomeUiState import net.mullvad.mullvadvpn.compose.util.createCopyToClipboardHandle import net.mullvad.mullvadvpn.lib.common.util.groupWithSpaces @@ -47,7 +47,6 @@ import net.mullvad.mullvadvpn.lib.theme.AlphaTopBar import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.lib.theme.Dimens import net.mullvad.mullvadvpn.lib.theme.MullvadWhite -import net.mullvad.mullvadvpn.ui.extension.copyToClipboard import net.mullvad.mullvadvpn.viewmodel.WelcomeViewModel @Preview @@ -253,17 +252,7 @@ fun DeviceNameRow(deviceName: String?) { ) } if (showDeviceNameDialog) { - InfoDialog( - message = - buildString { - appendLine(stringResource(id = R.string.device_name_info_first_paragraph)) - appendLine() - appendLine(stringResource(id = R.string.device_name_info_second_paragraph)) - appendLine() - appendLine(stringResource(id = R.string.device_name_info_third_paragraph)) - }, - onDismiss = { showDeviceNameDialog = false } - ) + DeviceNameInfoDialog { showDeviceNameDialog = false } } } } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/AccountUiState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/AccountUiState.kt deleted file mode 100644 index a952795571..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/AccountUiState.kt +++ /dev/null @@ -1,9 +0,0 @@ -package net.mullvad.mullvadvpn.compose.state - -import org.joda.time.DateTime - -data class AccountUiState( - val deviceName: String, - val accountNumber: String, - val accountExpiry: DateTime? -) 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 39013f11a8..666bd19cdb 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 @@ -36,10 +36,9 @@ class AccountFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter { enterTransitionEndAction = vm.enterTransitionEndAction, onRedeemVoucherClick = { openRedeemVoucherFragment() }, onManageAccountClick = vm::onManageAccountClick, - onLogoutClick = vm::onLogoutClick - ) { - activity?.onBackPressed() - } + onLogoutClick = vm::onLogoutClick, + onBackClick = { activity?.onBackPressedDispatcher?.onBackPressed() } + ) } } } 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 e359deed2e..b1ce2e0027 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 @@ -4,16 +4,17 @@ 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.AccountUiState +import net.mullvad.mullvadvpn.model.AccountExpiry +import net.mullvad.mullvadvpn.model.DeviceState import net.mullvad.mullvadvpn.repository.AccountRepository import net.mullvad.mullvadvpn.repository.DeviceRepository import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager import net.mullvad.mullvadvpn.ui.serviceconnection.authTokenCache +import org.joda.time.DateTime class AccountViewModel( private var accountRepository: AccountRepository, @@ -25,27 +26,17 @@ class AccountViewModel( private val _enterTransitionEndAction = MutableSharedFlow<Unit>() val viewActions = _viewActions.asSharedFlow() - private val vmState: StateFlow<AccountUiState> = + val uiState = combine(deviceRepository.deviceState, accountRepository.accountExpiryState) { deviceState, accountExpiry -> AccountUiState( - deviceName = deviceState.deviceName() ?: "", - accountNumber = deviceState.token() ?: "", + deviceName = deviceState.deviceName(), + accountNumber = deviceState.token(), accountExpiry = accountExpiry.date() ) } - .stateIn( - viewModelScope, - SharingStarted.WhileSubscribed(), - AccountUiState(deviceName = "", accountNumber = "", accountExpiry = null) - ) - val uiState = - vmState.stateIn( - viewModelScope, - SharingStarted.WhileSubscribed(), - AccountUiState(deviceName = "", accountNumber = "", accountExpiry = null) - ) + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), AccountUiState.default()) val enterTransitionEndAction = _enterTransitionEndAction.asSharedFlow() @@ -71,3 +62,18 @@ class AccountViewModel( data class OpenAccountManagementPageInBrowser(val token: String) : ViewAction() } } + +data class AccountUiState( + val deviceName: String?, + val accountNumber: String?, + val accountExpiry: DateTime? +) { + companion object { + fun default() = + AccountUiState( + deviceName = DeviceState.Unknown.deviceName(), + accountNumber = DeviceState.Unknown.token(), + accountExpiry = AccountExpiry.Missing.date() + ) + } +} diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt index 82048b5fd1..fc1fd5e99b 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt @@ -73,7 +73,7 @@ class AccountViewModelTest { // Act, Assert viewModel.uiState.test { var result = awaitItem() - assertEquals("", result.deviceName) + assertEquals(null, result.deviceName) deviceState.value = DeviceState.LoggedIn(accountAndDevice = dummyAccountAndDevice) result = awaitItem() assertEquals(DUMMY_DEVICE_NAME, result.accountNumber) |
