diff options
| author | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2025-11-03 17:17:02 +0100 |
|---|---|---|
| committer | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2025-11-03 17:17:02 +0100 |
| commit | d0bf6fb86e8cdf561f3443cfdb8f53e5928749f9 (patch) | |
| tree | 488ac2ee820453fb751a40eca668aeaa4e9f5037 | |
| parent | 03261020fb1ee4599427fc2543100da0bf1293c3 (diff) | |
| parent | 27491ea74e763b908546313d01164169d9f06d53 (diff) | |
| download | mullvadvpn-d0bf6fb86e8cdf561f3443cfdb8f53e5928749f9.tar.xz mullvadvpn-d0bf6fb86e8cdf561f3443cfdb8f53e5928749f9.zip | |
Merge branch 'improve-include-account-id-droid-2274'
11 files changed, 246 insertions, 95 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CheckboxCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CheckboxCell.kt index 633b32e420..75b6182039 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CheckboxCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CheckboxCell.kt @@ -12,6 +12,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import net.mullvad.mullvadvpn.lib.theme.AppTheme @@ -31,6 +32,7 @@ internal fun CheckboxCell( checked: Boolean, enabled: Boolean = true, onCheckedChange: (Boolean) -> Unit, + textStyle: TextStyle = MaterialTheme.typography.bodyLarge, background: Color = MaterialTheme.colorScheme.surfaceContainerHighest, startPadding: Dp = Dimens.smallPadding, endPadding: Dp = Dimens.cellEndPadding, @@ -50,7 +52,7 @@ internal fun CheckboxCell( Text( text = title, - style = MaterialTheme.typography.bodyLarge, + style = textStyle, color = MaterialTheme.colorScheme.onSurface, modifier = Modifier.weight(1f) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/ReportProblemUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/ReportProblemUiStatePreviewParameterProvider.kt index f878ae9d37..b5a32dcb91 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/ReportProblemUiStatePreviewParameterProvider.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/ReportProblemUiStatePreviewParameterProvider.kt @@ -11,6 +11,12 @@ class ReportProblemUiStatePreviewParameterProvider : get() = sequenceOf( ReportProblemUiState(showIncludeAccountId = true), + ReportProblemUiState(showIncludeAccountId = true, includeAccountId = true), + ReportProblemUiState( + showIncludeAccountId = true, + includeAccountId = true, + showIncludeAccountWarningMessage = true, + ), ReportProblemUiState(sendingState = SendingReportUiState.Sending), ReportProblemUiState(sendingState = SendingReportUiState.Success("email@mail.com")), ReportProblemUiState( diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ReportProblemScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ReportProblemScreen.kt index ca06b04e74..28ed5e18c6 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ReportProblemScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ReportProblemScreen.kt @@ -1,5 +1,8 @@ package net.mullvad.mullvadvpn.compose.screen +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -10,26 +13,22 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.ErrorOutline import androidx.compose.material3.Icon -import androidx.compose.material3.LocalMinimumInteractiveComponentSize import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider 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.graphics.Color -import androidx.compose.ui.layout.onSizeChanged -import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle @@ -38,6 +37,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.withStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter @@ -55,24 +55,29 @@ import com.ramcosta.composedestinations.result.ResultRecipient import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.button.PrimaryButton import net.mullvad.mullvadvpn.compose.button.VariantButton +import net.mullvad.mullvadvpn.compose.cell.CheckboxCell import net.mullvad.mullvadvpn.compose.component.MullvadCircularProgressIndicatorLarge import net.mullvad.mullvadvpn.compose.component.NavigateBackIconButton import net.mullvad.mullvadvpn.compose.component.ScaffoldWithMediumTopBar +import net.mullvad.mullvadvpn.compose.extensions.createUriHook import net.mullvad.mullvadvpn.compose.preview.ReportProblemUiStatePreviewParameterProvider import net.mullvad.mullvadvpn.compose.textfield.mullvadWhiteTextFieldColors import net.mullvad.mullvadvpn.compose.transitions.SlideInFromRightTransition import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle import net.mullvad.mullvadvpn.compose.util.SecureScreenWhileInView +import net.mullvad.mullvadvpn.compose.util.clickableAnnotatedString import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.lib.theme.Dimens -import net.mullvad.mullvadvpn.lib.ui.designsystem.Checkbox +import net.mullvad.mullvadvpn.lib.theme.color.warning +import net.mullvad.mullvadvpn.lib.ui.component.ExpandChevron +import net.mullvad.mullvadvpn.util.appendHideNavOnPlayBuild import net.mullvad.mullvadvpn.viewmodel.ReportProblemSideEffect import net.mullvad.mullvadvpn.viewmodel.ReportProblemUiState import net.mullvad.mullvadvpn.viewmodel.ReportProblemViewModel import net.mullvad.mullvadvpn.viewmodel.SendingReportUiState import org.koin.androidx.compose.koinViewModel -@Preview("Default|Sending|Success|Error") +@Preview("Default|IncludeAccountNumber|ShowWarning|Sending|Success|Error") @Composable private fun PreviewReportProblemScreen( @PreviewParameter(ReportProblemUiStatePreviewParameterProvider::class) @@ -87,6 +92,7 @@ private fun PreviewReportProblemScreen( onEmailChanged = {}, onDescriptionChanged = {}, onIncludeAccountIdCheckChange = {}, + toggleShowIncludeAccountInformationWarningMessage = {}, onBackClick = {}, ) } @@ -126,6 +132,8 @@ fun ReportProblem( onEmailChanged = vm::updateEmail, onDescriptionChanged = vm::updateDescription, onIncludeAccountIdCheckChange = vm::onIncludeAccountIdCheckChange, + toggleShowIncludeAccountInformationWarningMessage = + vm::showIncludeAccountInformationWarningMessage, onBackClick = dropUnlessResumed { navigator.navigateUp() }, ) } @@ -139,6 +147,7 @@ private fun ReportProblemScreen( onEmailChanged: (String) -> Unit, onDescriptionChanged: (String) -> Unit, onIncludeAccountIdCheckChange: (Boolean) -> Unit, + toggleShowIncludeAccountInformationWarningMessage: (Boolean) -> Unit, onBackClick: () -> Unit, ) { @@ -172,99 +181,207 @@ private fun ReportProblemScreen( end = Dimens.sideMargin, bottom = Dimens.screenBottomMargin, ) - .height(IntrinsicSize.Max), + .height(IntrinsicSize.Max) + .animateContentSize(), verticalArrangement = Arrangement.spacedBy(Dimens.mediumPadding), ) { - Description( + InputContent( state = state, - onIncludeAccountIdCheckChange = onIncludeAccountIdCheckChange, - ) - - TextField( - modifier = Modifier.fillMaxWidth(), - value = state.email, - onValueChange = onEmailChanged, - maxLines = 1, - singleLine = true, - placeholder = { Text(text = stringResource(id = R.string.user_email_hint)) }, - colors = mullvadWhiteTextFieldColors(), - keyboardOptions = - KeyboardOptions( - autoCorrectEnabled = false, - keyboardType = KeyboardType.Email, - imeAction = ImeAction.Next, - ), - ) - - ProblemMessageTextField( - modifier = Modifier.weight(1f), - value = state.description, + onEmailChanged = onEmailChanged, onDescriptionChanged = onDescriptionChanged, + onIncludeAccountIdCheckChange = onIncludeAccountIdCheckChange, + toggleShowIncludeAccountInformationWarningMessage = + toggleShowIncludeAccountInformationWarningMessage, + onNavigateToViewLogs = onNavigateToViewLogs, + onSendReport = onSendReport, ) - - Column { - PrimaryButton( - onClick = onNavigateToViewLogs, - text = stringResource(id = R.string.view_logs), - ) - Spacer(modifier = Modifier.height(Dimens.buttonSpacing)) - VariantButton( - onClick = onSendReport, - isEnabled = state.description.isNotEmpty(), - text = stringResource(id = R.string.send), - ) - } } } } } @Composable -private fun Description( +private fun InputContent( state: ReportProblemUiState, + onEmailChanged: (String) -> Unit, + onDescriptionChanged: (String) -> Unit, onIncludeAccountIdCheckChange: (Boolean) -> Unit, + toggleShowIncludeAccountInformationWarningMessage: (Boolean) -> Unit, + onNavigateToViewLogs: () -> Unit, + onSendReport: () -> Unit, ) { + Description() + + TextField( + modifier = Modifier.fillMaxWidth(), + value = state.email, + onValueChange = onEmailChanged, + maxLines = 1, + singleLine = true, + placeholder = { Text(text = stringResource(id = R.string.user_email_hint)) }, + colors = mullvadWhiteTextFieldColors(), + keyboardOptions = + KeyboardOptions( + autoCorrectEnabled = false, + keyboardType = KeyboardType.Email, + imeAction = ImeAction.Next, + ), + ) + + ProblemMessageTextField(value = state.description, onDescriptionChanged = onDescriptionChanged) + + if (state.showIncludeAccountId) { + IncludeAccountInformationCheckBox( + includeAccountInformation = state.includeAccountId, + onIncludeAccountInformationCheckChange = onIncludeAccountIdCheckChange, + toggleShowIncludeAccountInformationWarningMessage = + toggleShowIncludeAccountInformationWarningMessage, + showIncludeAccountInformationWarningMessage = state.showIncludeAccountWarningMessage, + isPlayBuild = state.isPlayBuild, + ) + } + + Column { + PrimaryButton( + onClick = onNavigateToViewLogs, + text = stringResource(id = R.string.view_logs), + ) + Spacer(modifier = Modifier.height(Dimens.buttonSpacing)) + VariantButton( + onClick = onSendReport, + isEnabled = state.description.isNotEmpty(), + text = stringResource(id = R.string.send), + ) + } +} + +@Composable +private fun Description() { Column { Text( text = stringResource(id = R.string.problem_report_description), color = MaterialTheme.colorScheme.onSurfaceVariant, style = MaterialTheme.typography.labelLarge, ) - - if (state.showIncludeAccountId) { - IncludeAccountInformationCheckBox( - includeAccountInformation = state.includeAccountId, - onIncludeAccountInformationCheckChange = onIncludeAccountIdCheckChange, - ) - } } } @Composable private fun IncludeAccountInformationCheckBox( includeAccountInformation: Boolean, + showIncludeAccountInformationWarningMessage: Boolean, onIncludeAccountInformationCheckChange: (Boolean) -> Unit, + toggleShowIncludeAccountInformationWarningMessage: (Boolean) -> Unit, + isPlayBuild: Boolean, ) { - Row( - verticalAlignment = Alignment.CenterVertically, + val openPrivacyPolicy = + LocalUriHandler.current.createUriHook( + stringResource(R.string.privacy_policy_url).appendHideNavOnPlayBuild(isPlayBuild) + ) + Column( modifier = - Modifier.clickable { - onIncludeAccountInformationCheckChange(!includeAccountInformation) - } - .padding(vertical = Dimens.smallPadding) - .fillMaxWidth(), + Modifier.animateContentSize() + .border(width = Dp.Hairline, color = MaterialTheme.colorScheme.primary) + .padding(bottom = if (includeAccountInformation) Dimens.smallPadding else 0.dp) ) { - // To align the checkbox with the text - CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) { - Checkbox( - modifier = Modifier.padding(end = Dimens.smallPadding), - checked = includeAccountInformation, - onCheckedChange = onIncludeAccountInformationCheckChange, + CheckboxCell( + title = stringResource(R.string.include_account_token_checkbox_text), + checked = includeAccountInformation, + background = MaterialTheme.colorScheme.surface, + startPadding = 0.dp, + textStyle = MaterialTheme.typography.bodyMedium, + onCheckedChange = onIncludeAccountInformationCheckChange, + ) + if (includeAccountInformation) { + AccountInformationWarning( + showIncludeAccountInformationWarningMessage = + showIncludeAccountInformationWarningMessage, + toggleShowIncludeAccountInformationWarningMessage = + toggleShowIncludeAccountInformationWarningMessage, + openPrivacyPolicy = openPrivacyPolicy, + ) + } + } +} + +@Composable +private fun AccountInformationWarning( + showIncludeAccountInformationWarningMessage: Boolean, + toggleShowIncludeAccountInformationWarningMessage: (Boolean) -> Unit, + openPrivacyPolicy: () -> Unit, +) { + Column( + modifier = + Modifier.padding(horizontal = Dimens.tinyPadding) + .background(MaterialTheme.colorScheme.surfaceDim) + .animateContentSize() + ) { + Row( + modifier = + Modifier.fillMaxWidth() + .clickable( + onClick = { + toggleShowIncludeAccountInformationWarningMessage( + !showIncludeAccountInformationWarningMessage + ) + } + ) + .padding( + top = Dimens.smallPadding, + start = Dimens.smallPadding, + end = Dimens.smallPadding, + bottom = + if (showIncludeAccountInformationWarningMessage) { + Dimens.tinyPadding + } else { + Dimens.smallPadding + }, + ) + ) { + Icon( + imageVector = Icons.Outlined.ErrorOutline, + contentDescription = stringResource(R.string.include_account_token_warning_title), + tint = MaterialTheme.colorScheme.warning, ) Text( - text = stringResource(R.string.include_account_token_checkbox_text), - color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = + Modifier.padding(horizontal = Dimens.smallPadding) + .weight(1f) + .align(Alignment.CenterVertically), style = MaterialTheme.typography.labelLarge, + text = stringResource(R.string.include_account_token_warning_title), + ) + ExpandChevron(isExpanded = showIncludeAccountInformationWarningMessage) + } + if (showIncludeAccountInformationWarningMessage) { + Text( + modifier = + Modifier.padding(horizontal = Dimens.smallPadding) + .padding(bottom = Dimens.smallPadding), + style = MaterialTheme.typography.bodySmall, + text = + clickableAnnotatedString( + text = + buildString { + appendLine( + stringResource( + R.string.include_account_token_warning_message_first + ) + ) + append( + stringResource( + R.string.include_account_token_warning_message_second + ) + ) + }, + argument = stringResource(R.string.privacy_policy_lower_case), + linkStyle = + SpanStyle( + color = MaterialTheme.colorScheme.onSurface, + textDecoration = TextDecoration.Underline, + ), + onClick = { openPrivacyPolicy() }, + ), ) } } @@ -276,23 +393,12 @@ private fun ProblemMessageTextField( value: String, onDescriptionChanged: (String) -> Unit, ) { - // Stores the height of the text field after the initial onSizeChanged callback is called. - // This size will be calculated as a weight set from the parent composable. - var textFieldHeight by remember { mutableStateOf(0.dp) } - - val localDensity = LocalDensity.current TextField( modifier = modifier .fillMaxWidth() - // Prevents the text field from shrinking when the IME is shown. - .defaultMinSize(minHeight = if (textFieldHeight > 0.dp) textFieldHeight else 180.dp) - // Prevents the text field from growing to large when the message is long. - .heightIn(max = if (textFieldHeight > 0.dp) textFieldHeight else Dp.Unspecified) - .onSizeChanged { size -> - textFieldHeight = with(localDensity) { size.height.toDp() } - }, + .defaultMinSize(minHeight = Dimens.problemReportTextFieldMinHeight), value = value, onValueChange = onDescriptionChanged, placeholder = { Text(stringResource(R.string.user_message_hint)) }, @@ -356,7 +462,7 @@ private fun ColumnScope.SentContent(sendingState: SendingReportUiState.Success) val emailStart = emailTemplate.indexOf('%') buildAnnotatedString { - append(emailTemplate.substring(0, emailStart)) + append(emailTemplate.take(emailStart)) withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { append(sendingState.email) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/ClickableString.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/ClickableString.kt index bcf4e1b76c..97ff867010 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/ClickableString.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/ClickableString.kt @@ -24,12 +24,7 @@ fun clickableAnnotatedString( link = LinkAnnotation.Clickable( tag = argument, - linkInteractionListener = - object : LinkInteractionListener { - override fun onClick(link: LinkAnnotation) { - onClick(argument) - } - }, + linkInteractionListener = LinkInteractionListener { onClick(argument) }, ), block = { withStyle(style = linkStyle) { append(argument) } }, ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt index 9c02c9011f..622d4f7814 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt @@ -270,7 +270,14 @@ val uiModule = module { viewModel { VoucherDialogViewModel(get()) } viewModel { VpnSettingsViewModel(get(), get(), get(), get(), get(), get()) } viewModel { WelcomeViewModel(get(), get(), get(), get(), isPlayBuild = IS_PLAY_BUILD) } - viewModel { ReportProblemViewModel(get(), get(), get()) } + viewModel { + ReportProblemViewModel( + mullvadProblemReporter = get(), + problemReportRepository = get(), + accountRepository = get(), + isPlayBuild = IS_PLAY_BUILD, + ) + } viewModel { ViewLogsViewModel(get()) } viewModel { OutOfTimeViewModel(get(), get(), get(), get(), get(), isPlayBuild = IS_PLAY_BUILD) } viewModel { FilterViewModel(get(), get()) } 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 f846303c09..4b2726c945 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 @@ -26,6 +26,8 @@ data class ReportProblemUiState( val description: String = "", val showIncludeAccountId: Boolean = false, val includeAccountId: Boolean = false, + val showIncludeAccountWarningMessage: Boolean = false, + val isPlayBuild: Boolean = false, ) sealed interface SendingReportUiState { @@ -44,30 +46,41 @@ class ReportProblemViewModel( private val mullvadProblemReporter: MullvadProblemReport, private val problemReportRepository: ProblemReportRepository, accountRepository: AccountRepository, + private val isPlayBuild: Boolean, ) : ViewModel() { private val sendingState: MutableStateFlow<SendingReportUiState?> = MutableStateFlow(null) private val includeAccountIdState: MutableStateFlow<Boolean> = MutableStateFlow(false) + private val showIncludeAccountWarningMessage: MutableStateFlow<Boolean> = + MutableStateFlow(false) val uiState = combine( sendingState, includeAccountIdState, + showIncludeAccountWarningMessage, problemReportRepository.problemReport, accountRepository.accountData, - ) { sendingState, includeAccountToken, userReport, accountData -> + ) { + sendingState, + includeAccountToken, + showIncludeAccountWarningMessage, + userReport, + accountData -> ReportProblemUiState( sendingState = sendingState, email = userReport.email ?: "", description = userReport.description, showIncludeAccountId = accountData != null, includeAccountId = includeAccountToken, + showIncludeAccountWarningMessage = showIncludeAccountWarningMessage, + isPlayBuild = isPlayBuild, ) } .stateIn( viewModelScope, SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT), - ReportProblemUiState(), + ReportProblemUiState(isPlayBuild = isPlayBuild), ) private val _uiSideEffect = Channel<ReportProblemSideEffect>() @@ -118,6 +131,10 @@ class ReportProblemViewModel( includeAccountIdState.tryEmit(checked) } + fun showIncludeAccountInformationWarningMessage(show: Boolean) { + showIncludeAccountWarningMessage.tryEmit(show) + } + private fun shouldShowConfirmNoEmail(userEmail: String?): Boolean = userEmail.isNullOrEmpty() && uiState.value.sendingState !is SendingReportUiState diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModelTest.kt index ead918124e..1fc1a49422 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ReportProblemViewModelTest.kt @@ -45,6 +45,7 @@ class ReportProblemViewModelTest { mockMullvadProblemReport, mockProblemReportRepository, mockAccountRepository, + isPlayBuild = false, ) } diff --git a/android/lib/resource/src/main/res/values/strings.xml b/android/lib/resource/src/main/res/values/strings.xml index 147559f0c2..68d04343d8 100644 --- a/android/lib/resource/src/main/res/values/strings.xml +++ b/android/lib/resource/src/main/res/values/strings.xml @@ -462,7 +462,11 @@ <string name="enable_all_methods">Enable all & retry</string> <string name="send_email">Send email</string> <string name="no_email_app_available">No email app available on the device</string> - <string name="include_account_token_checkbox_text">This is a question about account or payments (include account information)</string> + <string name="include_account_token_checkbox_text">Include my account token for faster help with payment or account related issues</string> <string name="no_matching_relay_entry">No entry server match your settings, try changing server or other settings.</string> <string name="no_matching_relay_exit">No exit server match your settings, try changing server or other settings.</string> + <string name="include_account_token_warning_title">This impacts your anonymity</string> + <string name="include_account_token_warning_message_first">By attaching your account token it links this report to your account, which helps us resolve your issue quicker. All reports are automatically deleted after a period of time.</string> + <string name="include_account_token_warning_message_second">For details, please see our %s.</string> + <string name="privacy_policy_lower_case">privacy policy</string> </resources> diff --git a/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt b/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt index 8f4426a907..6a07682d83 100644 --- a/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt +++ b/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt @@ -50,6 +50,7 @@ data class Dimensions( val obfuscationNavigationBoxWidth: Dp = 56.dp, val outLineButtonBorderWidth: Dp = 1.dp, val privacyPolicyIconSize: Dp = 16.dp, + val problemReportTextFieldMinHeight: Dp = 220.dp, val reconnectButtonMinInteractiveComponentSize: Dp = 40.dp, val relayCircleSize: Dp = 16.dp, val relayCirclePadding: Dp = 8.dp, diff --git a/desktop/packages/mullvad-vpn/locales/messages.pot b/desktop/packages/mullvad-vpn/locales/messages.pot index 580b9ee459..c4269f6233 100644 --- a/desktop/packages/mullvad-vpn/locales/messages.pot +++ b/desktop/packages/mullvad-vpn/locales/messages.pot @@ -3022,6 +3022,9 @@ msgstr "" msgid "Blocking..." msgstr "" +msgid "By attaching your account token it links this report to your account, which helps us resolve your issue quicker. All reports are automatically deleted after a period of time." +msgstr "" + msgid "Can't connect?" msgstr "" @@ -3172,6 +3175,9 @@ msgstr "" msgid "File" msgstr "" +msgid "For details, please see our %s." +msgstr "" + msgid "For the VPN to connect automatically on device startup, the app must have VPN permissions. You can grant these by clicking “Connect” in the map view and selecting “OK” if prompted. Additionally, ensure the app is installed on the internal storage by checking the storage information in the app details in system settings." msgstr "" @@ -3217,6 +3223,9 @@ msgstr "" msgid "In-tunnel IPv6" msgstr "" +msgid "Include my account token for faster help with payment or account related issues" +msgstr "" + msgid "Invalid or missing value \"%1$s\"" msgstr "" @@ -3439,7 +3448,7 @@ msgstr "" msgid "This field is required" msgstr "" -msgid "This is a question about account or payments (include account information)" +msgid "This impacts your anonymity" msgstr "" msgid "This is already set as current" @@ -3577,6 +3586,9 @@ msgstr "" msgid "login" msgstr "" +msgid "privacy policy" +msgstr "" + msgid "read more here" msgstr "" diff --git a/mullvad-problem-report/src/lib.rs b/mullvad-problem-report/src/lib.rs index 730b06ba0a..61c83e7193 100644 --- a/mullvad-problem-report/src/lib.rs +++ b/mullvad-problem-report/src/lib.rs @@ -321,7 +321,7 @@ async fn send_problem_report_inner( let message: String = match account_token { Some(account_token) => { - format!("{user_message}\nAccountToken: {account_token}") + format!("{user_message}\naccount-token: {account_token}") } None => user_message.to_string(), }; |
