diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderReadingPreferencesDialogFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderReadingPreferencesDialogFragment.kt index 6e75a63af686..cf95d934f78f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderReadingPreferencesDialogFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderReadingPreferencesDialogFragment.kt @@ -2,6 +2,7 @@ package org.wordpress.android.ui.reader import android.app.Dialog import android.content.DialogInterface +import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -14,6 +15,7 @@ import androidx.compose.ui.platform.ComposeView import androidx.fragment.app.FragmentManager import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope +import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialogFragment import dagger.hilt.android.AndroidEntryPoint @@ -61,7 +63,7 @@ class ReaderReadingPreferencesDialogFragment : BottomSheetDialogFragment() { val isFeedbackEnabled by viewModel.isFeedbackEnabled.collectAsState() ReadingPreferencesScreen( currentReadingPreferences = readerPreferences, - onCloseClick = viewModel::saveReadingPreferencesAndClose, + onCloseClick = viewModel::onExitActionClick, onSendFeedbackClick = viewModel::onSendFeedbackClick, onThemeClick = viewModel::onThemeClick, onFontFamilyClick = viewModel::onFontFamilyClick, @@ -81,33 +83,53 @@ class ReaderReadingPreferencesDialogFragment : BottomSheetDialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = super.onCreateDialog(savedInstanceState).apply { - (this as? BottomSheetDialog)?.fillScreen() + (this as? BottomSheetDialog)?.apply { + fillScreen(isDraggable = true) + + behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { + private var isStatusBarTransparent = false + override fun onStateChanged(bottomSheet: View, newState: Int) { + if (newState == BottomSheetBehavior.STATE_EXPANDED && isStatusBarTransparent) { + isStatusBarTransparent = false + val currentTheme = viewModel.currentReadingPreferences.value.theme + handleUpdateStatusBarColor(currentTheme) + } else if (newState != BottomSheetBehavior.STATE_EXPANDED && !isStatusBarTransparent) { + isStatusBarTransparent = true + dialog?.window?.setWindowStatusBarColor(Color.TRANSPARENT) + } + + if (newState == BottomSheetBehavior.STATE_HIDDEN) { + viewModel.onBottomSheetHidden() + } + } + + override fun onSlide(bottomSheet: View, slideOffset: Float) { + // no-op + } + }) + } (this as ComponentDialog).onBackPressedDispatcher.addCallback(this@ReaderReadingPreferencesDialogFragment) { - viewModel.saveReadingPreferencesAndClose() + viewModel.onExitActionClick() } } override fun onDismiss(dialog: DialogInterface) { - super.onDismiss(dialog) viewModel.onScreenClosed() + super.onDismiss(dialog) } private fun observeActionEvents() { viewModel.actionEvents.onEach { when (it) { + is ActionEvent.Close -> dismiss() + is ActionEvent.UpdatePostDetails -> postDetailViewModel.onReadingPreferencesThemeChanged() is ActionEvent.UpdateStatusBarColor -> handleUpdateStatusBarColor(it.theme) - is ActionEvent.Close -> handleClose(it.isDirty) is ActionEvent.OpenWebView -> handleOpenWebView(it.url) } }.launchIn(viewLifecycleOwner.lifecycleScope) } - private fun handleClose(isDirty: Boolean) { - if (isDirty) postDetailViewModel.onReadingPreferencesThemeChanged() - dismiss() - } - private fun handleUpdateStatusBarColor(theme: ReaderReadingPreferences.Theme) { val context = requireContext() val themeValues = ReaderReadingPreferences.ThemeValues.from(context, theme) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/viewmodels/ReaderReadingPreferencesViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/viewmodels/ReaderReadingPreferencesViewModel.kt index c4e16cafa5d5..2865b81c803c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/viewmodels/ReaderReadingPreferencesViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/viewmodels/ReaderReadingPreferencesViewModel.kt @@ -47,6 +47,12 @@ class ReaderReadingPreferencesViewModel @Inject constructor( } fun onScreenClosed() { + if (isDirty()) { + // here we assume the code for saving preferences has been called before reaching this point + launch { + _actionEvents.emit(ActionEvent.UpdatePostDetails) + } + } readingPreferencesTracker.trackScreenClosed() } @@ -65,15 +71,24 @@ class ReaderReadingPreferencesViewModel @Inject constructor( readingPreferencesTracker.trackItemTapped(fontSize) } - fun saveReadingPreferencesAndClose() { + /** + * An exit action has been triggered by the user. This means that we need to save the current preferences and emit + * the close event, so the dialog is dismissed. + */ + fun onExitActionClick() { launch { - val currentPreferences = currentReadingPreferences.value - val isDirty = currentPreferences != originalReadingPreferences - if (isDirty) { - saveReadingPreferences(currentPreferences) - readingPreferencesTracker.trackSaved(currentPreferences) - } - _actionEvents.emit(ActionEvent.Close(isDirty)) + saveReadingPreferencesInternal() + _actionEvents.emit(ActionEvent.Close) + } + } + + /** + * The bottom sheet has been hidden by the user, which means the dismiss process is already on its way. All we need + * to do is save the current preferences. + */ + fun onBottomSheetHidden() { + launch { + saveReadingPreferencesInternal() } } @@ -84,8 +99,19 @@ class ReaderReadingPreferencesViewModel @Inject constructor( } } + private suspend fun saveReadingPreferencesInternal() { + val currentPreferences = currentReadingPreferences.value + if (isDirty()) { + saveReadingPreferences(currentPreferences) + readingPreferencesTracker.trackSaved(currentPreferences) + } + } + + private fun isDirty(): Boolean = currentReadingPreferences.value != originalReadingPreferences + sealed interface ActionEvent { - data class Close(val isDirty: Boolean) : ActionEvent + data object Close : ActionEvent + data object UpdatePostDetails : ActionEvent data class UpdateStatusBarColor(val theme: ReaderReadingPreferences.Theme) : ActionEvent data class OpenWebView(val url: String) : ActionEvent } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/views/compose/readingpreferences/ReadingPreferencesScreen.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/views/compose/readingpreferences/ReadingPreferencesScreen.kt index f7ae9bbac88b..b72cd7c503fe 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/views/compose/readingpreferences/ReadingPreferencesScreen.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/views/compose/readingpreferences/ReadingPreferencesScreen.kt @@ -30,8 +30,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.hapticfeedback.HapticFeedbackType +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalHapticFeedback +import androidx.compose.ui.platform.rememberNestedScrollInteropConnection import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.onClick import androidx.compose.ui.semantics.semantics @@ -88,7 +90,9 @@ fun ReadingPreferencesScreen( val haptics = LocalHapticFeedback.current.takeIf { isHapticsFeedbackEnabled } Column( - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .fillMaxSize() + .nestedScroll(rememberNestedScrollInteropConnection()), verticalArrangement = Arrangement.Top, horizontalAlignment = Alignment.CenterHorizontally, ) { diff --git a/WordPress/src/main/res/values/styles.xml b/WordPress/src/main/res/values/styles.xml index 859f0431d63f..996e5f7ae12a 100644 --- a/WordPress/src/main/res/values/styles.xml +++ b/WordPress/src/main/res/values/styles.xml @@ -1371,6 +1371,7 @@