Skip to content

Commit 6822e20

Browse files
UI tweaks for app disguise settings (#1140)
* Adjustment * Remove unnecessary change * Tidy up * Remove unnecessary change * Update min height * Extending call timeout to match other platforms * Crowdin strings * Making sure the close button is set to danger color --------- Co-authored-by: ThomasSession <thomas.r@getsession.org>
1 parent 43483da commit 6822e20

File tree

10 files changed

+164
-94
lines changed

10 files changed

+164
-94
lines changed

app/src/main/java/org/thoughtcrime/securesms/ScreenLockActionBarActivity.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ import androidx.core.content.ContextCompat
1212
import androidx.core.content.FileProvider
1313
import androidx.fragment.app.Fragment
1414
import androidx.lifecycle.lifecycleScope
15-
import dagger.hilt.android.AndroidEntryPoint
16-
import java.io.File
17-
import java.io.FileOutputStream
18-
import java.lang.Exception
19-
import java.util.Locale
2015
import kotlinx.coroutines.Dispatchers
2116
import kotlinx.coroutines.launch
2217
import kotlinx.coroutines.withContext
@@ -30,7 +25,9 @@ import org.thoughtcrime.securesms.onboarding.landing.LandingActivity
3025
import org.thoughtcrime.securesms.service.KeyCachingService
3126
import org.thoughtcrime.securesms.util.FileProviderUtil
3227
import org.thoughtcrime.securesms.util.FilenameUtils
33-
import javax.inject.Inject
28+
import java.io.File
29+
import java.io.FileOutputStream
30+
import java.util.Locale
3431

3532
abstract class ScreenLockActionBarActivity : BaseActionBarActivity() {
3633

app/src/main/java/org/thoughtcrime/securesms/components/SwitchPreferenceCompat.kt

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,29 @@ package org.thoughtcrime.securesms.components
22

33
import android.content.Context
44
import android.util.AttributeSet
5-
import androidx.preference.CheckBoxPreference
6-
import com.squareup.phrase.Phrase
5+
import androidx.compose.runtime.collectAsState
6+
import androidx.compose.ui.platform.ComposeView
7+
import androidx.preference.PreferenceViewHolder
8+
import androidx.preference.TwoStatePreference
9+
import kotlinx.coroutines.flow.MutableStateFlow
710
import network.loki.messenger.R
811
import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY
12+
import org.thoughtcrime.securesms.ui.components.SessionSwitch
913
import org.thoughtcrime.securesms.ui.getSubbedCharSequence
10-
import org.thoughtcrime.securesms.ui.getSubbedString
14+
import org.thoughtcrime.securesms.ui.setThemedContent
1115

12-
class SwitchPreferenceCompat : CheckBoxPreference {
16+
class SwitchPreferenceCompat : TwoStatePreference {
1317
private var listener: OnPreferenceClickListener? = null
1418

15-
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context!!, attrs, defStyleAttr) {
16-
setLayoutRes()
17-
}
18-
19-
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context!!, attrs, defStyleAttr, defStyleRes) {
20-
setLayoutRes()
21-
}
22-
23-
constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs) {
24-
setLayoutRes()
25-
}
19+
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
20+
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
21+
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
22+
constructor(context: Context) : super(context)
2623

27-
constructor(context: Context?) : super(context!!) {
28-
setLayoutRes()
29-
}
24+
private val checkState = MutableStateFlow(isChecked)
25+
private val enableState = MutableStateFlow(isEnabled)
3026

31-
private fun setLayoutRes() {
27+
init {
3228
widgetLayoutResource = R.layout.switch_compat_preference
3329

3430
if (this.hasKey()) {
@@ -43,6 +39,31 @@ class SwitchPreferenceCompat : CheckBoxPreference {
4339
}
4440
}
4541

42+
override fun setChecked(checked: Boolean) {
43+
super.setChecked(checked)
44+
45+
checkState.value = checked
46+
}
47+
48+
override fun setEnabled(enabled: Boolean) {
49+
super.setEnabled(enabled)
50+
51+
enableState.value = enabled
52+
}
53+
54+
override fun onBindViewHolder(holder: PreferenceViewHolder) {
55+
super.onBindViewHolder(holder)
56+
57+
val composeView = holder.findViewById(R.id.compose_preference) as ComposeView
58+
composeView.setThemedContent {
59+
SessionSwitch(
60+
checked = checkState.collectAsState().value,
61+
onCheckedChange = null,
62+
enabled = isEnabled
63+
)
64+
}
65+
}
66+
4667
override fun setOnPreferenceClickListener(listener: OnPreferenceClickListener?) {
4768
this.listener = listener
4869
}

app/src/main/java/org/thoughtcrime/securesms/disguise/AppDisguiseManager.kt

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -105,38 +105,28 @@ class AppDisguiseManager @Inject constructor(
105105
}
106106

107107
all.map { alias ->
108-
// Set the state to enabled or disabled based on the selected alias,
109-
// and also taking the default state into account. This is trying to
110-
// not change the state if the default is sufficient.
111-
val state = when {
112-
alias === enabledAlias && alias.defaultEnabled -> {
113-
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
114-
}
115-
116-
alias === enabledAlias -> {
117-
PackageManager.COMPONENT_ENABLED_STATE_ENABLED
118-
}
119-
120-
alias.defaultEnabled -> {
121-
PackageManager.COMPONENT_ENABLED_STATE_DISABLED
122-
}
123-
124-
else -> {
125-
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
126-
}
127-
}
108+
val state = if (alias === enabledAlias) PackageManager.COMPONENT_ENABLED_STATE_ENABLED
109+
else PackageManager.COMPONENT_ENABLED_STATE_DISABLED
128110

129111
ComponentName(application, alias.activityAliasName) to state
130112
}
131113
}.collectLatest { all ->
132-
all.forEach { (name, state) ->
133-
Log.d(TAG, "Set state $name: $state")
134-
135-
application.packageManager.setComponentEnabledSetting(
136-
name,
137-
state,
138-
PackageManager.DONT_KILL_APP
114+
if (android.os.Build.VERSION.SDK_INT >= 33) {
115+
application.packageManager.setComponentEnabledSettings(
116+
all.map { (name, state) ->
117+
PackageManager.ComponentEnabledSetting(
118+
name, state, PackageManager.DONT_KILL_APP or PackageManager.SYNCHRONOUS
119+
)
120+
}
139121
)
122+
} else {
123+
all.forEach { (name, state) ->
124+
application.packageManager.setComponentEnabledSetting(
125+
name,
126+
state,
127+
PackageManager.DONT_KILL_APP
128+
)
129+
}
140130
}
141131
}
142132
}

app/src/main/java/org/thoughtcrime/securesms/preferences/appearance/AppDisguiseSettings.kt

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ import androidx.compose.ui.unit.dp
4242
import androidx.core.content.res.ResourcesCompat
4343
import androidx.core.graphics.drawable.toBitmap
4444
import network.loki.messenger.R
45+
import org.thoughtcrime.securesms.ui.AlertDialog
4546
import org.thoughtcrime.securesms.ui.Cell
47+
import org.thoughtcrime.securesms.ui.DialogButtonModel
48+
import org.thoughtcrime.securesms.ui.GetString
4649
import org.thoughtcrime.securesms.ui.components.BackAppBar
4750
import org.thoughtcrime.securesms.ui.components.SessionSwitch
4851
import org.thoughtcrime.securesms.ui.theme.LocalColors
@@ -61,10 +64,10 @@ fun AppDisguiseSettingsScreen(
6164
) {
6265
AppDisguiseSettings(
6366
onBack = onBack,
64-
setOn = viewModel::setOn,
6567
isOn = viewModel.isOn.collectAsState().value,
6668
items = viewModel.alternativeIcons.collectAsState().value,
67-
onItemSelected = viewModel::onIconSelected
69+
dialogState = viewModel.confirmDialogState.collectAsState().value,
70+
onCommand = viewModel::onCommand,
6871
)
6972
}
7073

@@ -73,9 +76,9 @@ fun AppDisguiseSettingsScreen(
7376
private fun AppDisguiseSettings(
7477
items: List<AppDisguiseSettingsViewModel.IconAndName>,
7578
isOn: Boolean,
76-
setOn: (Boolean) -> Unit,
77-
onItemSelected: (String) -> Unit,
79+
dialogState: AppDisguiseSettingsViewModel.ConfirmDialogState,
7880
onBack: () -> Unit,
81+
onCommand: (AppDisguiseSettingsViewModel.Command) -> Unit,
7982
) {
8083
Scaffold(
8184
topBar = {
@@ -98,7 +101,9 @@ private fun AppDisguiseSettings(
98101
Cell {
99102
Row(
100103
modifier = Modifier
101-
.toggleable(value = isOn, onValueChange = setOn)
104+
.toggleable(value = isOn, onValueChange = {
105+
onCommand(AppDisguiseSettingsViewModel.Command.ToggleClicked(it))
106+
})
102107
.padding(LocalDimensions.current.xsSpacing),
103108
verticalAlignment = Alignment.CenterVertically,
104109
) {
@@ -150,7 +155,7 @@ private fun AppDisguiseSettings(
150155
icon = item.icon,
151156
name = item.name,
152157
selected = item.selected,
153-
onSelected = { onItemSelected(item.id) },
158+
onSelected = { onCommand(AppDisguiseSettingsViewModel.Command.IconSelected(item.id)) },
154159
modifier = Modifier.weight(1f)
155160
)
156161
}
@@ -169,9 +174,23 @@ private fun AppDisguiseSettings(
169174
)
170175
}
171176
}
172-
173177
}
174178
}
179+
180+
if (dialogState.showDialog) {
181+
AlertDialog(
182+
onDismissRequest = { onCommand(AppDisguiseSettingsViewModel.Command.IconSelectDismissed) },
183+
text = stringResource(R.string.appIconAndNameChangeConfirmation),
184+
title = stringResource(R.string.appIconAndNameChange),
185+
buttons = listOf(
186+
DialogButtonModel(
187+
text = GetString(R.string.closeApp),
188+
color = LocalColors.current.danger,
189+
) { onCommand(AppDisguiseSettingsViewModel.Command.IconSelectConfirmed(dialogState.id)) },
190+
DialogButtonModel(text = GetString(R.string.cancel), dismissOnClick = true)
191+
)
192+
)
193+
}
175194
}
176195

177196
private const val ICON_ITEM_SIZE_DP = 90
@@ -287,9 +306,9 @@ private fun AppDisguiseSettingsPreview(
287306
),
288307
),
289308
isOn = true,
290-
setOn = { },
291-
onItemSelected = { },
292309
onBack = { },
310+
dialogState = AppDisguiseSettingsViewModel.ConfirmDialogState(null, false),
311+
onCommand = {}
293312
)
294313
}
295314
}

