diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/help/HelpSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/help/HelpSettingsFragment.kt index 3f673a5f29..4269efd5e4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/help/HelpSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/help/HelpSettingsFragment.kt @@ -1,70 +1,128 @@ +/* + * Copyright 2025 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + package org.thoughtcrime.securesms.components.settings.app.help -import androidx.navigation.Navigation +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment.Companion.CenterVertically +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource +import androidx.navigation.NavController +import androidx.navigation.fragment.findNavController +import org.signal.core.ui.compose.Dividers +import org.signal.core.ui.compose.Rows +import org.signal.core.ui.compose.Rows.TextAndLabel +import org.signal.core.ui.compose.Rows.defaultPadding +import org.signal.core.ui.compose.Scaffolds import org.thoughtcrime.securesms.BuildConfig import org.thoughtcrime.securesms.R -import org.thoughtcrime.securesms.components.settings.DSLConfiguration -import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment -import org.thoughtcrime.securesms.components.settings.DSLSettingsText -import org.thoughtcrime.securesms.components.settings.configure -import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter +import org.thoughtcrime.securesms.compose.ComposeFragment +import org.thoughtcrime.securesms.util.CommunicationActions import org.thoughtcrime.securesms.util.navigation.safeNavigate -class HelpSettingsFragment : DSLSettingsFragment(R.string.preferences__help) { +class HelpSettingsFragment : ComposeFragment() { - override fun bindAdapter(adapter: MappingAdapter) { - adapter.submitList(getConfiguration().toMappingModelList()) - } + @Composable + override fun FragmentContent() { + val navController: NavController = remember { findNavController() } - fun getConfiguration(): DSLConfiguration { - return configure { - externalLinkPref( - title = DSLSettingsText.from(R.string.HelpSettingsFragment__support_center), - linkId = R.string.support_center_url - ) + val context = LocalContext.current - clickPref( - title = DSLSettingsText.from(R.string.HelpSettingsFragment__contact_us), - onClick = { - Navigation.findNavController(requireView()).safeNavigate(R.id.action_helpSettingsFragment_to_helpFragment) + Scaffolds.Settings( + title = stringResource(R.string.preferences__help), + onNavigationClick = { navController.popBackStack() }, + navigationIconPainter = painterResource(id = R.drawable.ic_arrow_left_24), + navigationContentDescription = stringResource(id = R.string.Material3SearchToolbar__close) + ) { contentPadding -> + LazyColumn( + modifier = Modifier.padding(contentPadding) + ) { + item { + Rows.LinkRow( + text = stringResource(R.string.HelpSettingsFragment__support_center), + icon = ImageVector.vectorResource(R.drawable.symbol_open_20), + onClick = { + CommunicationActions.openBrowserLink(context, getString(R.string.support_center_url)) + } + ) } - ) - dividerPref() - - textPref( - title = DSLSettingsText.from(R.string.HelpSettingsFragment__version), - summary = DSLSettingsText.from(BuildConfig.VERSION_NAME) - ) - - clickPref( - title = DSLSettingsText.from(R.string.HelpSettingsFragment__debug_log), - onClick = { - Navigation.findNavController(requireView()).safeNavigate(R.id.action_helpSettingsFragment_to_submitDebugLogActivity) + item { + Rows.TextRow( + text = stringResource(id = R.string.HelpSettingsFragment__contact_us), + onClick = { + navController.safeNavigate(R.id.action_helpSettingsFragment_to_helpFragment) + } + ) } - ) - clickPref( - title = DSLSettingsText.from(R.string.HelpSettingsFragment__licenses), - onClick = { - Navigation.findNavController(requireView()).safeNavigate(R.id.action_helpSettingsFragment_to_licenseFragment) + item { + Dividers.Default() } - ) - externalLinkPref( - title = DSLSettingsText.from(R.string.HelpSettingsFragment__terms_amp_privacy_policy), - linkId = R.string.terms_and_privacy_policy_url - ) + item { + Rows.TextRow( + text = stringResource(R.string.HelpSettingsFragment__version), + label = BuildConfig.VERSION_NAME + ) + } - textPref( - summary = DSLSettingsText.from( - StringBuilder().apply { - append(getString(R.string.HelpFragment__copyright_signal_messenger)) - append("\n") - append(getString(R.string.HelpFragment__licenced_under_the_agplv3)) + item { + Rows.TextRow( + text = stringResource(id = R.string.HelpSettingsFragment__debug_log), + onClick = { + navController.safeNavigate(R.id.action_helpSettingsFragment_to_submitDebugLogActivity) + } + ) + } + + item { + Rows.TextRow( + text = stringResource(id = R.string.HelpSettingsFragment__licenses), + onClick = { + navController.safeNavigate(R.id.action_helpSettingsFragment_to_licenseFragment) + } + ) + } + + item { + Rows.LinkRow( + text = stringResource(R.string.HelpSettingsFragment__terms_amp_privacy_policy), + icon = ImageVector.vectorResource(R.drawable.symbol_open_20), + onClick = { + CommunicationActions.openBrowserLink(context, getString(R.string.terms_and_privacy_policy_url)) + } + ) + } + + item { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(defaultPadding()), + verticalAlignment = CenterVertically + ) { + TextAndLabel( + label = StringBuilder().apply { + append(getString(R.string.HelpFragment__copyright_signal_messenger)) + append("\n") + append(getString(R.string.HelpFragment__licenced_under_the_agplv3)) + }.toString() + ) } - ) - ) + } + } } } } diff --git a/core-ui/src/main/java/org/signal/core/ui/compose/Rows.kt b/core-ui/src/main/java/org/signal/core/ui/compose/Rows.kt index 5b3151d4b7..97de16b5ae 100644 --- a/core-ui/src/main/java/org/signal/core/ui/compose/Rows.kt +++ b/core-ui/src/main/java/org/signal/core/ui/compose/Rows.kt @@ -48,6 +48,45 @@ import org.signal.core.ui.compose.Rows.TextAndLabel object Rows { + /** + * Link row that positions [text] and optional [label] in a [TextAndLabel] to the side of an [icon] on the right. + */ + @OptIn(ExperimentalFoundationApi::class) + @Composable + fun LinkRow( + text: String, + onClick: (() -> Unit)? = null, + modifier: Modifier = Modifier, + label: String? = null, + textColor: Color = MaterialTheme.colorScheme.onSurface, + enabled: Boolean = true, + icon: ImageVector + ) { + Row( + modifier = modifier + .fillMaxWidth() + .clickable( + enabled = enabled, + onClick = onClick ?: {} + ) + .padding(defaultPadding()), + verticalAlignment = CenterVertically + ) { + TextAndLabel( + text = text, + label = label, + textColor = textColor, + enabled = enabled, + modifier = Modifier.padding(end = 16.dp) + ) + + Icon( + imageVector = icon, + contentDescription = null + ) + } + } + /** * A row consisting of a radio button and [text] and optional [label] in a [TextAndLabel]. */ @@ -293,7 +332,7 @@ object Rows { */ @Composable fun RowScope.TextAndLabel( - text: String, + text: String? = null, modifier: Modifier = Modifier, label: String? = null, enabled: Boolean = true, @@ -305,11 +344,13 @@ object Rows { .alpha(if (enabled) 1f else 0.4f) .weight(1f) ) { - Text( - text = text, - style = textStyle, - color = textColor - ) + if (text != null) { + Text( + text = text, + style = textStyle, + color = textColor + ) + } if (label != null) { Text(