Add PNP settings.
This commit is contained in:
parent
f3693c966a
commit
45a04423b0
15 changed files with 425 additions and 167 deletions
|
@ -1,21 +1,16 @@
|
|||
package org.thoughtcrime.securesms.components.settings.app.privacy
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.style.TextAppearanceSpan
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.biometric.BiometricManager
|
||||
import androidx.biometric.BiometricPrompt
|
||||
import androidx.biometric.BiometricPrompt.PromptInfo
|
||||
|
@ -41,8 +36,6 @@ import org.thoughtcrime.securesms.components.settings.PreferenceModel
|
|||
import org.thoughtcrime.securesms.components.settings.PreferenceViewHolder
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues.PhoneNumberListingMode
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions
|
||||
import org.thoughtcrime.securesms.util.ConversationUtil
|
||||
|
@ -126,6 +119,19 @@ class PrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__privac
|
|||
|
||||
private fun getConfiguration(state: PrivacySettingsState): DSLConfiguration {
|
||||
return configure {
|
||||
if (FeatureFlags.phoneNumberPrivacy()) {
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_app_protection__phone_number),
|
||||
summary = DSLSettingsText.from(R.string.preferences_app_protection__choose_who_can_see),
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView())
|
||||
.safeNavigate(R.id.action_privacySettingsFragment_to_phoneNumberPrivacySettingsFragment)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
}
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.PrivacySettingsFragment__blocked),
|
||||
summary = DSLSettingsText.from(getString(R.string.PrivacySettingsFragment__d_contacts, state.blockedCount)),
|
||||
|
@ -137,28 +143,6 @@ class PrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__privac
|
|||
|
||||
dividerPref()
|
||||
|
||||
if (FeatureFlags.phoneNumberPrivacy()) {
|
||||
sectionHeaderPref(R.string.preferences_app_protection__who_can)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_app_protection__see_my_phone_number),
|
||||
summary = DSLSettingsText.from(getWhoCanSeeMyPhoneNumberSummary(state.seeMyPhoneNumber)),
|
||||
onClick = {
|
||||
onSeeMyPhoneNumberClicked(state.seeMyPhoneNumber)
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_app_protection__find_me_by_phone_number),
|
||||
summary = DSLSettingsText.from(getWhoCanFindMeByPhoneNumberSummary(state.findMeByPhoneNumber)),
|
||||
onClick = {
|
||||
onFindMyPhoneNumberClicked(state.findMeByPhoneNumber)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
}
|
||||
|
||||
sectionHeaderPref(R.string.PrivacySettingsFragment__messaging)
|
||||
|
||||
switchPref(
|
||||
|
@ -389,117 +373,6 @@ class PrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__privac
|
|||
}
|
||||
}
|
||||
|
||||
@StringRes
|
||||
private fun getWhoCanSeeMyPhoneNumberSummary(phoneNumberSharingMode: PhoneNumberPrivacyValues.PhoneNumberSharingMode): Int {
|
||||
return when (phoneNumberSharingMode) {
|
||||
PhoneNumberPrivacyValues.PhoneNumberSharingMode.EVERYONE -> R.string.PhoneNumberPrivacy_everyone
|
||||
PhoneNumberPrivacyValues.PhoneNumberSharingMode.CONTACTS -> R.string.PhoneNumberPrivacy_my_contacts
|
||||
PhoneNumberPrivacyValues.PhoneNumberSharingMode.NOBODY -> R.string.PhoneNumberPrivacy_nobody
|
||||
}
|
||||
}
|
||||
|
||||
@StringRes
|
||||
private fun getWhoCanFindMeByPhoneNumberSummary(phoneNumberListingMode: PhoneNumberListingMode): Int {
|
||||
return when (phoneNumberListingMode) {
|
||||
PhoneNumberListingMode.LISTED -> R.string.PhoneNumberPrivacy_everyone
|
||||
PhoneNumberListingMode.UNLISTED -> R.string.PhoneNumberPrivacy_nobody
|
||||
}
|
||||
}
|
||||
|
||||
private fun onSeeMyPhoneNumberClicked(phoneNumberSharingMode: PhoneNumberPrivacyValues.PhoneNumberSharingMode) {
|
||||
val value = arrayOf(phoneNumberSharingMode)
|
||||
val items = items(requireContext())
|
||||
val modes: List<PhoneNumberPrivacyValues.PhoneNumberSharingMode> = ArrayList(items.keys)
|
||||
val modeStrings = items.values.toTypedArray()
|
||||
val selectedMode = modes.indexOf(value[0])
|
||||
|
||||
MaterialAlertDialogBuilder(requireActivity()).apply {
|
||||
setTitle(R.string.preferences_app_protection__see_my_phone_number)
|
||||
setCancelable(true)
|
||||
setSingleChoiceItems(
|
||||
modeStrings,
|
||||
selectedMode
|
||||
) { _: DialogInterface?, which: Int -> value[0] = modes[which] }
|
||||
setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
|
||||
val newSharingMode = value[0]
|
||||
Log.i(
|
||||
TAG,
|
||||
String.format(
|
||||
"PhoneNumberSharingMode changed to %s. Scheduling storage value sync",
|
||||
newSharingMode
|
||||
)
|
||||
)
|
||||
viewModel.setPhoneNumberSharingMode(value[0])
|
||||
}
|
||||
setNegativeButton(android.R.string.cancel, null)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun items(context: Context): Map<PhoneNumberPrivacyValues.PhoneNumberSharingMode, CharSequence> {
|
||||
val map: MutableMap<PhoneNumberPrivacyValues.PhoneNumberSharingMode, CharSequence> = LinkedHashMap()
|
||||
map[PhoneNumberPrivacyValues.PhoneNumberSharingMode.EVERYONE] = titleAndDescription(
|
||||
context,
|
||||
context.getString(R.string.PhoneNumberPrivacy_everyone),
|
||||
context.getString(R.string.PhoneNumberPrivacy_everyone_see_description)
|
||||
)
|
||||
map[PhoneNumberPrivacyValues.PhoneNumberSharingMode.NOBODY] =
|
||||
context.getString(R.string.PhoneNumberPrivacy_nobody)
|
||||
return map
|
||||
}
|
||||
|
||||
private fun titleAndDescription(
|
||||
context: Context,
|
||||
header: String,
|
||||
description: String
|
||||
): CharSequence {
|
||||
return SpannableStringBuilder().apply {
|
||||
append("\n")
|
||||
append(header)
|
||||
append("\n")
|
||||
setSpan(
|
||||
TextAppearanceSpan(context, android.R.style.TextAppearance_Small),
|
||||
length,
|
||||
length,
|
||||
Spanned.SPAN_INCLUSIVE_INCLUSIVE
|
||||
)
|
||||
append(description)
|
||||
append("\n")
|
||||
}
|
||||
}
|
||||
|
||||
fun onFindMyPhoneNumberClicked(phoneNumberListingMode: PhoneNumberListingMode) {
|
||||
val context = requireContext()
|
||||
val value = arrayOf(phoneNumberListingMode)
|
||||
MaterialAlertDialogBuilder(requireActivity()).apply {
|
||||
setTitle(R.string.preferences_app_protection__find_me_by_phone_number)
|
||||
setCancelable(true)
|
||||
setSingleChoiceItems(
|
||||
arrayOf(
|
||||
titleAndDescription(
|
||||
context,
|
||||
context.getString(R.string.PhoneNumberPrivacy_everyone),
|
||||
context.getString(R.string.PhoneNumberPrivacy_everyone_find_description)
|
||||
),
|
||||
context.getString(R.string.PhoneNumberPrivacy_nobody)
|
||||
),
|
||||
value[0].ordinal
|
||||
) { _: DialogInterface?, which: Int -> value[0] = PhoneNumberListingMode.values()[which] }
|
||||
setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
|
||||
Log.i(
|
||||
TAG,
|
||||
String.format(
|
||||
"PhoneNumberListingMode changed to %s. Scheduling storage value sync",
|
||||
value[0]
|
||||
)
|
||||
)
|
||||
viewModel.setPhoneNumberListingMode(value[0])
|
||||
}
|
||||
setNegativeButton(android.R.string.cancel, null)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
private class ValueClickPreference(
|
||||
val value: DSLSettingsText,
|
||||
val clickPreference: ClickPreference
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
package org.thoughtcrime.securesms.components.settings.app.privacy
|
||||
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues
|
||||
|
||||
data class PrivacySettingsState(
|
||||
val blockedCount: Int,
|
||||
val seeMyPhoneNumber: PhoneNumberPrivacyValues.PhoneNumberSharingMode,
|
||||
val findMeByPhoneNumber: PhoneNumberPrivacyValues.PhoneNumberListingMode,
|
||||
val readReceipts: Boolean,
|
||||
val typingIndicators: Boolean,
|
||||
val screenLock: Boolean,
|
||||
|
|
|
@ -4,14 +4,8 @@ import android.content.SharedPreferences
|
|||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob
|
||||
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.livedata.Store
|
||||
|
||||
|
@ -58,20 +52,6 @@ class PrivacySettingsViewModel(
|
|||
refresh()
|
||||
}
|
||||
|
||||
fun setPhoneNumberSharingMode(phoneNumberSharingMode: PhoneNumberPrivacyValues.PhoneNumberSharingMode) {
|
||||
SignalStore.phoneNumberPrivacy().phoneNumberSharingMode = phoneNumberSharingMode
|
||||
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setPhoneNumberListingMode(phoneNumberListingMode: PhoneNumberPrivacyValues.PhoneNumberListingMode) {
|
||||
SignalStore.phoneNumberPrivacy().phoneNumberListingMode = phoneNumberListingMode
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
ApplicationDependencies.getJobManager().startChain(RefreshAttributesJob()).then(RefreshOwnProfileJob()).enqueue()
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setIncognitoKeyboard(enabled: Boolean) {
|
||||
sharedPreferences.edit().putBoolean(TextSecurePreferences.INCOGNITO_KEYBORAD_PREF, enabled).apply()
|
||||
refresh()
|
||||
|
@ -106,8 +86,6 @@ class PrivacySettingsViewModel(
|
|||
screenSecurity = TextSecurePreferences.isScreenSecurityEnabled(ApplicationDependencies.getApplication()),
|
||||
incognitoKeyboard = TextSecurePreferences.isIncognitoKeyboardEnabled(ApplicationDependencies.getApplication()),
|
||||
paymentLock = SignalStore.paymentsValues().paymentLock,
|
||||
seeMyPhoneNumber = SignalStore.phoneNumberPrivacy().phoneNumberSharingMode,
|
||||
findMeByPhoneNumber = SignalStore.phoneNumberPrivacy().phoneNumberListingMode,
|
||||
isObsoletePasswordEnabled = !TextSecurePreferences.isPasswordDisabled(ApplicationDependencies.getApplication()),
|
||||
isObsoletePasswordTimeoutEnabled = TextSecurePreferences.isPassphraseTimeoutEnabled(ApplicationDependencies.getApplication()),
|
||||
obsoletePasswordTimeout = TextSecurePreferences.getPassphraseTimeoutInterval(ApplicationDependencies.getApplication()),
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
package org.thoughtcrime.securesms.components.settings.app.privacy.pnp
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import org.signal.core.ui.Dividers
|
||||
import org.signal.core.ui.Rows
|
||||
import org.signal.core.ui.Scaffolds
|
||||
import org.signal.core.ui.Texts
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues.PhoneNumberListingMode
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues.PhoneNumberSharingMode
|
||||
|
||||
class PhoneNumberPrivacySettingsFragment : ComposeFragment() {
|
||||
|
||||
private val viewModel: PhoneNumberPrivacySettingsViewModel by viewModels()
|
||||
|
||||
@Composable
|
||||
override fun SheetContent() {
|
||||
val state: PhoneNumberPrivacySettingsState by viewModel.state
|
||||
val onNavigationClick: () -> Unit = remember {
|
||||
{ findNavController().popBackStack() }
|
||||
}
|
||||
|
||||
Scaffolds.Settings(
|
||||
title = stringResource(id = R.string.preferences_app_protection__phone_number),
|
||||
onNavigationClick = onNavigationClick,
|
||||
painter = painterResource(id = R.drawable.ic_arrow_left_24),
|
||||
navigationContentDescription = stringResource(id = R.string.Material3SearchToolbar__close)
|
||||
) { contentPadding ->
|
||||
Box(modifier = Modifier.padding(contentPadding)) {
|
||||
LazyColumn {
|
||||
item {
|
||||
Texts.SectionHeader(
|
||||
text = stringResource(id = R.string.PhoneNumberPrivacySettingsFragment__who_can_see_my_number)
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Rows.RadioRow(
|
||||
selected = state.seeMyPhoneNumber == PhoneNumberSharingMode.EVERYONE,
|
||||
text = stringResource(id = R.string.PhoneNumberPrivacy_everyone),
|
||||
modifier = Modifier.clickable(onClick = viewModel::setEveryoneCanSeeMyNumber)
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Rows.RadioRow(
|
||||
selected = state.seeMyPhoneNumber == PhoneNumberSharingMode.NOBODY,
|
||||
text = stringResource(id = R.string.PhoneNumberPrivacy_nobody),
|
||||
modifier = Modifier.clickable(onClick = viewModel::setNobodyCanSeeMyNumber)
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Text(
|
||||
text = stringResource(
|
||||
id = when (state.seeMyPhoneNumber) {
|
||||
PhoneNumberSharingMode.EVERYONE -> R.string.PhoneNumberPrivacySettingsFragment__your_phone_number
|
||||
PhoneNumberSharingMode.NOBODY -> R.string.PhoneNumberPrivacySettingsFragment__nobody_will_see
|
||||
else -> error("Unexpected state $state")
|
||||
}
|
||||
),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp)
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Dividers.Default()
|
||||
}
|
||||
|
||||
item {
|
||||
Texts.SectionHeader(text = stringResource(id = R.string.PhoneNumberPrivacySettingsFragment__who_can_find_me_by_number))
|
||||
}
|
||||
|
||||
item {
|
||||
Rows.RadioRow(
|
||||
selected = state.findMeByPhoneNumber == PhoneNumberListingMode.LISTED,
|
||||
text = stringResource(id = R.string.PhoneNumberPrivacy_everyone),
|
||||
modifier = Modifier.clickable(onClick = viewModel::setEveryoneCanFindMeByMyNumber)
|
||||
)
|
||||
}
|
||||
|
||||
if (state.seeMyPhoneNumber == PhoneNumberSharingMode.NOBODY) {
|
||||
item {
|
||||
Rows.RadioRow(
|
||||
selected = state.findMeByPhoneNumber == PhoneNumberListingMode.UNLISTED,
|
||||
text = stringResource(id = R.string.PhoneNumberPrivacy_nobody),
|
||||
modifier = Modifier.clickable(onClick = viewModel::setNobodyCanFindMeByMyNumber)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Text(
|
||||
text = stringResource(
|
||||
id = when (state.findMeByPhoneNumber) {
|
||||
PhoneNumberListingMode.UNLISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__nobody_on_signal
|
||||
PhoneNumberListingMode.LISTED -> R.string.WhoCanSeeMyPhoneNumberFragment__anyone_who_has
|
||||
}
|
||||
),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.core_ui__gutter), vertical = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package org.thoughtcrime.securesms.components.settings.app.privacy.pnp
|
||||
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues
|
||||
|
||||
data class PhoneNumberPrivacySettingsState(
|
||||
val seeMyPhoneNumber: PhoneNumberPrivacyValues.PhoneNumberSharingMode,
|
||||
val findMeByPhoneNumber: PhoneNumberPrivacyValues.PhoneNumberListingMode
|
||||
)
|
|
@ -0,0 +1,63 @@
|
|||
package org.thoughtcrime.securesms.components.settings.app.privacy.pnp
|
||||
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob
|
||||
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues.PhoneNumberListingMode
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues.PhoneNumberSharingMode
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper
|
||||
|
||||
class PhoneNumberPrivacySettingsViewModel : ViewModel() {
|
||||
|
||||
private val _state = mutableStateOf(
|
||||
PhoneNumberPrivacySettingsState(
|
||||
seeMyPhoneNumber = SignalStore.phoneNumberPrivacy().phoneNumberSharingMode,
|
||||
findMeByPhoneNumber = SignalStore.phoneNumberPrivacy().phoneNumberListingMode
|
||||
)
|
||||
)
|
||||
|
||||
val state: State<PhoneNumberPrivacySettingsState> = _state
|
||||
|
||||
fun setNobodyCanSeeMyNumber() {
|
||||
setPhoneNumberSharingMode(PhoneNumberSharingMode.NOBODY)
|
||||
}
|
||||
|
||||
fun setEveryoneCanSeeMyNumber() {
|
||||
setPhoneNumberSharingMode(PhoneNumberSharingMode.EVERYONE)
|
||||
}
|
||||
|
||||
fun setNobodyCanFindMeByMyNumber() {
|
||||
setPhoneNumberListingMode(PhoneNumberListingMode.UNLISTED)
|
||||
}
|
||||
|
||||
fun setEveryoneCanFindMeByMyNumber() {
|
||||
setPhoneNumberListingMode(PhoneNumberListingMode.LISTED)
|
||||
}
|
||||
|
||||
private fun setPhoneNumberSharingMode(phoneNumberSharingMode: PhoneNumberSharingMode) {
|
||||
SignalStore.phoneNumberPrivacy().phoneNumberSharingMode = phoneNumberSharingMode
|
||||
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
refresh()
|
||||
}
|
||||
|
||||
private fun setPhoneNumberListingMode(phoneNumberListingMode: PhoneNumberListingMode) {
|
||||
SignalStore.phoneNumberPrivacy().phoneNumberListingMode = phoneNumberListingMode
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
ApplicationDependencies.getJobManager().startChain(RefreshAttributesJob()).then(RefreshOwnProfileJob()).enqueue()
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
_state.value = PhoneNumberPrivacySettingsState(
|
||||
seeMyPhoneNumber = SignalStore.phoneNumberPrivacy().phoneNumberSharingMode,
|
||||
findMeByPhoneNumber = SignalStore.phoneNumberPrivacy().phoneNumberListingMode
|
||||
)
|
||||
}
|
||||
}
|
|
@ -35,6 +35,13 @@
|
|||
app:exitAnim="@anim/fragment_open_exit"
|
||||
app:popEnterAnim="@anim/fragment_close_enter"
|
||||
app:popExitAnim="@anim/fragment_close_exit" />
|
||||
<action
|
||||
android:id="@+id/action_privacySettingsFragment_to_phoneNumberPrivacySettingsFragment"
|
||||
app:destination="@id/phoneNumberPrivacySettingsFragment"
|
||||
app:enterAnim="@anim/fragment_open_enter"
|
||||
app:exitAnim="@anim/fragment_open_exit"
|
||||
app:popEnterAnim="@anim/fragment_close_enter"
|
||||
app:popExitAnim="@anim/fragment_close_exit" />
|
||||
|
||||
</fragment>
|
||||
|
||||
|
@ -48,6 +55,11 @@
|
|||
android:name="org.thoughtcrime.securesms.components.settings.app.privacy.advanced.AdvancedPrivacySettingsFragment"
|
||||
android:label="advanced_privacy_settings_fragment" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/phoneNumberPrivacySettingsFragment"
|
||||
android:name="org.thoughtcrime.securesms.components.settings.app.privacy.pnp.PhoneNumberPrivacySettingsFragment"
|
||||
android:label="phone_number_privacy_settings_fragment" />
|
||||
|
||||
<include app:graph="@navigation/app_settings_expire_timer" />
|
||||
|
||||
</navigation>
|
||||
|
|
|
@ -3458,6 +3458,18 @@
|
|||
<string name="BackupUtil_unknown">Unknown</string>
|
||||
<string name="preferences_app_protection__see_my_phone_number">See my phone number</string>
|
||||
<string name="preferences_app_protection__find_me_by_phone_number">Find me by phone number</string>
|
||||
<!-- Phone number heading displayed as a screen title -->
|
||||
<string name="preferences_app_protection__phone_number">Phone number</string>
|
||||
<!-- Subtext below option to launch into phone number privacy settings screen -->
|
||||
<string name="preferences_app_protection__choose_who_can_see">Choose who can see your phone number and who can contact you on Signal with it.</string>
|
||||
<!-- Section title above two radio buttons for enabling and disabling phone number display -->
|
||||
<string name="PhoneNumberPrivacySettingsFragment__who_can_see_my_number">Who can see my number</string>
|
||||
<!-- Subtext below radio buttons when who can see my number is set to nobody -->
|
||||
<string name="PhoneNumberPrivacySettingsFragment__nobody_will_see">Nobody will see your phone number on Signal</string>
|
||||
<!-- Section title above two radio buttons for enabling and disabling whether users can find me by my phone number -->
|
||||
<string name="PhoneNumberPrivacySettingsFragment__who_can_find_me_by_number">Who can find me by number</string>
|
||||
<!-- Subtext below radio buttons when who can see my number is set to everyone -->
|
||||
<string name="PhoneNumberPrivacySettingsFragment__your_phone_number">Your phone number will be visible to people and groups you message. People who have your number in their phone contacts will also see it on Signal.</string>
|
||||
<string name="PhoneNumberPrivacy_everyone">Everyone</string>
|
||||
<string name="PhoneNumberPrivacy_my_contacts">My contacts</string>
|
||||
<string name="PhoneNumberPrivacy_nobody">Nobody</string>
|
||||
|
|
32
core-ui/src/main/java/org/signal/core/ui/Dividers.kt
Normal file
32
core-ui/src/main/java/org/signal/core/ui/Dividers.kt
Normal file
|
@ -0,0 +1,32 @@
|
|||
package org.signal.core.ui
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.signal.core.ui.theme.SignalTheme
|
||||
|
||||
/**
|
||||
* Thin divider lines for separating content.
|
||||
*/
|
||||
object Dividers {
|
||||
@Composable
|
||||
fun Default(modifier: Modifier = Modifier) {
|
||||
Divider(
|
||||
thickness = 1.5.dp,
|
||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||
modifier = modifier.padding(vertical = 16.25.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun DefaultPreview() {
|
||||
SignalTheme(isDarkMode = false) {
|
||||
Dividers.Default()
|
||||
}
|
||||
}
|
55
core-ui/src/main/java/org/signal/core/ui/Rows.kt
Normal file
55
core-ui/src/main/java/org/signal/core/ui/Rows.kt
Normal file
|
@ -0,0 +1,55 @@
|
|||
package org.signal.core.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.signal.core.ui.theme.SignalTheme
|
||||
|
||||
object Rows {
|
||||
/**
|
||||
* A row consisting of a radio button and text, which takes up the full
|
||||
* width of the screen.
|
||||
*/
|
||||
@Composable
|
||||
fun RadioRow(
|
||||
selected: Boolean,
|
||||
text: String,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
horizontal = dimensionResource(id = R.dimen.core_ui__gutter),
|
||||
vertical = 16.dp
|
||||
)
|
||||
) {
|
||||
RadioButton(
|
||||
selected = selected,
|
||||
onClick = null,
|
||||
modifier = Modifier.padding(end = 24.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.bodyLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun RadioRowPreview() {
|
||||
SignalTheme(isDarkMode = false) {
|
||||
Rows.RadioRow(true, "RadioRow")
|
||||
}
|
||||
}
|
54
core-ui/src/main/java/org/signal/core/ui/Scaffolds.kt
Normal file
54
core-ui/src/main/java/org/signal/core/ui/Scaffolds.kt
Normal file
|
@ -0,0 +1,54 @@
|
|||
package org.signal.core.ui
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
object Scaffolds {
|
||||
@Composable
|
||||
fun Settings(
|
||||
title: String,
|
||||
onNavigationClick: () -> Unit,
|
||||
painter: Painter,
|
||||
modifier: Modifier = Modifier,
|
||||
navigationContentDescription: String? = null,
|
||||
content: @Composable (PaddingValues) -> Unit
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(
|
||||
onClick = onNavigationClick,
|
||||
Modifier.padding(end = 16.dp)
|
||||
) {
|
||||
Icon(
|
||||
painter = painter,
|
||||
contentDescription = navigationContentDescription
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
modifier = modifier,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
}
|
40
core-ui/src/main/java/org/signal/core/ui/Texts.kt
Normal file
40
core-ui/src/main/java/org/signal/core/ui/Texts.kt
Normal file
|
@ -0,0 +1,40 @@
|
|||
package org.signal.core.ui
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.signal.core.ui.theme.SignalTheme
|
||||
|
||||
object Texts {
|
||||
/**
|
||||
* Header row for settings pages.
|
||||
*/
|
||||
@Composable
|
||||
fun SectionHeader(
|
||||
text: String,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
modifier = modifier
|
||||
.padding(
|
||||
horizontal = dimensionResource(id = R.dimen.core_ui__gutter)
|
||||
)
|
||||
.padding(top = 16.dp, bottom = 12.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun SectionHeaderPreview() {
|
||||
SignalTheme(isDarkMode = false) {
|
||||
Texts.SectionHeader("Header")
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ import androidx.compose.ui.text.font.FontFamily
|
|||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
private val typography = Typography().apply {
|
||||
private val typography = Typography().run {
|
||||
copy(
|
||||
headlineLarge = headlineLarge.copy(
|
||||
lineHeight = 40.sp,
|
||||
|
|
4
core-ui/src/main/res/values-sw360dp/dimens.xml
Normal file
4
core-ui/src/main/res/values-sw360dp/dimens.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="core_ui__gutter">24dp</dimen>
|
||||
</resources>
|
4
core-ui/src/main/res/values/dimens.xml
Normal file
4
core-ui/src/main/res/values/dimens.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="core_ui__gutter">16dp</dimen>
|
||||
</resources>
|
Loading…
Add table
Reference in a new issue