Spruce up the welcome and permission screens in regV5.

This commit is contained in:
Greyson Parrelli
2026-02-12 15:57:08 -05:00
committed by Alex Hart
parent a1862c3420
commit 7b362460e7
20 changed files with 322 additions and 160 deletions

View File

@@ -578,6 +578,7 @@ dependencies {
implementation(project(":core:models"))
implementation(project(":core:models-jvm"))
implementation(project(":feature:camera"))
implementation(project(":feature:registration"))
implementation(libs.androidx.fragment.ktx)
implementation(libs.androidx.appcompat) {

View File

@@ -25,7 +25,7 @@ import androidx.compose.ui.unit.dp
import org.signal.core.ui.compose.Buttons
import org.signal.core.ui.compose.DayNightPreviews
import org.signal.core.ui.compose.Previews
import org.thoughtcrime.securesms.R
import org.signal.registration.R
import org.thoughtcrime.securesms.registration.ui.shared.RegistrationScreen
/**

View File

@@ -2770,8 +2770,6 @@
<string name="RegistrationActivity_i_understand">I understand</string>
<string name="RegistrationActivity_play_services_error">Play Services Error</string>
<string name="RegistrationActivity_google_play_services_is_updating_or_unavailable">Google Play Services is updating or temporarily unavailable. Please try again.</string>
<!-- Non-English translations should use "Signal is a nonprofit" instead, dropping the 501c3 reference. -->
<string name="RegistrationActivity_terms_and_privacy">Signal is a 501c3 nonprofit\nTerms &amp; Privacy Policy</string>
<string name="RegistrationActivity_signal_needs_access_to_your_contacts_and_media_in_order_to_connect_with_friends">Signal needs the contacts and media permissions to help you connect with friends and send messages. Your contacts are uploaded using Signal\'s private contact discovery, which means they are end-to-end encrypted and never visible to the Signal service.</string>
<string name="RegistrationActivity_signal_needs_access_to_your_contacts_in_order_to_connect_with_friends">Signal needs the contacts permission to help you connect with friends. Your contacts are uploaded using Signal\'s private contact discovery, which means they are end-to-end encrypted and never visible to the Signal service.</string>
<string name="RegistrationActivity_rate_limited_to_service">You\'ve made too many attempts to register this number. Please try again later.</string>
@@ -2804,8 +2802,6 @@
<!-- Dialog button to cancel the pending action and return to the previous state. -->
<string name="RegistrationActivity_cancel">Cancel</string>
<string name="RegistrationActivity_next">Next</string>
<string name="RegistrationActivity_continue">Continue</string>
<string name="RegistrationActivity_take_privacy_with_you_be_yourself_in_every_message">Take privacy with you.\nBe yourself in every message.</string>
<!-- Title of registration screen when asking for the users phone number -->
<string name="RegistrationActivity_phone_number">Phone number</string>
<!-- Subtitle of registration screen when asking for the users phone number -->
@@ -4341,31 +4337,6 @@
<!-- Alert dialog button to update now -->
<string name="PaymentsHomeFragment__update_now">Update now</string>
<!-- GrantPermissionsFragment -->
<!-- Displayed as a text-only action button at the bottom start of the screen -->
<string name="GrantPermissionsFragment__not_now">Not now</string>
<!-- Displayed as an action button at the bottom end of the screen -->
<string name="GrantPermissionsFragment__next">Next</string>
<!-- Displayed as a title at the top of the screen -->
<string name="GrantPermissionsFragment__allow_permissions">Allow permissions</string>
<!-- Displayed as a subtitle at the top of the screen -->
<string name="GrantPermissionsFragment__to_help_you_message_people_you_know">To help you message people you know, Signal will request these permissions. </string>
<!-- Notifications permission row title -->
<string name="GrantPermissionsFragment__notifications">Notifications</string>
<!-- Notifications permission row description -->
<string name="GrantPermissionsFragment__get_notified_when">Get notified when new messages arrive.</string>
<!-- Contacts permission row title -->
<string name="GrantPermissionsFragment__contacts">Contacts</string>
<!-- Contacts permission row description -->
<string name="GrantPermissionsFragment__find_people_you_know">Find people you know. Your contacts are encrypted and not visible to the Signal service.</string>
<!-- Phone calls permission row title -->
<string name="GrantPermissionsFragment__phone_calls">Phone calls</string>
<!-- Phone calls permission row description -->
<string name="GrantPermissionsFragment__make_registering_easier">Make registering easier and enable additional calling features.</string>
<!-- Storage permission row title -->
<string name="GrantPermissionsFragment__storage">Storage</string>
<!-- Storage permission row description -->
<string name="GrantPermissionsFragment__send_photos_videos_and_files">Send photos, videos and files from your device.</string>
<!-- PaymentsSecuritySetupFragment -->
@@ -4828,8 +4799,6 @@
<string name="backup_enable_dialog__i_have_written_down_this_passphrase">I have written down this passphrase. Without it, I will be unable to restore a backup.</string>
<string name="registration_activity__restore_backup">Restore backup</string>
<string name="registration_activity__transfer_or_restore_account">Transfer or restore account</string>
<!-- Screen title for restoring or transfering account -->
<string name="registration_activity__restore_or_transfer">Restore or transfer</string>
<string name="registration_activity__transfer_account">Transfer account</string>
<string name="registration_activity__skip">Skip</string>
<!-- Text label button to skip restoring -->

View File

@@ -8,27 +8,31 @@
package org.signal.registration.screens.permissions
import android.Manifest
import androidx.compose.foundation.Image
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.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.foundation.layout.size
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.MultiplePermissionsState
import org.signal.core.ui.compose.Buttons
import org.signal.core.ui.compose.DayNightPreviews
import org.signal.core.ui.compose.Previews
import org.signal.registration.R
import org.signal.registration.screens.shared.RegistrationScreen
import org.signal.registration.screens.util.MockMultiplePermissionsState
import org.signal.registration.screens.util.MockPermissionsState
import org.signal.registration.test.TestTags
@@ -38,7 +42,7 @@ import org.signal.registration.test.TestTags
* Requests necessary runtime permissions before continuing.
*
* @param permissionsState The permissions state managed at the activity level.
* @param onEvent Callback for screen events.
* @param onProceed Callback invoked when the user proceeds (either granting or skipping).
* @param modifier Modifier to be applied to the root container.
*/
@Composable
@@ -47,102 +51,60 @@ fun PermissionsScreen(
onProceed: () -> Unit = {},
modifier: Modifier = Modifier
) {
Column(
modifier = modifier
.fillMaxSize()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
val permissions = permissionsState.permissions.map { it.permission }
RegistrationScreen(
title = stringResource(id = R.string.GrantPermissionsFragment__allow_permissions),
subtitle = stringResource(id = R.string.GrantPermissionsFragment__to_help_you_message_people_you_know),
modifier = modifier.testTag(TestTags.PERMISSIONS_SCREEN),
bottomContent = {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxWidth()
) {
TextButton(
modifier = Modifier
.weight(weight = 1f, fill = false)
.testTag(TestTags.PERMISSIONS_NOT_NOW_BUTTON),
onClick = onProceed
) {
Text(
text = stringResource(id = R.string.GrantPermissionsFragment__not_now)
)
}
Spacer(modifier = Modifier.size(24.dp))
Buttons.LargeTonal(
modifier = Modifier.testTag(TestTags.PERMISSIONS_NEXT_BUTTON),
onClick = {
permissionsState.launchMultiplePermissionRequest()
onProceed()
}
) {
Text(
text = stringResource(id = R.string.GrantPermissionsFragment__next)
)
}
}
}
) {
Text(
text = "Permissions",
style = MaterialTheme.typography.headlineLarge,
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "Signal needs the following permissions to provide the best experience:",
style = MaterialTheme.typography.bodyLarge,
textAlign = TextAlign.Center,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.height(24.dp))
PermissionsList(permissions = permissionsState.permissions.map { it.permission })
Spacer(modifier = Modifier.height(48.dp))
Button(
onClick = {
permissionsState.launchMultiplePermissionRequest()
onProceed()
},
modifier = Modifier
.fillMaxWidth()
.testTag(TestTags.PERMISSIONS_NEXT_BUTTON)
) {
Text("Next")
}
OutlinedButton(
onClick = { onProceed() },
modifier = Modifier
.fillMaxWidth()
.testTag(TestTags.PERMISSIONS_NOT_NOW_BUTTON)
) {
Text("Not now")
}
}
}
/**
* Displays a list of permission explanations.
*/
@Composable
private fun PermissionsList(
permissions: List<String>,
modifier: Modifier = Modifier
) {
Column(
modifier = modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
val permissionDescriptions = getPermissionDescriptions(permissions)
permissionDescriptions.forEach { description ->
PermissionItem(description = description)
}
}
}
/**
* Individual permission item with description.
*/
@Composable
private fun PermissionItem(
description: String,
modifier: Modifier = Modifier
) {
Text(
text = "$description",
style = MaterialTheme.typography.bodyMedium,
modifier = modifier.fillMaxWidth()
)
}
/**
* Converts permission names to user-friendly descriptions.
*/
private fun getPermissionDescriptions(permissions: List<String>): List<String> {
return buildList {
if (permissions.any { it == Manifest.permission.POST_NOTIFICATIONS }) {
add("Notifications - Stay updated with new messages")
PermissionRow(
imageVector = ImageVector.vectorResource(id = R.drawable.permission_notification),
title = stringResource(id = R.string.GrantPermissionsFragment__notifications),
subtitle = stringResource(id = R.string.GrantPermissionsFragment__get_notified_when)
)
}
if (permissions.any { it == Manifest.permission.READ_CONTACTS || it == Manifest.permission.WRITE_CONTACTS }) {
add("Contacts - Find friends who use Signal")
PermissionRow(
imageVector = ImageVector.vectorResource(id = R.drawable.permission_contact),
title = stringResource(id = R.string.GrantPermissionsFragment__contacts),
subtitle = stringResource(id = R.string.GrantPermissionsFragment__find_people_you_know)
)
}
if (permissions.any {
it == Manifest.permission.READ_EXTERNAL_STORAGE ||
it == Manifest.permission.WRITE_EXTERNAL_STORAGE ||
@@ -151,14 +113,54 @@ private fun getPermissionDescriptions(permissions: List<String>): List<String> {
it == Manifest.permission.READ_MEDIA_AUDIO
}
) {
add("Photos and media - Share images and videos")
PermissionRow(
imageVector = ImageVector.vectorResource(id = R.drawable.permission_file),
title = stringResource(id = R.string.GrantPermissionsFragment__storage),
subtitle = stringResource(id = R.string.GrantPermissionsFragment__send_photos_videos_and_files)
)
}
if (permissions.any { it == Manifest.permission.READ_PHONE_STATE || it == Manifest.permission.READ_PHONE_NUMBERS }) {
add("Phone - Verify your phone number")
PermissionRow(
imageVector = ImageVector.vectorResource(id = R.drawable.permission_phone),
title = stringResource(id = R.string.GrantPermissionsFragment__phone_calls),
subtitle = stringResource(id = R.string.GrantPermissionsFragment__make_registering_easier)
)
}
}
}
@Composable
private fun PermissionRow(
imageVector: ImageVector,
title: String,
subtitle: String
) {
Row(modifier = Modifier.padding(bottom = 32.dp)) {
Image(
imageVector = imageVector,
contentDescription = null,
modifier = Modifier.size(48.dp)
)
Spacer(modifier = Modifier.size(16.dp))
Column {
Text(
text = title,
style = MaterialTheme.typography.titleSmall
)
Text(
text = subtitle,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
Spacer(modifier = Modifier.size(32.dp))
}
}
@DayNightPreviews
@Composable
private fun PermissionsScreenPreview() {

View File

@@ -76,7 +76,7 @@ fun PhoneNumberScreen(
)
}
Box(modifier = modifier.fillMaxSize()) {
Box(modifier = modifier.fillMaxSize().testTag(TestTags.PHONE_NUMBER_SCREEN)) {
ScreenContent(state, onEvent)
if (state.showFullScreenSpinner) {

View File

@@ -0,0 +1,110 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.signal.registration.screens.shared
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import org.signal.core.ui.compose.DayNightPreviews
import org.signal.core.ui.compose.Previews
import org.signal.core.ui.compose.horizontalGutters
/**
* A base framework for rendering the various registration screens.
*/
@Composable
fun RegistrationScreen(
title: String,
subtitle: String,
bottomContent: @Composable (BoxScope.() -> Unit),
modifier: Modifier = Modifier,
mainContent: @Composable ColumnScope.() -> Unit
) {
Surface(modifier = modifier) {
Column(
verticalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
) {
val scrollState = rememberScrollState()
Column(
modifier = Modifier
.verticalScroll(scrollState)
.weight(weight = 1f, fill = false)
.padding(bottom = 16.dp)
.horizontalGutters()
) {
Spacer(Modifier.height(40.dp))
Text(
text = title,
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier.fillMaxWidth()
)
Text(
text = subtitle,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(top = 16.dp)
)
Spacer(modifier = Modifier.height(40.dp))
mainContent()
}
Surface(
shadowElevation = if (scrollState.canScrollForward) 8.dp else 0.dp,
modifier = Modifier.fillMaxWidth()
) {
Box(
modifier = Modifier
.padding(top = 8.dp, bottom = 24.dp)
.horizontalGutters()
) {
bottomContent()
}
}
}
}
}
@DayNightPreviews
@Composable
private fun RegistrationScreenPreview() {
Previews.Preview {
RegistrationScreen(
title = "Title",
subtitle = "Subtitle",
bottomContent = {
TextButton(onClick = {}) {
Text("Bottom Button")
}
}
) {
Text("Main content")
}
}
}

View File

@@ -7,19 +7,19 @@
package org.signal.registration.screens.welcome
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.SheetState
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@@ -29,14 +29,20 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.CoroutineScope
import org.signal.core.ui.compose.BottomSheets
import org.signal.core.ui.compose.Buttons
import org.signal.core.ui.compose.DayNightPreviews
import org.signal.core.ui.compose.Previews
import org.signal.core.ui.compose.dismissWithAnimation
import org.signal.core.ui.compose.theme.SignalTheme
import org.signal.registration.R
import org.signal.registration.test.TestTags
/**
@@ -53,34 +59,70 @@ fun WelcomeScreen(
Column(
modifier = modifier
.fillMaxSize()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
.testTag(TestTags.WELCOME_SCREEN),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Welcome to Signal",
style = MaterialTheme.typography.headlineLarge,
textAlign = TextAlign.Center
Image(
painter = painterResource(R.drawable.welcome),
contentDescription = null,
modifier = Modifier
.weight(1f)
.fillMaxWidth()
.padding(16.dp),
contentScale = ContentScale.Fit
)
Spacer(modifier = Modifier.height(48.dp))
Text(
text = stringResource(R.string.RegistrationActivity_take_privacy_with_you_be_yourself_in_every_message),
style = MaterialTheme.typography.headlineMedium,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(horizontal = 32.dp)
.testTag(TestTags.WELCOME_HEADLINE)
)
Button(
Spacer(modifier = Modifier.height(40.dp))
TextButton(
onClick = { /* Terms & Privacy link */ },
colors = ButtonDefaults.textButtonColors(
contentColor = MaterialTheme.colorScheme.onSurfaceVariant
)
) {
Text(
text = stringResource(R.string.RegistrationActivity_terms_and_privacy),
textAlign = TextAlign.Center
)
}
Spacer(modifier = Modifier.height(24.dp))
Buttons.LargeTonal(
onClick = { onEvent(WelcomeScreenEvents.Continue) },
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 32.dp)
.testTag(TestTags.WELCOME_GET_STARTED_BUTTON)
) {
Text("Get Started")
Text(stringResource(R.string.RegistrationActivity_continue))
}
OutlinedButton(
Spacer(modifier = Modifier.height(17.dp))
Buttons.LargeTonal(
onClick = { showBottomSheet = true },
colors = ButtonDefaults.filledTonalButtonColors(
containerColor = SignalTheme.colors.colorSurface2
),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 32.dp)
.testTag(TestTags.WELCOME_RESTORE_OR_TRANSFER_BUTTON)
) {
Text("Restore or transfer")
Text(stringResource(R.string.registration_activity__restore_or_transfer))
}
Spacer(modifier = Modifier.height(48.dp))
}
if (showBottomSheet) {
@@ -130,9 +172,9 @@ private fun RestoreOrTransferBottomSheetContent(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp, vertical = 16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(
Buttons.LargeTonal(
onClick = {
sheetState.dismissWithAnimation(scope) {
onEvent(WelcomeScreenEvents.HasOldPhone)
@@ -145,9 +187,10 @@ private fun RestoreOrTransferBottomSheetContent(
Text("I have my old phone")
}
Button(
Spacer(modifier = Modifier.height(12.dp))
Buttons.LargeTonal(
onClick = {
onEvent(WelcomeScreenEvents.DoesNotHaveOldPhone)
sheetState.dismissWithAnimation(scope) {
onEvent(WelcomeScreenEvents.DoesNotHaveOldPhone)
}

View File

@@ -11,16 +11,20 @@ package org.signal.registration.test
object TestTags {
// Welcome Screen
const val WELCOME_SCREEN = "welcome_screen"
const val WELCOME_HEADLINE = "welcome_headline"
const val WELCOME_GET_STARTED_BUTTON = "welcome_get_started_button"
const val WELCOME_RESTORE_OR_TRANSFER_BUTTON = "welcome_restore_or_transfer_button"
const val WELCOME_RESTORE_HAS_OLD_PHONE_BUTTON = "welcome_restore_has_old_phone_button"
const val WELCOME_RESTORE_NO_OLD_PHONE_BUTTON = "welcome_restore_no_old_phone_button"
// Permissions Screen
const val PERMISSIONS_SCREEN = "permissions_screen"
const val PERMISSIONS_NEXT_BUTTON = "permissions_next_button"
const val PERMISSIONS_NOT_NOW_BUTTON = "permissions_not_now_button"
// Phone Number Screen
const val PHONE_NUMBER_SCREEN = "phone_number_screen"
const val PHONE_NUMBER_COUNTRY_PICKER = "phone_number_country_picker"
const val PHONE_NUMBER_COUNTRY_CODE_FIELD = "phone_number_country_code_field"
const val PHONE_NUMBER_PHONE_FIELD = "phone_number_phone_field"

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="RegistrationActivity_take_privacy_with_you_be_yourself_in_every_message">Take privacy with you.\nBe yourself in every message.</string>
<!-- Non-English translations should use "Signal is a nonprofit" instead, dropping the 501c3 reference. -->
<string name="RegistrationActivity_terms_and_privacy">Signal is a 501c3 nonprofit\nTerms &amp; Privacy Policy</string>
<string name="RegistrationActivity_continue">Continue</string>
<!-- Screen title for restoring or transfering account -->
<string name="registration_activity__restore_or_transfer">Restore or transfer</string>
<!-- GrantPermissionsFragment -->
<!-- Displayed as a title at the top of the screen -->
<string name="GrantPermissionsFragment__allow_permissions">Allow permissions</string>
<!-- Displayed as a subtitle at the top of the screen -->
<string name="GrantPermissionsFragment__to_help_you_message_people_you_know">To help you message people you know, Signal will request these permissions. </string>
<!-- Displayed as a text-only action button at the bottom start of the screen -->
<string name="GrantPermissionsFragment__not_now">Not now</string>
<!-- Displayed as an action button at the bottom end of the screen -->
<string name="GrantPermissionsFragment__next">Next</string>
<!-- Notifications permission row title -->
<string name="GrantPermissionsFragment__notifications">Notifications</string>
<!-- Notifications permission row description -->
<string name="GrantPermissionsFragment__get_notified_when">Get notified when new messages arrive.</string>
<!-- Contacts permission row title -->
<string name="GrantPermissionsFragment__contacts">Contacts</string>
<!-- Contacts permission row description -->
<string name="GrantPermissionsFragment__find_people_you_know">Find people you know. Your contacts are encrypted and not visible to the Signal service.</string>
<!-- Phone calls permission row title -->
<string name="GrantPermissionsFragment__phone_calls">Phone calls</string>
<!-- Phone calls permission row description -->
<string name="GrantPermissionsFragment__make_registering_easier">Make registering easier and enable additional calling features.</string>
<!-- Storage permission row title -->
<string name="GrantPermissionsFragment__storage">Storage</string>
<!-- Storage permission row description -->
<string name="GrantPermissionsFragment__send_photos_videos_and_files">Send photos, videos and files from your device.</string>
</resources>

View File

@@ -10,7 +10,6 @@ import androidx.compose.ui.test.assertIsDisplayed
import androidx.test.core.app.ApplicationProvider
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.lifecycle.SavedStateHandle
import com.google.accompanist.permissions.ExperimentalPermissionsApi
@@ -67,7 +66,7 @@ class RegistrationNavigationTest {
}
// Then - verify Welcome screen is displayed
composeTestRule.onNodeWithText("Welcome to Signal").assertIsDisplayed()
composeTestRule.onNodeWithTag(TestTags.WELCOME_SCREEN).assertIsDisplayed()
}
@Test
@@ -89,7 +88,7 @@ class RegistrationNavigationTest {
composeTestRule.onNodeWithTag(TestTags.WELCOME_GET_STARTED_BUTTON).performClick()
// Then - verify Permissions screen is displayed
composeTestRule.onNodeWithText("Permissions").assertIsDisplayed()
composeTestRule.onNodeWithTag(TestTags.PERMISSIONS_SCREEN).assertIsDisplayed()
}
@Test
@@ -114,7 +113,7 @@ class RegistrationNavigationTest {
composeTestRule.onNodeWithTag(TestTags.PERMISSIONS_NEXT_BUTTON).performClick()
// Then - verify PhoneNumber screen is displayed
composeTestRule.onNodeWithText("You will receive a verification code").assertIsDisplayed()
composeTestRule.onNodeWithTag(TestTags.PHONE_NUMBER_SCREEN).assertIsDisplayed()
}
@Test
@@ -139,7 +138,7 @@ class RegistrationNavigationTest {
composeTestRule.onNodeWithTag(TestTags.PERMISSIONS_NOT_NOW_BUTTON).performClick()
// Then - verify PhoneNumber screen is displayed
composeTestRule.onNodeWithText("You will receive a verification code").assertIsDisplayed()
composeTestRule.onNodeWithTag(TestTags.PHONE_NUMBER_SCREEN).assertIsDisplayed()
}
// Note: Back navigation testing in Navigation 3 requires testing through
@@ -168,7 +167,7 @@ class RegistrationNavigationTest {
// Then - verify Permissions screen is displayed
// (After permissions, user would go to RestoreViaQr screen)
composeTestRule.onNodeWithText("Permissions").assertIsDisplayed()
composeTestRule.onNodeWithTag(TestTags.PERMISSIONS_SCREEN).assertIsDisplayed()
}
@Test

View File

@@ -10,7 +10,6 @@ import androidx.compose.ui.test.assertIsDisplayed
import androidx.test.core.app.ApplicationProvider
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import org.junit.Rule
import org.junit.Test
@@ -130,7 +129,7 @@ class WelcomeScreenTest {
}
// Then
composeTestRule.onNodeWithText("Welcome to Signal").assertIsDisplayed()
composeTestRule.onNodeWithTag(TestTags.WELCOME_HEADLINE).assertIsDisplayed()
composeTestRule.onNodeWithTag(TestTags.WELCOME_GET_STARTED_BUTTON).assertIsDisplayed()
composeTestRule.onNodeWithTag(TestTags.WELCOME_RESTORE_OR_TRANSFER_BUTTON).assertIsDisplayed()
}