mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-08-04 20:34:14 +01:00
Improve UX around max linked devices.
This commit is contained in:
committed by
Michelle Tang
parent
07500f62ab
commit
0b6cd03115
@@ -72,6 +72,7 @@ class EditDeviceNameFragment : ComposeFragment() {
|
||||
LinkDeviceSettingsState.OneTimeEvent.ToastNetworkFailed,
|
||||
is LinkDeviceSettingsState.OneTimeEvent.ToastUnlinked,
|
||||
LinkDeviceSettingsState.OneTimeEvent.LaunchEmail,
|
||||
LinkDeviceSettingsState.OneTimeEvent.SnackbarDeviceLimitReached,
|
||||
LinkDeviceSettingsState.OneTimeEvent.SnackbarLinkCancelled -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import androidx.compose.foundation.text.ClickableText
|
||||
import androidx.compose.foundation.text.InlineTextContent
|
||||
import androidx.compose.foundation.text.appendInlineContent
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
@@ -74,6 +75,7 @@ import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.linkdevice.LinkDeviceSettingsState.DialogState
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions
|
||||
import org.thoughtcrime.securesms.util.DateUtils
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
import org.thoughtcrime.securesms.util.SupportEmailUtil
|
||||
import org.thoughtcrime.securesms.util.navigation.safeNavigate
|
||||
import org.signal.core.ui.R as CoreUiR
|
||||
@@ -129,6 +131,7 @@ class LinkDeviceFragment : ComposeFragment() {
|
||||
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||
val navController: NavController by remember { mutableStateOf(findNavController()) }
|
||||
val context = LocalContext.current
|
||||
val atDeviceLimit = state.devices.size >= RemoteConfig.maxLinkedDevices
|
||||
|
||||
LaunchedEffect(state.dialogState) {
|
||||
when (state.dialogState) {
|
||||
@@ -158,6 +161,9 @@ class LinkDeviceFragment : ComposeFragment() {
|
||||
LinkDeviceSettingsState.OneTimeEvent.SnackbarLinkCancelled -> {
|
||||
Snackbar.make(requireView(), getString(R.string.LinkDeviceFragment__linking_cancelled), Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
LinkDeviceSettingsState.OneTimeEvent.SnackbarDeviceLimitReached -> {
|
||||
Snackbar.make(requireView(), getString(R.string.LinkDeviceFragment__you_can_only_have_d_linked_devices, RemoteConfig.maxLinkedDevices), Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
LinkDeviceSettingsState.OneTimeEvent.ToastNetworkFailed -> {
|
||||
Toast.makeText(requireContext(), getString(R.string.DeviceListActivity_network_failed), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
@@ -195,10 +201,15 @@ class LinkDeviceFragment : ComposeFragment() {
|
||||
DeviceListScreen(
|
||||
state = state,
|
||||
modifier = Modifier.padding(contentPadding),
|
||||
atDeviceLimit = atDeviceLimit,
|
||||
onLearnMoreClicked = { navController.safeNavigate(R.id.action_linkDeviceFragment_to_linkDeviceLearnMoreBottomSheet) },
|
||||
onLinkNewDeviceClicked = {
|
||||
viewModel.stopExistingPolling()
|
||||
navController.navigateToQrScannerIfAuthed()
|
||||
if (atDeviceLimit) {
|
||||
viewModel.onDeviceLimitReached()
|
||||
} else {
|
||||
viewModel.stopExistingPolling()
|
||||
navController.navigateToQrScannerIfAuthed()
|
||||
}
|
||||
},
|
||||
onDeviceSelectedForRemoval = { device -> viewModel.setDeviceToRemove(device) },
|
||||
onDeviceRemovalConfirmed = { device -> viewModel.removeDevice(device) },
|
||||
@@ -272,6 +283,7 @@ class LinkDeviceFragment : ComposeFragment() {
|
||||
fun DeviceListScreen(
|
||||
state: LinkDeviceSettingsState,
|
||||
modifier: Modifier = Modifier,
|
||||
atDeviceLimit: Boolean = false,
|
||||
onLearnMoreClicked: () -> Unit = {},
|
||||
onLinkNewDeviceClicked: () -> Unit = {},
|
||||
onDeviceSelectedForRemoval: (Device?) -> Unit = {},
|
||||
@@ -411,8 +423,17 @@ fun DeviceListScreen(
|
||||
|
||||
Spacer(modifier = Modifier.size(20.dp))
|
||||
|
||||
val linkButtonColors = ButtonDefaults.filledTonalButtonColors()
|
||||
Buttons.LargeTonal(
|
||||
onClick = onLinkNewDeviceClicked,
|
||||
colors = if (atDeviceLimit) {
|
||||
linkButtonColors.copy(
|
||||
containerColor = linkButtonColors.disabledContainerColor,
|
||||
contentColor = linkButtonColors.disabledContentColor
|
||||
)
|
||||
} else {
|
||||
linkButtonColors
|
||||
},
|
||||
modifier = Modifier
|
||||
.defaultMinSize(300.dp)
|
||||
.padding(bottom = 8.dp)
|
||||
|
||||
@@ -41,6 +41,7 @@ data class LinkDeviceSettingsState(
|
||||
data class ToastUnlinked(val name: String) : OneTimeEvent
|
||||
data class ToastLinked(val name: String) : OneTimeEvent
|
||||
data object SnackbarLinkCancelled : OneTimeEvent
|
||||
data object SnackbarDeviceLimitReached : OneTimeEvent
|
||||
data object SnackbarNameChangeSuccess : OneTimeEvent
|
||||
data object SnackbarNameChangeFailure : OneTimeEvent
|
||||
data object ShowFinishedSheet : OneTimeEvent
|
||||
|
||||
@@ -152,6 +152,10 @@ class LinkDeviceViewModel : ViewModel() {
|
||||
pollJob?.cancel()
|
||||
}
|
||||
|
||||
fun onDeviceLimitReached() {
|
||||
_state.update { it.copy(oneTimeEvent = OneTimeEvent.SnackbarDeviceLimitReached) }
|
||||
}
|
||||
|
||||
fun markQrEducationSheetSeen() {
|
||||
SignalStore.uiHints.markHasSeenLinkDeviceQrEducationSheet()
|
||||
_state.update {
|
||||
|
||||
@@ -605,6 +605,15 @@ object RemoteConfig {
|
||||
hotSwappable = true
|
||||
)
|
||||
|
||||
/** The maximum number of linked devices a user can have. */
|
||||
@JvmStatic
|
||||
@get:JvmName("maxLinkedDevices")
|
||||
val maxLinkedDevices: Int by remoteInt(
|
||||
key = "global.maxLinkedDevices",
|
||||
defaultValue = 5,
|
||||
hotSwappable = true
|
||||
)
|
||||
|
||||
/** The maximum number of grapheme */
|
||||
@JvmStatic
|
||||
val maxGroupNameGraphemeLength: Int by remoteValue(
|
||||
|
||||
@@ -1122,6 +1122,8 @@
|
||||
<string name="LinkDeviceFragment__edit_name">Edit name</string>
|
||||
<!-- Toast shown when the process of linking a device has been cancelled -->
|
||||
<string name="LinkDeviceFragment__linking_cancelled">Linking cancelled</string>
|
||||
<!-- Snackbar shown when the user tries to link a new device but has already reached the maximum number of linked devices. Placeholder is the maximum count. -->
|
||||
<string name="LinkDeviceFragment__you_can_only_have_d_linked_devices">You can only have %1$d linked devices.</string>
|
||||
<!-- Message shown in progress dialog telling users to avoid closing the app while messages are being synced -->
|
||||
<string name="LinkDeviceFragment__do_not_close">Do not close app</string>
|
||||
<!-- Dialog title shown when a device is unlinked -->
|
||||
|
||||
Reference in New Issue
Block a user