Allow users to select a compact tab bar.

This commit is contained in:
Alex Hart
2023-04-13 14:19:47 -03:00
committed by Cody Henthorne
parent 06f19aa6cd
commit 09cf8074aa
20 changed files with 1354 additions and 21 deletions

View File

@@ -2,10 +2,12 @@ package org.thoughtcrime.securesms.components.settings.app.appearance
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.Navigation
import org.signal.core.util.concurrent.observe
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.app.appearance.navbar.ChooseNavigationBarStyleFragment
import org.thoughtcrime.securesms.components.settings.configure
import org.thoughtcrime.securesms.keyvalue.SettingsValues
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
@@ -30,10 +32,25 @@ class AppearanceSettingsFragment : DSLSettingsFragment(R.string.preferences__app
viewModel.state.observe(viewLifecycleOwner) { state ->
adapter.submitList(getConfiguration(state).toMappingModelList())
}
childFragmentManager.setFragmentResultListener(ChooseNavigationBarStyleFragment.REQUEST_KEY, viewLifecycleOwner) { key, bundle ->
if (bundle.getBoolean(key, false)) {
viewModel.refreshState()
}
}
}
private fun getConfiguration(state: AppearanceSettingsState): DSLConfiguration {
return configure {
radioListPref(
title = DSLSettingsText.from(R.string.preferences__language),
listItems = languageLabels,
selected = languageValues.indexOf(state.language),
onSelected = {
viewModel.setLanguage(languageValues[it])
}
)
radioListPref(
title = DSLSettingsText.from(R.string.preferences__theme),
listItems = themeLabels,
@@ -59,12 +76,17 @@ class AppearanceSettingsFragment : DSLSettingsFragment(R.string.preferences__app
}
)
radioListPref(
title = DSLSettingsText.from(R.string.preferences__language),
listItems = languageLabels,
selected = languageValues.indexOf(state.language),
onSelected = {
viewModel.setLanguage(languageValues[it])
clickPref(
title = DSLSettingsText.from(R.string.preferences_navigation_bar_size),
summary = DSLSettingsText.from(
if (state.isCompactNavigationBar) {
R.string.preferences_compact
} else {
R.string.preferences_normal
}
),
onClick = {
ChooseNavigationBarStyleFragment().show(childFragmentManager, null)
}
)
}

View File

@@ -5,5 +5,6 @@ import org.thoughtcrime.securesms.keyvalue.SettingsValues
data class AppearanceSettingsState(
val theme: SettingsValues.Theme,
val messageFontSize: Int,
val language: String
val language: String,
val isCompactNavigationBar: Boolean
)

View File

@@ -1,28 +1,26 @@
package org.thoughtcrime.securesms.components.settings.app.appearance
import android.app.Activity
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import io.reactivex.rxjava3.core.Flowable
import org.thoughtcrime.securesms.jobs.EmojiSearchIndexDownloadJob
import org.thoughtcrime.securesms.keyvalue.SettingsValues.Theme
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.SplashScreenUtil
import org.thoughtcrime.securesms.util.livedata.Store
import org.thoughtcrime.securesms.util.rx.RxStore
class AppearanceSettingsViewModel : ViewModel() {
private val store: Store<AppearanceSettingsState>
private val store = RxStore(getState())
val state: Flowable<AppearanceSettingsState> = store.stateFlowable
init {
val initialState = AppearanceSettingsState(
SignalStore.settings().theme,
SignalStore.settings().messageFontSize,
SignalStore.settings().language
)
store = Store(initialState)
override fun onCleared() {
super.onCleared()
store.dispose()
}
val state: LiveData<AppearanceSettingsState> = store.stateLiveData
fun refreshState() {
store.update { getState() }
}
fun setTheme(activity: Activity?, theme: Theme) {
store.update { it.copy(theme = theme) }
@@ -40,4 +38,13 @@ class AppearanceSettingsViewModel : ViewModel() {
store.update { it.copy(messageFontSize = size) }
SignalStore.settings().messageFontSize = size
}
private fun getState(): AppearanceSettingsState {
return AppearanceSettingsState(
SignalStore.settings().theme,
SignalStore.settings().messageFontSize,
SignalStore.settings().language,
SignalStore.settings().useCompactNavigationBar
)
}
}

View File

@@ -0,0 +1,90 @@
package org.thoughtcrime.securesms.components.settings.app.appearance.navbar
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.View
import androidx.annotation.DrawableRes
import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.setFragmentResult
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.ViewBinderDelegate
import org.thoughtcrime.securesms.databinding.ChooseNavigationBarStyleFragmentBinding
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.FeatureFlags
/**
* Allows the user to choose between a compact and full-sized navigation bar.
*/
class ChooseNavigationBarStyleFragment : DialogFragment(R.layout.choose_navigation_bar_style_fragment) {
private val binding by ViewBinderDelegate(ChooseNavigationBarStyleFragmentBinding::bind)
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
return dialog
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
presentToggleState(SignalStore.settings().useCompactNavigationBar)
binding.toggle.addOnButtonCheckedListener { group, checkedId, isChecked ->
if (isChecked) {
presentToggleState(checkedId == R.id.compact)
}
}
binding.ok.setOnClickListener {
val isCompact = binding.toggle.checkedButtonId == R.id.compact
SignalStore.settings().useCompactNavigationBar = isCompact
dismissAllowingStateLoss()
setFragmentResult(REQUEST_KEY, bundleOf(REQUEST_KEY to true))
}
}
private fun presentToggleState(isCompact: Boolean) {
binding.toggle.check(if (isCompact) R.id.compact else R.id.normal)
binding.image.setImageResource(PreviewImages.getImageResourceId(isCompact))
binding.normal.setIconResource(if (isCompact) 0 else R.drawable.ic_check_20)
binding.compact.setIconResource(if (isCompact) R.drawable.ic_check_20 else 0)
}
private sealed class PreviewImages(
@DrawableRes private val compact: Int,
@DrawableRes private val normal: Int
) {
@DrawableRes
fun getImageResource(isCompact: Boolean): Int {
return if (isCompact) compact else normal
}
private object ThreeButtons : PreviewImages(
compact = R.drawable.navbar_compact,
normal = R.drawable.navbar_normal
)
private object TwoButtons : PreviewImages(
compact = R.drawable.navbar_compact_2,
normal = R.drawable.navbar_normal_2
)
companion object {
@DrawableRes
fun getImageResourceId(isCompact: Boolean): Int {
return if (FeatureFlags.callsTab()) {
ThreeButtons.getImageResource(isCompact)
} else {
TwoButtons.getImageResource(isCompact)
}
}
}
}
companion object {
const val REQUEST_KEY = "ChooseNavigationBarStyle"
}
}

View File

@@ -23,7 +23,6 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.webrtc.CallBandwidthMode;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@SuppressWarnings("deprecation")
@@ -71,6 +70,7 @@ public final class SettingsValues extends SignalStoreValues {
private static final String SENT_MEDIA_QUALITY = "settings.sentMediaQuality";
private static final String CENSORSHIP_CIRCUMVENTION_ENABLED = "settings.censorshipCircumventionEnabled";
private static final String KEEP_MUTED_CHATS_ARCHIVED = "settings.keepMutedChatsArchived";
private static final String USE_COMPACT_NAVIGATION_BAR = "settings.useCompactNavigationBar";
private final SingleLiveEvent<String> onConfigurationSettingChanged = new SingleLiveEvent<>();
@@ -115,7 +115,8 @@ public final class SettingsValues extends SignalStoreValues {
NOTIFY_WHEN_CONTACT_JOINS_SIGNAL,
UNIVERSAL_EXPIRE_TIMER,
SENT_MEDIA_QUALITY,
KEEP_MUTED_CHATS_ARCHIVED);
KEEP_MUTED_CHATS_ARCHIVED,
USE_COMPACT_NAVIGATION_BAR);
}
public @NonNull LiveData<String> getOnConfigurationSettingChanged() {
@@ -455,6 +456,14 @@ public final class SettingsValues extends SignalStoreValues {
return getBoolean(KEEP_MUTED_CHATS_ARCHIVED, false);
}
public void setUseCompactNavigationBar(boolean enabled) {
putBoolean(USE_COMPACT_NAVIGATION_BAR, enabled);
}
public boolean getUseCompactNavigationBar() {
return getBoolean(USE_COMPACT_NAVIGATION_BAR, false);
}
private @Nullable Uri getUri(@NonNull String key) {
String uri = getString(key, "");

View File

@@ -6,6 +6,7 @@ import android.animation.ValueAnimator
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.content.ContextCompat
import androidx.core.view.animation.PathInterpolatorCompat
import androidx.fragment.app.Fragment
@@ -14,9 +15,11 @@ import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieProperty
import com.airbnb.lottie.model.KeyPath
import org.signal.core.util.DimensionUnit
import org.signal.core.util.dp
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.ViewBinderDelegate
import org.thoughtcrime.securesms.databinding.ConversationListTabsBinding
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.stories.Stories
import org.thoughtcrime.securesms.util.FeatureFlags
import org.thoughtcrime.securesms.util.visible
@@ -32,9 +35,15 @@ class ConversationListTabsFragment : Fragment(R.layout.conversation_list_tabs) {
private var shouldBeImmediate = true
private var pillAnimator: Animator? = null
private val largeConstraintSet: ConstraintSet = ConstraintSet()
private val smallConstraintSet: ConstraintSet = ConstraintSet()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val iconTint = ContextCompat.getColor(requireContext(), R.color.signal_colorOnSecondaryContainer)
largeConstraintSet.clone(binding.root)
smallConstraintSet.clone(requireContext(), R.layout.conversation_list_tabs_small)
binding.chatsTabIcon.addValueCallback(
KeyPath("**"),
LottieProperty.COLOR
@@ -76,6 +85,14 @@ class ConversationListTabsFragment : Fragment(R.layout.conversation_list_tabs) {
}
private fun updateTabsVisibility() {
if (SignalStore.settings().useCompactNavigationBar) {
smallConstraintSet.applyTo(binding.root)
binding.root.minHeight = 48.dp
} else {
largeConstraintSet.applyTo(binding.root)
binding.root.minHeight = 80.dp
}
listOf(
binding.callsPill,
binding.callsTabIcon,
@@ -98,6 +115,16 @@ class ConversationListTabsFragment : Fragment(R.layout.conversation_list_tabs) {
it.visible = Stories.isFeatureEnabled()
}
if (SignalStore.settings().useCompactNavigationBar) {
listOf(
binding.callsTabLabel,
binding.chatsTabLabel,
binding.storiesTabLabel
).forEach {
it.visible = false
}
}
update(viewModel.stateSnapshot, true)
}