diff --git a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt index 3aba37f2c8..91e5da0e58 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt @@ -61,6 +61,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.LocalResources import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.fragment.app.DialogFragment @@ -73,7 +74,6 @@ import androidx.lifecycle.createSavedStateHandle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.RecyclerView -import androidx.window.core.layout.WindowSizeClass import com.google.android.material.dialog.MaterialAlertDialogBuilder import io.reactivex.rxjava3.subjects.PublishSubject import io.reactivex.rxjava3.subjects.Subject @@ -88,6 +88,7 @@ import org.signal.core.ui.compose.Snackbars import org.signal.core.ui.compose.theme.SignalTheme import org.signal.core.ui.isSplitPane import org.signal.core.ui.permissions.Permissions +import org.signal.core.ui.rememberIsSplitPane import org.signal.core.util.Util import org.signal.core.util.concurrent.LifecycleDisposable import org.signal.core.util.getParcelableCompat @@ -429,11 +430,12 @@ class MainActivity : ) } + val isSplitPane = LocalResources.current.rememberIsSplitPane() val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass val contentLayoutData = MainContentLayoutData.rememberContentLayoutData(mainToolbarState.mode) MainContainer { - val wrappedNavigator = rememberNavigator(windowSizeClass, contentLayoutData, maxWidth) + val wrappedNavigator = rememberNavigator(isSplitPane, contentLayoutData, maxWidth) val listPaneWidth = contentLayoutData.rememberDefaultPanePreferredWidth(maxWidth) val navigationType = NavigationType.rememberNavigationType() @@ -478,7 +480,7 @@ class MainActivity : } } - val chatNavGraphState = ChatNavGraphState.remember(windowSizeClass) + val chatNavGraphState = ChatNavGraphState.remember(isSplitPane) val mutableInteractionSource = remember { MutableInteractionSource() } MainNavigationDetailLocationEffect(mainNavigationViewModel, chatNavGraphState::writeGraphicsLayerToBitmap) @@ -624,7 +626,7 @@ class MainActivity : onDestinationSelected = mainNavigationCallback ) - if (!windowSizeClass.isSplitPane()) { + if (!LocalResources.current.rememberIsSplitPane()) { Spacer(Modifier.navigationBarsPadding()) } } @@ -640,7 +642,7 @@ class MainActivity : } }, secondaryContent = { - val listContainerColor = if (windowSizeClass.isSplitPane()) { + val listContainerColor = if (isSplitPane) { SignalTheme.colors.colorSurface1 } else { MaterialTheme.colorScheme.surface @@ -781,12 +783,12 @@ class MainActivity : @OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable private fun rememberNavigator( - windowSizeClass: WindowSizeClass, + isSplitPane: Boolean, contentLayoutData: MainContentLayoutData, maxWidth: Dp ): AppScaffoldNavigator { val scaffoldNavigator = rememberThreePaneScaffoldNavigatorDelegate( - isSplitPane = windowSizeClass.isSplitPane(), + isSplitPane = isSplitPane, horizontalPartitionSpacerSize = contentLayoutData.partitionWidth, defaultPanePreferredWidth = contentLayoutData.rememberDefaultPanePreferredWidth(maxWidth) ) @@ -800,18 +802,18 @@ class MainActivity : @Composable private fun MainContainer(content: @Composable BoxWithConstraintsScope.() -> Unit) { - val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass + val isSplitPane = LocalResources.current.rememberIsSplitPane() CompositionLocalProvider(LocalSnackbarStateConsumerRegistry provides mainNavigationViewModel.snackbarRegistry) { SignalTheme { - val backgroundColor = if (!windowSizeClass.isSplitPane()) { + val backgroundColor = if (!isSplitPane) { MaterialTheme.colorScheme.surface } else { SignalTheme.colors.colorSurface1 } val modifier = when { - windowSizeClass.isSplitPane() -> { + isSplitPane -> { Modifier .systemBarsPadding() .displayCutoutPadding() diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/links/EditCallLinkNameDialogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/links/EditCallLinkNameDialogFragment.kt index bcae97a37b..1d9da50313 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/calls/links/EditCallLinkNameDialogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/calls/links/EditCallLinkNameDialogFragment.kt @@ -16,7 +16,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextField -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -27,6 +26,7 @@ import androidx.compose.ui.Alignment.Companion.End import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.platform.LocalResources import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextRange @@ -43,7 +43,7 @@ import org.signal.core.ui.compose.Buttons import org.signal.core.ui.compose.ComposeDialogFragment import org.signal.core.ui.compose.Scaffolds import org.signal.core.ui.compose.SignalIcons -import org.signal.core.ui.isSplitPane +import org.signal.core.ui.rememberIsSplitPane import org.signal.core.util.BreakIteratorCompat import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.calls.links.details.CallLinkDetailsViewModel @@ -109,7 +109,7 @@ fun EditCallLinkNameScreen( onNavigationClick = { backPressedDispatcherOwner?.onBackPressedDispatcher?.onBackPressed() }, - showNavigationIcon = !currentWindowAdaptiveInfo().windowSizeClass.isSplitPane() + showNavigationIcon = !LocalResources.current.rememberIsSplitPane() ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/links/details/CallLinkDetailsScreen.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/links/details/CallLinkDetailsScreen.kt index 13815b6271..34f25ccb93 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/calls/links/details/CallLinkDetailsScreen.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/calls/links/details/CallLinkDetailsScreen.kt @@ -15,12 +15,12 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SnackbarHostState -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalResources import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.core.app.ShareCompat @@ -37,7 +37,7 @@ import org.signal.core.ui.compose.Rows import org.signal.core.ui.compose.Scaffolds import org.signal.core.ui.compose.SignalIcons import org.signal.core.ui.compose.Snackbars -import org.signal.core.ui.isSplitPane +import org.signal.core.ui.rememberIsSplitPane import org.signal.core.util.Util import org.signal.core.util.concurrent.LifecycleDisposable import org.signal.ringrtc.CallLinkState.Restrictions @@ -83,7 +83,7 @@ fun CallLinkDetailsScreen( state = state, showAlreadyInACall = showAlreadyInACall, callback = callback, - showNavigationIcon = !currentWindowAdaptiveInfo().windowSizeClass.isSplitPane() + showNavigationIcon = !LocalResources.current.rememberIsSplitPane() ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogFragment.kt index f5c8bcfd21..fce3358a73 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogFragment.kt @@ -23,7 +23,6 @@ import io.reactivex.rxjava3.kotlin.subscribeBy import kotlinx.coroutines.launch import org.signal.core.ui.BottomSheetUtil import org.signal.core.ui.compose.Snackbars -import org.signal.core.ui.getWindowSizeClass import org.signal.core.ui.isSplitPane import org.signal.core.util.DimensionUnit import org.signal.core.util.concurrent.LifecycleDisposable @@ -133,7 +132,7 @@ class CallLogFragment : Fragment(R.layout.call_log_fragment), CallLogAdapter.Cal val filteredCount = callLogAdapter.submitCallRows( data, selected, - activeCallLogRowId = activeRowId.orNull().takeIf { resources.getWindowSizeClass().isSplitPane() }, + activeCallLogRowId = activeRowId.orNull().takeIf { resources.isSplitPane() }, viewModel.callLogPeekHelper.localDeviceCallRecipientId, scrollToPositionDelegate::notifyListCommitted ) @@ -187,7 +186,7 @@ class CallLogFragment : Fragment(R.layout.call_log_fragment), CallLogAdapter.Cal } } - if (!resources.getWindowSizeClass().isSplitPane()) { + if (!resources.isSplitPane()) { ViewUtil.setBottomMargin(binding.bottomActionBar, ViewUtil.getNavigationBarHeight(binding.bottomActionBar)) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt index 8426a0b02d..44e134401b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt @@ -30,7 +30,6 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import io.reactivex.rxjava3.kotlin.subscribeBy import kotlinx.coroutines.launch -import org.signal.core.ui.getWindowSizeClass import org.signal.core.ui.isSplitPane import org.signal.core.ui.permissions.Permissions import org.signal.core.util.DimensionUnit @@ -277,7 +276,7 @@ class ConversationSettingsFragment : views = listOf(toolbar!!), lifecycleOwner = viewLifecycleOwner, setStatusBarColor = { color -> - if (!resources.getWindowSizeClass().isSplitPane() || activity is ConversationSettingsActivity) { + if (!resources.isSplitPane() || activity is ConversationSettingsActivity) { WindowUtil.setStatusBarColor(requireActivity().window, color) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt index e81b35bb1e..c9eb826355 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt @@ -666,7 +666,7 @@ class ConversationFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { viewModel.resetBackPressedState() binding.toolbar.isBackInvokedCallbackEnabled = false - binding.root.setUseWindowTypes(args.conversationScreenType == ConversationScreenType.NORMAL && !resources.getWindowSizeClass().isSplitPane()) + binding.root.setUseWindowTypes(args.conversationScreenType == ConversationScreenType.NORMAL && !resources.isSplitPane()) if (args.conversationScreenType == ConversationScreenType.BUBBLE) { binding.root.setNavigationBarInsetOverride(0) view.post { @@ -1763,7 +1763,7 @@ class ConversationFragment : } private fun updateNavigationIconForNormal(isFullScreenPane: Boolean) { - if (!resources.getWindowSizeClass().isSplitPane() || isFullScreenPane) { + if (!resources.isSplitPane() || isFullScreenPane) { binding.toolbar.setNavigationIcon(CoreUiR.drawable.symbol_arrow_start_24) binding.toolbar.navigationIcon?.setTint( ContextCompat.getColor( @@ -4359,7 +4359,7 @@ class ConversationFragment : */ private fun navigateTo(location: MainNavigationDetailLocation.Chats) { val router = mainNavRouter - if (router != null && resources.getWindowSizeClass().isSplitPane()) { + if (router != null && resources.isSplitPane()) { router.goTo(location) } else { when (location) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java index fd1f30a6e7..74710bf035 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java @@ -459,7 +459,7 @@ public class ConversationListFragment extends MainFragment implements Conversati } })); - if (isSplitPane(getWindowSizeClass(getResources()))) { + if (isSplitPane(getResources())) { lifecycleDisposable.add(mainNavigationViewModel.getObservableActiveChatThreadId() .subscribeOn(AndroidSchedulers.mainThread()) .subscribe(defaultAdapter::setActiveThreadId)); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragmentExtensions.kt b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragmentExtensions.kt index faaa149bd5..007bb27395 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragmentExtensions.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragmentExtensions.kt @@ -15,7 +15,6 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch import org.greenrobot.eventbus.EventBus -import org.signal.core.ui.getWindowSizeClass import org.signal.core.ui.isSplitPane import org.thoughtcrime.securesms.main.MainNavigationDetailLocation @@ -36,7 +35,7 @@ fun Fragment.listenToEventBusWhileResumed( detailLocation .flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.RESUMED) .collectLatest { - if (!resources.getWindowSizeClass().isSplitPane()) { + if (!resources.isSplitPane()) { when (it) { is MainNavigationDetailLocation.Chats.Conversation -> unsubscribe() MainNavigationDetailLocation.Empty -> subscribe() diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/ChatsNavHost.kt b/app/src/main/java/org/thoughtcrime/securesms/main/ChatsNavHost.kt index 447931ff90..2ae5379750 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/ChatsNavHost.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/ChatsNavHost.kt @@ -43,11 +43,9 @@ import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable import androidx.navigation.toRoute -import androidx.window.core.layout.WindowSizeClass import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch -import org.signal.core.ui.isSplitPane import org.thoughtcrime.securesms.MainNavigator import org.thoughtcrime.securesms.components.settings.conversation.ConversationSettingsNavHostFragment import org.thoughtcrime.securesms.compose.FragmentBackHandler @@ -247,17 +245,17 @@ private fun Transition.chatAnimationState(hasFake: Boolean): AppScaffol */ @Stable class ChatNavGraphState private constructor( - val windowSizeClass: WindowSizeClass, + val isSplitPane: Boolean, val graphicsLayer: GraphicsLayer ) { companion object { @Composable - fun remember(windowSizeClass: WindowSizeClass): ChatNavGraphState { + fun remember(isSplitPane: Boolean): ChatNavGraphState { val graphicsLayer = rememberGraphicsLayer() - return remember(windowSizeClass) { + return remember(isSplitPane) { ChatNavGraphState( - windowSizeClass, + isSplitPane, graphicsLayer ) } @@ -271,7 +269,7 @@ class ChatNavGraphState private constructor( suspend fun writeGraphicsLayerToBitmap() { // toImageBitmap() uses LayerSnapshot which has format compatibility issues on Android 7 and below - if (Build.VERSION.SDK_INT >= 26 && !windowSizeClass.isSplitPane() && hasWrittenToGraphicsLayer) { + if (Build.VERSION.SDK_INT >= 26 && !isSplitPane && hasWrittenToGraphicsLayer) { chatBitmap = graphicsLayer.toImageBitmap() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainBottomChrome.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainBottomChrome.kt index 7c340fe05c..0f961449c7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainBottomChrome.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainBottomChrome.kt @@ -13,18 +13,19 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarResult -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalResources import org.signal.core.ui.compose.AllDevicePreviews import org.signal.core.ui.compose.Previews import org.signal.core.ui.compose.Snackbars import org.signal.core.ui.compose.showSnackbar import org.signal.core.ui.isSplitPane +import org.signal.core.ui.rememberIsSplitPane import org.thoughtcrime.securesms.components.snackbars.SnackbarHostKey import org.thoughtcrime.securesms.components.snackbars.rememberSnackbarState import org.thoughtcrime.securesms.megaphone.Megaphone @@ -64,7 +65,7 @@ fun MainBottomChrome( megaphoneActionController: MegaphoneActionController, modifier: Modifier = Modifier ) { - val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass + val isSplitPane = LocalResources.current.rememberIsSplitPane() val navigationType = NavigationType.rememberNavigationType() Column( @@ -92,7 +93,7 @@ fun MainBottomChrome( ) } - if (windowSizeClass.isSplitPane()) { + if (isSplitPane) { return@Column } diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainContentLayoutData.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainContentLayoutData.kt index 1059bad4e5..e1172cdbec 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainContentLayoutData.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainContentLayoutData.kt @@ -18,7 +18,7 @@ import androidx.compose.ui.unit.dp import androidx.window.core.layout.WindowSizeClass import org.signal.core.ui.WindowBreakpoint import org.signal.core.ui.getWindowBreakpoint -import org.signal.core.ui.isSplitPane +import org.signal.core.ui.rememberIsSplitPane private val MEDIUM_CONTENT_CORNERS = 18.dp private val EXTENDED_CONTENT_CORNERS = 14.dp @@ -47,7 +47,7 @@ data class MainContentLayoutData( */ @Composable fun hasDragHandle(): Boolean { - return currentWindowAdaptiveInfo().windowSizeClass.isSplitPane() + return LocalResources.current.rememberIsSplitPane() } /** @@ -55,11 +55,12 @@ data class MainContentLayoutData( */ @Composable fun rememberDefaultPanePreferredWidth(maxWidth: Dp): Dp { + val isSplitPane = LocalResources.current.rememberIsSplitPane() val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass return remember(maxWidth, windowSizeClass) { when { - !windowSizeClass.isSplitPane() -> maxWidth + !isSplitPane -> maxWidth windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_EXPANDED_LOWER_BOUND) -> 416.dp else -> (maxWidth - extraPadding) / 2f } @@ -75,9 +76,9 @@ data class MainContentLayoutData( val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass val resources = LocalResources.current val breakpoint = resources.getWindowBreakpoint() + val isSplitPane = resources.rememberIsSplitPane() - return remember(windowSizeClass, mode, breakpoint) { - val isSplitPane = windowSizeClass.isSplitPane() + return remember(windowSizeClass, mode, breakpoint, isSplitPane) { val isLargeWindowSize = breakpoint == WindowBreakpoint.LARGE MainContentLayoutData( diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/RecipientPickerScaffold.kt b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/RecipientPickerScaffold.kt index 11f062dbfd..df80258bfd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/RecipientPickerScaffold.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/RecipientPickerScaffold.kt @@ -26,6 +26,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalResources import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import org.signal.core.ui.compose.AllDevicePreviews @@ -34,6 +35,7 @@ import org.signal.core.ui.compose.Scaffolds import org.signal.core.ui.compose.SignalIcons import org.signal.core.ui.detailPaneMaxContentWidth import org.signal.core.ui.isSplitPane +import org.signal.core.ui.rememberIsSplitPane import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.components.compose.ScreenTitlePane import org.thoughtcrime.securesms.window.AppScaffold @@ -53,8 +55,8 @@ fun RecipientPickerScaffold( primaryContent: @Composable () -> Unit, floatingActionButton: (@Composable () -> Unit)? = null ) { + val isSplitPane = LocalResources.current.rememberIsSplitPane(forceSplitPane) val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass - val isSplitPane = windowSizeClass.isSplitPane(forceSplitPane = forceSplitPane) AppScaffold( topBarContent = { diff --git a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffold.kt b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffold.kt index b820259bef..f0b6c131a4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffold.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffold.kt @@ -49,6 +49,7 @@ import org.signal.core.ui.compose.Previews import org.signal.core.ui.getWindowBreakpoint import org.signal.core.ui.isSplitPane import org.signal.core.ui.isWidthExpanded +import org.signal.core.ui.rememberIsSplitPane import org.thoughtcrime.securesms.main.MainFloatingActionButtonsCallback import org.thoughtcrime.securesms.main.MainNavigationBar import org.thoughtcrime.securesms.main.MainNavigationRail @@ -274,10 +275,11 @@ private fun ListAndNavigation( private fun AppScaffoldPreview() { Previews.Preview { val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass + val isSplitPane = LocalResources.current.rememberIsSplitPane(false) AppScaffold( navigator = rememberAppScaffoldNavigator( - isSplitPane = windowSizeClass.isSplitPane(false), + isSplitPane = isSplitPane, defaultPanePreferredWidth = 416.dp, horizontalPartitionSpacerSize = 16.dp ), diff --git a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt index a7e607450c..b1f14b3d7c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt @@ -20,11 +20,13 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.platform.LocalResources import androidx.compose.ui.unit.Dp import androidx.window.core.layout.WindowSizeClass import org.signal.core.ui.horizontalPartitionDefaultSpacerSize import org.signal.core.ui.isSplitPane import org.signal.core.ui.listPaneDefaultPreferredWidth +import org.signal.core.ui.rememberIsSplitPane import org.thoughtcrime.securesms.keyvalue.SignalStore /** @@ -99,7 +101,7 @@ open class AppScaffoldNavigator @RememberInComposition constructor(private va @Composable fun rememberAppScaffoldNavigator( windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass, - isSplitPane: Boolean = windowSizeClass.isSplitPane( + isSplitPane: Boolean = LocalResources.current.rememberIsSplitPane( forceSplitPane = if (LocalInspectionMode.current) false else SignalStore.internal.forceSplitPane ), horizontalPartitionSpacerSize: Dp = windowSizeClass.horizontalPartitionDefaultSpacerSize, diff --git a/core/ui/src/main/java/org/signal/core/ui/FixedRoundedCornerBottomSheetDialogFragment.kt b/core/ui/src/main/java/org/signal/core/ui/FixedRoundedCornerBottomSheetDialogFragment.kt index bc94668176..3b68be8483 100644 --- a/core/ui/src/main/java/org/signal/core/ui/FixedRoundedCornerBottomSheetDialogFragment.kt +++ b/core/ui/src/main/java/org/signal/core/ui/FixedRoundedCornerBottomSheetDialogFragment.kt @@ -35,7 +35,7 @@ abstract class FixedRoundedCornerBottomSheetDialogFragment : BottomSheetDialogFr * Sheet corner radius in DP */ protected open val cornerRadius: Int - get() = if (resources.getWindowSizeClass().isSplitPane()) { + get() = if (resources.isSplitPane()) { 32 } else { 18 diff --git a/core/ui/src/main/java/org/signal/core/ui/WindowSizeClassExtensions.kt b/core/ui/src/main/java/org/signal/core/ui/WindowSizeClassExtensions.kt index 2a34aec6ce..14f3439a1b 100644 --- a/core/ui/src/main/java/org/signal/core/ui/WindowSizeClassExtensions.kt +++ b/core/ui/src/main/java/org/signal/core/ui/WindowSizeClassExtensions.kt @@ -15,6 +15,8 @@ import androidx.compose.ui.unit.dp import androidx.window.core.layout.WindowSizeClass import androidx.window.core.layout.computeWindowSizeClass +private const val TABLET_ASPECT_RATIO = 1.5f + val WindowSizeClass.listPaneDefaultPreferredWidth: Dp get() = if (isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_EXPANDED_LOWER_BOUND)) 416.dp else 316.dp val WindowSizeClass.horizontalPartitionDefaultSpacerSize: Dp get() = 12.dp val WindowSizeClass.detailPaneMaxContentWidth: Dp get() = 624.dp @@ -50,9 +52,7 @@ fun rememberWindowBreakpoint(): WindowBreakpoint { * [Resources] and window size class. * * This function uses several heuristics: - * - Returns [WindowBreakpoint.SMALL] if the width or height is compact. - * - Returns [WindowBreakpoint.LARGE] if the height is at least the expanded lower bound. - * - Returns [WindowBreakpoint.MEDIUM] if the width is at least the medium lower bound. + * - Returns [WindowBreakpoint.SMALL] if the width or height is compact * - Otherwise, falls back to aspect ratio heuristics: wider (≥ 1.5) is [WindowBreakpoint.LARGE], else [WindowBreakpoint.MEDIUM]. * * @return the inferred [WindowBreakpoint] for the current device. @@ -64,15 +64,11 @@ fun Resources.getWindowBreakpoint(): WindowBreakpoint { return WindowBreakpoint.SMALL } - if (windowSizeClass.isHeightAtLeastBreakpoint(WindowSizeClass.HEIGHT_DP_EXPANDED_LOWER_BOUND)) { - return WindowBreakpoint.LARGE - } - val numerator = maxOf(displayMetrics.widthPixels, displayMetrics.heightPixels) val denominator = minOf(displayMetrics.widthPixels, displayMetrics.heightPixels) val aspectRatio = numerator.toFloat() / denominator - return if (aspectRatio >= 1.5f) { + return if (aspectRatio >= TABLET_ASPECT_RATIO) { WindowBreakpoint.LARGE } else { WindowBreakpoint.MEDIUM @@ -92,19 +88,34 @@ enum class WindowBreakpoint { LARGE } +@Composable +fun Resources.rememberIsSplitPane( + forceSplitPane: Boolean = CoreUiDependencies.forceSplitPane +): Boolean { + return remember(this, forceSplitPane) { + isSplitPane(forceSplitPane) + } +} + /** * Determines whether the UI should display in split-pane mode based on available screen space. */ @JvmOverloads -fun WindowSizeClass.isSplitPane( +fun Resources.isSplitPane( forceSplitPane: Boolean = CoreUiDependencies.forceSplitPane ): Boolean { if (forceSplitPane) { return true } - return isAtLeastBreakpoint( - widthDpBreakpoint = WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND, - heightDpBreakpoint = WindowSizeClass.HEIGHT_DP_MEDIUM_LOWER_BOUND - ) + val breakpoint = getWindowBreakpoint() + if (breakpoint == WindowBreakpoint.SMALL) { + return false + } + + if (breakpoint == WindowBreakpoint.LARGE && displayMetrics.widthPixels < displayMetrics.heightPixels) { + return false + } + + return true }