app/src/main/java/org/thoughtcrime/securesms/preferences/appearance/AppDisguiseSettingsViewModel.kt

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import androidx.annotation.StringRes
55
import androidx.lifecycle.ViewModel
66
import androidx.lifecycle.viewModelScope
77
import dagger.hilt.android.lifecycle.HiltViewModel
8+
import kotlinx.coroutines.flow.MutableStateFlow
89
import kotlinx.coroutines.flow.SharingStarted
910
import kotlinx.coroutines.flow.StateFlow
1011
import kotlinx.coroutines.flow.combine
@@ -39,16 +40,42 @@ class AppDisguiseSettingsViewModel @Inject constructor(
3940
initialValue = emptyList()
4041
)
4142

42-
fun onIconSelected(id: String) {
43-
manager.setOn(true)
44-
manager.setSelectedAliasName(id)
45-
}
43+
private val mutableConfirmDialogState = MutableStateFlow(ConfirmDialogState(null, false))
44+
val confirmDialogState: StateFlow<ConfirmDialogState> get() = mutableConfirmDialogState
45+
46+
fun onCommand(command: Command) {
47+
when (command) {
48+
is Command.IconSelectConfirmed -> {
49+
mutableConfirmDialogState.value = ConfirmDialogState(null, false)
50+
if (command.id == null) {
51+
manager.setOn(false)
52+
} else {
53+
manager.setOn(true)
54+
manager.setSelectedAliasName(command.id)
55+
}
56+
}
57+
58+
Command.IconSelectDismissed -> {
59+
mutableConfirmDialogState.value = ConfirmDialogState(null, false)
60+
}
61+
62+
is Command.IconSelected -> {
63+
if (!isOn.value || command.id != manager.selectedAppAliasName.value) {
64+
mutableConfirmDialogState.value = ConfirmDialogState(
65+
id = command.id,
66+
showDialog = true
67+
)
68+
}
69+
}
4670

47-
fun setOn(on: Boolean) {
48-
manager.setOn(on)
71+
is Command.ToggleClicked -> {
72+
if (isOn.value == command.on) return
4973

50-
if (manager.selectedAppAliasName.value == null) {
51-
manager.setSelectedAliasName(alternativeIcons.value.firstOrNull()?.id)
74+
mutableConfirmDialogState.value = ConfirmDialogState(
75+
id = if (command.on) manager.selectedAppAliasName.value ?: alternativeIcons.value.firstOrNull()?.id else null,
76+
showDialog = true
77+
)
78+
}
5279
}
5380
}
5481

@@ -58,4 +85,13 @@ class AppDisguiseSettingsViewModel @Inject constructor(
5885
@StringRes val name: Int,
5986
val selected: Boolean,
6087
)
88+
89+
data class ConfirmDialogState(val id: String?, val showDialog: Boolean)
90+
91+
sealed interface Command {
92+
data class IconSelected(val id: String) : Command
93+
data class IconSelectConfirmed(val id: String?) : Command
94+
data object IconSelectDismissed : Command
95+
data class ToggleClicked(val on: Boolean) : Command
96+
}
6197
}

app/src/main/java/org/thoughtcrime/securesms/preferences/appearance/AppearanceSettingsActivity.kt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package org.thoughtcrime.securesms.preferences.appearance
33
import android.content.Intent
44
import android.os.Bundle
55
import android.os.Parcelable
6+
import android.se.omapi.Session
67
import android.util.SparseArray
78
import android.view.View
89
import androidx.activity.viewModels
10+
import androidx.compose.runtime.collectAsState
911
import androidx.core.view.children
1012
import androidx.lifecycle.lifecycleScope
1113
import dagger.hilt.android.AndroidEntryPoint
@@ -17,6 +19,8 @@ import org.session.libsession.utilities.TextSecurePreferences.Companion.CLASSIC_
1719
import org.session.libsession.utilities.TextSecurePreferences.Companion.OCEAN_DARK
1820
import org.session.libsession.utilities.TextSecurePreferences.Companion.OCEAN_LIGHT
1921
import org.thoughtcrime.securesms.ScreenLockActionBarActivity
22+
import org.thoughtcrime.securesms.ui.components.SessionSwitch
23+
import org.thoughtcrime.securesms.ui.setThemedContent
2024
import org.thoughtcrime.securesms.util.ThemeState
2125

2226
@AndroidEntryPoint
@@ -107,10 +111,6 @@ class AppearanceSettingsActivity: ScreenLockActionBarActivity(), View.OnClickLis
107111
}
108112
}
109113

