diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java
index c890637ce7..472b7e159f 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java
@@ -34,6 +34,7 @@ import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.notifications.TurnOnNotificationsBottomSheet;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.profiles.manage.EditProfileActivity;
+import org.thoughtcrime.securesms.profiles.username.NewWaysToConnectDialogFragment;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.ServiceUtil;
@@ -340,13 +341,13 @@ public final class Megaphones {
public static @NonNull Megaphone buildSetUpYourUsernameMegaphone(@NonNull Context context) {
return new Megaphone.Builder(Event.SET_UP_YOUR_USERNAME, Megaphone.Style.BASIC)
- .setTitle(R.string.SetUpYourUsername__set_up_your_signal_username)
- .setBody(R.string.SetUpYourUsername__usernames_let_others)
- .setImage(R.drawable.usernames_64)
- .setActionButton(R.string.SetUpYourUsername__continue, (megaphone, controller) -> {
- controller.onMegaphoneNavigationRequested(EditProfileActivity.getIntentForUsernameEdit(context));
+ .setTitle(R.string.NewWaysToConnectDialogFragment__new_ways_to_connect)
+ .setBody(R.string.SetUpYourUsername__introducing_phone_number_privacy)
+ .setImage(R.drawable.usernames_megaphone)
+ .setActionButton(R.string.SetUpYourUsername__learn_more, (megaphone, controller) -> {
+ controller.onMegaphoneDialogFragmentRequested(new NewWaysToConnectDialogFragment());
})
- .setSecondaryButton(R.string.SetUpYourUsername__not_now, (megaphone, controller) -> {
+ .setSecondaryButton(R.string.SetUpYourUsername__dismiss, (megaphone, controller) -> {
controller.onMegaphoneCompleted(Event.SET_UP_YOUR_USERNAME);
})
.build();
@@ -360,7 +361,7 @@ public final class Megaphones {
.setActionButton(R.string.GrantFullScreenIntentPermission_megaphone_turn_on, (megaphone, controller) -> {
controller.onMegaphoneDialogFragmentRequested(TurnOnNotificationsBottomSheet.turnOnFullScreenIntentFragment(context));
})
- .setSecondaryButton(R.string.SetUpYourUsername__not_now, (megaphone, controller) -> {
+ .setSecondaryButton(R.string.GrantFullScreenIntentPermission_megaphone_not_now, (megaphone, controller) -> {
controller.onMegaphoneCompleted(Event.GRANT_FULL_SCREEN_INTENT);
})
.build();
diff --git a/app/src/main/java/org/thoughtcrime/securesms/profiles/username/NewWaysToConnectDialogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/profiles/username/NewWaysToConnectDialogFragment.kt
new file mode 100644
index 0000000000..ee5ed6c157
--- /dev/null
+++ b/app/src/main/java/org/thoughtcrime/securesms/profiles/username/NewWaysToConnectDialogFragment.kt
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2024 Signal Messenger, LLC
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+package org.thoughtcrime.securesms.profiles.username
+
+import android.os.Bundle
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.defaultMinSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.material3.MaterialTheme
+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.painter.Painter
+import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import org.signal.core.ui.Buttons
+import org.signal.core.ui.Previews
+import org.signal.core.ui.Scaffolds
+import org.thoughtcrime.securesms.R
+import org.thoughtcrime.securesms.compose.ComposeDialogFragment
+import org.thoughtcrime.securesms.profiles.manage.EditProfileActivity
+
+/**
+ * Displays an explanation page about usernames and gives the user
+ * the opportunity to set one up now.
+ */
+class NewWaysToConnectDialogFragment : ComposeDialogFragment() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setStyle(STYLE_NO_FRAME, R.style.Signal_DayNight_Dialog_FullScreen)
+ }
+
+ @Composable
+ override fun DialogContent() {
+ NewWaysToConnectDialogContent(
+ onSetUpUsernameClick = {
+ startActivity(EditProfileActivity.getIntentForUsernameEdit(requireContext()))
+ dismissAllowingStateLoss()
+ },
+ onNotNowClick = { dismissAllowingStateLoss() }
+ )
+ }
+}
+
+@Preview
+@Composable
+private fun PreviewNewWaysToConnectDialogContent() {
+ Previews.Preview {
+ NewWaysToConnectDialogContent(
+ onSetUpUsernameClick = {},
+ onNotNowClick = {}
+ )
+ }
+}
+
+@Composable
+private fun NewWaysToConnectDialogContent(
+ onSetUpUsernameClick: () -> Unit,
+ onNotNowClick: () -> Unit
+) {
+ Scaffolds.Settings(
+ title = "",
+ onNavigationClick = onNotNowClick,
+ navigationIconPainter = painterResource(id = R.drawable.symbol_x_24)
+ ) {
+ Column(modifier = Modifier.padding(it)) {
+ Text(
+ text = stringResource(id = R.string.NewWaysToConnectDialogFragment__new_ways_to_connect),
+ style = MaterialTheme.typography.headlineMedium,
+ textAlign = TextAlign.Center,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter))
+ .padding(top = 16.dp, bottom = 36.dp)
+ )
+
+ LazyColumn(modifier = Modifier.weight(1f)) {
+ item {
+ NewWaysToConnectRowItem(
+ title = stringResource(id = R.string.NewWaysToConnectDialogFragment__phone_number_privacy),
+ description = stringResource(id = R.string.NewWaysToConnectDialogFragment__your_phone_number_is_no_longer_shared),
+ image = painterResource(id = R.drawable.phone_48_color)
+ )
+ }
+
+ item {
+ NewWaysToConnectRowItem(
+ title = stringResource(id = R.string.NewWaysToConnectDialogFragment__usernames),
+ description = stringResource(id = R.string.NewWaysToConnectDialogFragment__people_can_now_message_you_using_your_optional_username),
+ image = painterResource(id = R.drawable.usernames_48_color)
+ )
+ }
+
+ item {
+ NewWaysToConnectRowItem(
+ title = stringResource(id = R.string.NewWaysToConnectDialogFragment__qr_codes_and_links),
+ description = stringResource(id = R.string.NewWaysToConnectDialogFragment__usernames_have_a_unique_qr_code),
+ image = painterResource(id = R.drawable.qr_codes_48_color)
+ )
+ }
+ }
+
+ Buttons.LargeTonal(
+ onClick = onSetUpUsernameClick,
+ modifier = Modifier
+ .padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter))
+ .padding(top = 36.dp)
+ .defaultMinSize(minWidth = 221.dp)
+ .align(alignment = Alignment.CenterHorizontally)
+ ) {
+ Text(
+ text = stringResource(id = R.string.NewWaysToConnectDialogFragment__set_up_your_username)
+ )
+ }
+
+ TextButton(
+ onClick = onNotNowClick,
+ modifier = Modifier
+ .padding(
+ horizontal = dimensionResource(id = R.dimen.core_ui__gutter),
+ vertical = 36.dp
+ )
+ .defaultMinSize(minWidth = 221.dp)
+ .align(alignment = Alignment.CenterHorizontally)
+ ) {
+ Text(text = stringResource(id = R.string.NewWaysToConnectDialogFragment__not_now))
+ }
+ }
+ }
+}
+
+@Preview
+@Composable
+private fun PreviewNewWaysToConnectRowItem() {
+ Previews.Preview {
+ NewWaysToConnectRowItem(
+ title = "Example Item",
+ description = "Sample text for the subtitle of the example",
+ image = painterResource(id = R.drawable.symbol_album_tilt_24)
+ )
+ }
+}
+
+@Composable
+private fun NewWaysToConnectRowItem(
+ title: String,
+ description: String,
+ image: Painter,
+ modifier: Modifier = Modifier
+) {
+ Row(
+ modifier = modifier
+ .padding(
+ horizontal = dimensionResource(id = R.dimen.core_ui__gutter)
+ )
+ .padding(
+ bottom = 40.dp
+ )
+ ) {
+ Image(
+ painter = image,
+ contentDescription = null,
+ modifier = Modifier
+ .padding(
+ start = 12.dp,
+ top = 4.dp,
+ end = 24.dp
+ )
+ .size(48.dp)
+ )
+ Column {
+ Text(
+ text = title,
+ style = MaterialTheme.typography.titleMedium
+ )
+ Text(
+ text = description,
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ modifier = Modifier.padding(top = 2.dp, end = 8.dp)
+ )
+ }
+ }
+}
diff --git a/app/src/main/res/drawable-night/phone_48_color.xml b/app/src/main/res/drawable-night/phone_48_color.xml
new file mode 100644
index 0000000000..df1c074f83
--- /dev/null
+++ b/app/src/main/res/drawable-night/phone_48_color.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable-night/qr_codes_48_color.xml b/app/src/main/res/drawable-night/qr_codes_48_color.xml
new file mode 100644
index 0000000000..0a655fd194
--- /dev/null
+++ b/app/src/main/res/drawable-night/qr_codes_48_color.xml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable-night/usernames_48_color.xml b/app/src/main/res/drawable-night/usernames_48_color.xml
new file mode 100644
index 0000000000..70175a9921
--- /dev/null
+++ b/app/src/main/res/drawable-night/usernames_48_color.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/phone_48_color.xml b/app/src/main/res/drawable/phone_48_color.xml
new file mode 100644
index 0000000000..68b0f26d48
--- /dev/null
+++ b/app/src/main/res/drawable/phone_48_color.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/qr_codes_48_color.xml b/app/src/main/res/drawable/qr_codes_48_color.xml
new file mode 100644
index 0000000000..95b4c5e308
--- /dev/null
+++ b/app/src/main/res/drawable/qr_codes_48_color.xml
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/usernames_48_color.xml b/app/src/main/res/drawable/usernames_48_color.xml
new file mode 100644
index 0000000000..95e8d5bf2f
--- /dev/null
+++ b/app/src/main/res/drawable/usernames_48_color.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/usernames_64.xml b/app/src/main/res/drawable/usernames_64.xml
deleted file mode 100644
index 9248c4a4a5..0000000000
--- a/app/src/main/res/drawable/usernames_64.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
diff --git a/app/src/main/res/drawable/usernames_megaphone.xml b/app/src/main/res/drawable/usernames_megaphone.xml
new file mode 100644
index 0000000000..0346c9df92
--- /dev/null
+++ b/app/src/main/res/drawable/usernames_megaphone.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e0cb89dba9..613d083f1c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -2427,6 +2427,26 @@
%1$s • Story
+
+
+ New ways to connect
+
+ Phone number privacy
+
+ Your phone number is no longer shared with chats. If your number is saved to a friend\'s contacts, they will still see it.
+
+ Usernames
+
+ People can now message you using your optional username so you don\'t have to give out your phone number. Usernames aren\'t visible on your profile.
+
+ QR codes and links
+
+ Usernames have a unique QR code and link you can share with friends to quickly start a chat with you.
+
+ Not now
+
+ Set up your username
+
Play video
Has a caption
@@ -6213,11 +6233,11 @@
Set up your Signal username
- Usernames let others message you without needing your phone number
+ Introducing phone number privacy, optional usernames and links.
- Not now
+ Dismiss
- Continue
+ Learn more
@@ -6562,6 +6582,8 @@
Never miss a call from your contacts and groups.
Turn on
+
+ Not now
Turn on full screen notifications
diff --git a/core-ui/src/main/java/org/signal/core/ui/Previews.kt b/core-ui/src/main/java/org/signal/core/ui/Previews.kt
new file mode 100644
index 0000000000..7394b3528c
--- /dev/null
+++ b/core-ui/src/main/java/org/signal/core/ui/Previews.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2024 Signal Messenger, LLC
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+package org.signal.core.ui
+
+import androidx.compose.material3.Surface
+import androidx.compose.runtime.Composable
+import org.signal.core.ui.theme.SignalTheme
+
+object Previews {
+ @Composable
+ fun Preview(
+ content: @Composable () -> Unit
+ ) {
+ SignalTheme {
+ Surface {
+ content()
+ }
+ }
+ }
+}