Skip to content

Commit

Permalink
Add info dialog for device name
Browse files Browse the repository at this point in the history
  • Loading branch information
sabercodic committed Sep 19, 2023
1 parent 34874c9 commit 99c5881
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
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 = stringResource(id = R.string.local_network_sharing_info),
additionalInfo =
buildString {
appendLine(stringResource(id = R.string.device_name_info_part1))
appendLine(stringResource(id = R.string.device_name_info_part2))
appendLine(stringResource(id = R.string.device_name_info_part3))
},
onDismiss = onDismiss
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,26 @@ package net.mullvad.mullvadvpn.compose.screen

import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
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
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.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.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.google.accompanist.systemuicontroller.rememberSystemUiController
Expand All @@ -35,12 +39,14 @@ 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.lib.common.constant.BuildTypes
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.AccountScreenDialogState
import net.mullvad.mullvadvpn.viewmodel.AccountUiState
import net.mullvad.mullvadvpn.viewmodel.AccountViewModel

@OptIn(ExperimentalMaterial3Api::class)
Expand All @@ -52,7 +58,8 @@ private fun PreviewAccountScreen() {
AccountUiState(
deviceName = "Test Name",
accountNumber = "1234123412341234",
accountExpiry = null
accountExpiry = null,
dialogState = AccountScreenDialogState.NoDialog
),
viewActions = MutableSharedFlow<AccountViewModel.ViewAction>().asSharedFlow(),
enterTransitionEndAction = MutableSharedFlow()
Expand All @@ -64,6 +71,8 @@ private fun PreviewAccountScreen() {
fun AccountScreen(
uiState: AccountUiState,
viewActions: SharedFlow<AccountViewModel.ViewAction>,
onDeviceNameInfoClick: () -> Unit = {},
onDismissInfoClick: () -> Unit = {},
enterTransitionEndAction: SharedFlow<Unit>,
onRedeemVoucherClick: () -> Unit = {},
onManageAccountClick: () -> Unit = {},
Expand All @@ -79,6 +88,10 @@ fun AccountScreen(
LaunchedEffect(Unit) {
enterTransitionEndAction.collect { systemUiController.setStatusBarColor(backgroundColor) }
}
if (uiState.dialogState == AccountScreenDialogState.DeviceNameInfoDialog) {
DeviceNameInfoDialog(onDismissInfoClick)
}

CollapsingToolbarScaffold(
backgroundColor = MaterialTheme.colorScheme.background,
modifier = Modifier.fillMaxSize(),
Expand Down Expand Up @@ -127,10 +140,21 @@ fun AccountScreen(
modifier = Modifier.padding(start = Dimens.sideMargin, end = Dimens.sideMargin)
)

InformationView(
content = uiState.deviceName.capitalizeFirstCharOfEachWord(),
whenMissing = MissingPolicy.SHOW_SPINNER
)
Row {
InformationView(
content = uiState.deviceName.capitalizeFirstCharOfEachWord(),
whenMissing = MissingPolicy.SHOW_SPINNER
)
Icon(
modifier =
Modifier.clickable { onDeviceNameInfoClick() }
.padding(start = Dimens.mediumPadding, end = Dimens.mediumPadding)
.align(Alignment.CenterVertically),
painter = painterResource(id = R.drawable.icon_info),
contentDescription = null,
tint = MaterialTheme.colorScheme.inverseSurface
)
}

Text(
style = MaterialTheme.typography.labelMedium,
Expand All @@ -142,9 +166,9 @@ fun AccountScreen(
top = Dimens.smallPadding
)
)

CopyableObfuscationView(content = uiState.accountNumber)

if (uiState.accountNumber != null) {
CopyableObfuscationView(content = uiState.accountNumber)
}
Text(
style = MaterialTheme.typography.labelMedium,
text = stringResource(id = R.string.paid_until),
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ class AccountFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter {
enterTransitionEndAction = vm.enterTransitionEndAction,
onRedeemVoucherClick = { openRedeemVoucherFragment() },
onManageAccountClick = vm::onManageAccountClick,
onLogoutClick = vm::onLogoutClick
) {
activity?.onBackPressed()
}
onLogoutClick = vm::onLogoutClick,
onDeviceNameInfoClick = vm::onDeviceNameInfoClick,
onDismissInfoClick = vm::onDismissInfoClick,
onBackClick = { activity?.onBackPressedDispatcher?.onBackPressed() }
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package net.mullvad.mullvadvpn.viewmodel

import net.mullvad.mullvadvpn.model.AccountExpiry
import net.mullvad.mullvadvpn.model.DeviceState
import org.joda.time.DateTime

data class AccountUiState(
val deviceName: String,
val accountNumber: String?,
val accountExpiry: DateTime?,
val dialogState: AccountScreenDialogState = AccountScreenDialogState.NoDialog
) {
companion object {
fun default() =
AccountUiState(
deviceName = DeviceState.Unknown.deviceName() ?: "",
accountNumber = DeviceState.Unknown.token(),
accountExpiry = AccountExpiry.Missing.date(),
dialogState = AccountScreenDialogState.NoDialog
)
}
}

sealed class AccountScreenDialogState {
data object NoDialog : AccountScreenDialogState()

data object DeviceNameInfoDialog : AccountScreenDialogState()
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ package net.mullvad.mullvadvpn.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
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.flow.update
import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.compose.state.AccountUiState
import net.mullvad.mullvadvpn.repository.AccountRepository
import net.mullvad.mullvadvpn.repository.DeviceRepository
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager
Expand All @@ -25,27 +26,24 @@ class AccountViewModel(
private val _enterTransitionEndAction = MutableSharedFlow<Unit>()
val viewActions = _viewActions.asSharedFlow()

private val dialogState =
MutableStateFlow<AccountScreenDialogState>(AccountScreenDialogState.NoDialog)

private val vmState: StateFlow<AccountUiState> =
combine(deviceRepository.deviceState, accountRepository.accountExpiryState) {
combine(deviceRepository.deviceState, accountRepository.accountExpiryState, dialogState) {
deviceState,
accountExpiry ->
accountExpiry,
dialogState ->
AccountUiState(
deviceName = deviceState.deviceName() ?: "",
accountNumber = deviceState.token() ?: "",
accountExpiry = accountExpiry.date()
accountNumber = deviceState.token(),
accountExpiry = accountExpiry.date(),
dialogState = dialogState
)
}
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(),
AccountUiState(deviceName = "", accountNumber = "", accountExpiry = null)
)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), AccountUiState.default())
val uiState =
vmState.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(),
AccountUiState(deviceName = "", accountNumber = "", accountExpiry = null)
)
vmState.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), AccountUiState.default())

val enterTransitionEndAction = _enterTransitionEndAction.asSharedFlow()

Expand All @@ -63,6 +61,18 @@ class AccountViewModel(
accountRepository.logout()
}

fun onDeviceNameInfoClick() {
dialogState.update { AccountScreenDialogState.DeviceNameInfoDialog }
}

fun onDismissInfoClick() {
hideDialog()
}

private fun hideDialog() {
dialogState.update { AccountScreenDialogState.NoDialog }
}

fun onTransitionAnimationEnd() {
viewModelScope.launch { _enterTransitionEndAction.emit(Unit) }
}
Expand Down
3 changes: 3 additions & 0 deletions android/lib/resource/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -216,4 +216,7 @@
<string name="custom_port_dialog_remove">Remove custom port</string>
<string name="custom_port_dialog_valid_ranges">Valid ranges: %s</string>
<string name="custom_port_dialog_placeholder">Enter port</string>
<string name="device_name_info_part1">This is the name assigned to the device. Each device logged in on a Mullvad account gets a unique name that helps you identify it when you manage your devices in the app or on the website.</string>
<string name="device_name_info_part2">You can have up to 5 devices logged in on one Mullvad account.</string>
<string name="device_name_info_part3">If you log out, the device and the device name is removed. When you log back in again, the device will get a new name.</string>
</resources>

0 comments on commit 99c5881

Please sign in to comment.