110-
private fun updateFollowSystemToggle(followSystemSettings: Boolean) {
111-
binding.systemSettingsSwitch.isChecked = followSystemSettings
112-
}
113-
114114
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
115115
super.onCreate(savedInstanceState, ready)
116116
binding = ActivityAppearanceSettingsBinding.inflate(layoutInflater)
@@ -128,8 +128,13 @@ class AppearanceSettingsActivity: ScreenLockActionBarActivity(), View.OnClickLis
128128
it.setOnClickListener(this@AppearanceSettingsActivity)
129129
}
130130
// system settings toggle
131-
systemSettingsSwitch.setOnCheckedChangeListener { _, isChecked -> viewModel.setNewFollowSystemSettings(isChecked) }
132-
systemSettingsSwitchHolder.setOnClickListener { systemSettingsSwitch.toggle() }
131+
systemSettingsSwitch.setThemedContent {
132+
SessionSwitch(
133+
checked = viewModel.uiState.collectAsState().value.followSystem,
134+
onCheckedChange = viewModel::setNewFollowSystemSettings,
135+
enabled = true
136+
)
137+
}
133138

134139
systemSettingsAppIcon.setOnClickListener {
135140
startActivity(Intent(this@AppearanceSettingsActivity, AppDisguiseSettingsActivity::class.java))
@@ -138,10 +143,9 @@ class AppearanceSettingsActivity: ScreenLockActionBarActivity(), View.OnClickLis
138143

139144
lifecycleScope.launchWhenResumed {
140145
viewModel.uiState.collectLatest { themeState ->
141-
val (theme, accent, followSystem) = themeState
146+
val (theme, accent) = themeState
142147
updateSelectedTheme(theme)
143148
updateSelectedAccent(accent)
144-
updateFollowSystemToggle(followSystem)
145149
if (currentTheme != null && currentTheme != themeState) {
146150
recreate()
147151
} else {

0 commit comments

Comments
 (0)