diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 12d1a43375..2a0f832482 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -41,6 +41,10 @@
+
+
+
+
diff --git a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.java b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.java
index 0f1b75c70b..98b4e3a3c3 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.java
@@ -15,6 +15,7 @@ import androidx.lifecycle.ViewModelProvider;
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController;
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner;
+import org.thoughtcrime.securesms.conversationlist.RelinkDevicesReminderBottomSheetFragment;
import org.thoughtcrime.securesms.devicetransfer.olddevice.OldDeviceTransferLockedDialog;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.stories.Stories;
@@ -116,6 +117,11 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
OldDeviceTransferLockedDialog.show(getSupportFragmentManager());
}
+ if (SignalStore.misc().getShouldShowLinkedDevicesReminder()) {
+ SignalStore.misc().setShouldShowLinkedDevicesReminder(false);
+ RelinkDevicesReminderBottomSheetFragment.show(getSupportFragmentManager());
+ }
+
updateTabVisibility();
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsActivity.kt
index ea9e77a1d2..21eeace1be 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsActivity.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsActivity.kt
@@ -64,6 +64,7 @@ class AppSettingsActivity : DSLSettingsActivity(), DonationPaymentComponent {
EditNotificationProfileScheduleFragmentArgs.fromBundle(intent.getBundleExtra(START_ARGUMENTS)!!).profileId
)
StartLocation.PRIVACY -> AppSettingsFragmentDirections.actionDirectToPrivacy()
+ StartLocation.LINKED_DEVICES -> AppSettingsFragmentDirections.actionDirectToDevices()
}
}
@@ -184,6 +185,9 @@ class AppSettingsActivity : DSLSettingsActivity(), DonationPaymentComponent {
.putExtra(START_ARGUMENTS, arguments)
}
+ @JvmStatic
+ fun linkedDevices(context: Context): Intent = getIntentForStartLocation(context, StartLocation.LINKED_DEVICES)
+
private fun getIntentForStartLocation(context: Context, startLocation: StartLocation): Intent {
return Intent(context, AppSettingsActivity::class.java)
.putExtra(ARG_NAV_GRAPH, R.navigation.app_settings)
@@ -204,7 +208,8 @@ class AppSettingsActivity : DSLSettingsActivity(), DonationPaymentComponent {
NOTIFICATION_PROFILES(9),
CREATE_NOTIFICATION_PROFILE(10),
NOTIFICATION_PROFILE_DETAILS(11),
- PRIVACY(12);
+ PRIVACY(12),
+ LINKED_DEVICES(13);
companion object {
fun fromCode(code: Int?): StartLocation {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/RelinkDevicesReminderBottomSheetFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/RelinkDevicesReminderBottomSheetFragment.kt
new file mode 100644
index 0000000000..5a6b5dbaff
--- /dev/null
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/RelinkDevicesReminderBottomSheetFragment.kt
@@ -0,0 +1,90 @@
+package org.thoughtcrime.securesms.conversationlist
+
+import android.annotation.SuppressLint
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentSize
+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.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.fragment.app.FragmentManager
+import org.signal.core.ui.Buttons
+import org.thoughtcrime.securesms.R
+import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity
+import org.thoughtcrime.securesms.compose.ComposeBottomSheetDialogFragment
+import org.thoughtcrime.securesms.util.BottomSheetUtil
+
+/**
+ * Bottom Sheet Dialog to remind a user who has just re-registered to re-link their linked devices.
+ */
+class RelinkDevicesReminderBottomSheetFragment : ComposeBottomSheetDialogFragment() {
+
+ @Preview
+ @Composable
+ override fun SheetContent() {
+ return Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = Modifier
+ .padding(16.dp)
+ .wrapContentSize()
+ ) {
+ Handle()
+ Column(horizontalAlignment = Alignment.Start) {
+ Text(
+ text = stringResource(id = R.string.RelinkDevicesReminderFragment__relink_your_devices),
+ style = MaterialTheme.typography.headlineMedium,
+ modifier = Modifier
+ .padding(8.dp)
+ )
+ Text(
+ text = stringResource(R.string.RelinkDevicesReminderFragment__the_devices_you_added_were_unlinked),
+ style = MaterialTheme.typography.bodySmall,
+ modifier = Modifier.padding(8.dp)
+ )
+ }
+ Buttons.LargeTonal(
+ onClick = ::launchLinkedDevicesSettingsPage,
+ modifier = Modifier
+ .padding(8.dp)
+ .fillMaxWidth()
+ .align(Alignment.Start)
+ ) {
+ Text(
+ text = stringResource(R.string.RelinkDevicesReminderFragment__open_settings),
+ style = MaterialTheme.typography.labelLarge,
+ color = MaterialTheme.colorScheme.onPrimaryContainer
+ )
+ }
+ TextButton(
+ onClick = ::dismiss,
+ modifier = Modifier
+ .padding(start = 8.dp, end = 8.dp)
+ .wrapContentSize()
+ ) {
+ Text(
+ text = stringResource(R.string.RelinkDevicesReminderFragment__later),
+ color = MaterialTheme.colorScheme.primary
+ )
+ }
+ }
+ }
+
+ @SuppressLint("DiscouragedApi")
+ private fun launchLinkedDevicesSettingsPage() {
+ startActivity(AppSettingsActivity.linkedDevices(requireContext()))
+ }
+
+ companion object {
+ @JvmStatic
+ fun show(fragmentManager: FragmentManager) {
+ RelinkDevicesReminderBottomSheetFragment().show(fragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
+ }
+ }
+}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java
index 907b1698d1..7ff3c8d154 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java
@@ -5,10 +5,8 @@ import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.database.model.databaseprotos.PendingChangeNumberMetadata;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.TimeUnit;
public final class MiscellaneousValues extends SignalStoreValues {
@@ -30,6 +28,7 @@ public final class MiscellaneousValues extends SignalStoreValues {
private static final String LAST_FOREGROUND_TIME = "misc.last_foreground_time";
private static final String PNI_INITIALIZED_DEVICES = "misc.pni_initialized_devices";
private static final String SMS_PHASE_1_START_MS = "misc.sms_export.phase_1_start.3";
+ private static final String LINKED_DEVICES_REMINDER = "misc.linked_devices_reminder";
MiscellaneousValues(@NonNull KeyValueStore store) {
super(store);
@@ -242,4 +241,12 @@ public final class MiscellaneousValues extends SignalStoreValues {
long phase1StartMs = getLong(SMS_PHASE_1_START_MS, now);
return phase1StartMs + SmsExportPhase.PHASE_3.getDuration();
}
+
+ public void setShouldShowLinkedDevicesReminder(boolean value) {
+ putBoolean(LINKED_DEVICES_REMINDER, value);
+ }
+
+ public boolean getShouldShowLinkedDevicesReminder() {
+ return getBoolean(LINKED_DEVICES_REMINDER, false);
+ }
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/RegistrationCompleteFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/RegistrationCompleteFragment.kt
index 2307cefedf..8caf9277d7 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/RegistrationCompleteFragment.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/RegistrationCompleteFragment.kt
@@ -38,12 +38,16 @@ class RegistrationCompleteFragment : LoggingFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val activity = requireActivity()
+ val viewModel: RegistrationViewModel by viewModels(ownerProducer = { requireActivity() })
+
+ if (viewModel.isReregister) {
+ SignalStore.misc().shouldShowLinkedDevicesReminder = true
+ }
+
if (SignalStore.storageService().needsAccountRestore()) {
Log.i(TAG, "Performing pin restore.")
activity.startActivity(Intent(activity, PinRestoreActivity::class.java))
} else {
- val viewModel: RegistrationViewModel by viewModels(ownerProducer = { requireActivity() })
-
val isProfileNameEmpty = Recipient.self().profileName.isEmpty
val isAvatarEmpty = !AvatarHelper.hasAvatar(activity, Recipient.self().id)
val needsProfile = isProfileNameEmpty || isAvatarEmpty
diff --git a/app/src/main/res/navigation/app_settings.xml b/app/src/main/res/navigation/app_settings.xml
index 730c446d5b..01f714561e 100644
--- a/app/src/main/res/navigation/app_settings.xml
+++ b/app/src/main/res/navigation/app_settings.xml
@@ -486,6 +486,16 @@
app:popUpTo="@id/app_settings"
app:popUpToInclusive="true" />
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 10440ef349..d4794b712a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -543,6 +543,15 @@
+%1$d
+
+ Re-link your devices
+
+ The devices you added were unlinked when your device was unregistered. Go to Settings to re-link any devices.
+
+ Open settings
+
+ Later
+
Select members