From 3bdceac2fb0a835d1709ad4558c9dcc2dfee6f25 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Thu, 30 May 2024 14:39:36 +0300 Subject: [PATCH] Composer - Use sheet presentation on iOS (#4278) * use sheet presentation + tweak spacing * line up elements + add hitslop to cancel * fixing spacing on replies --- src/alf/util/useColorModeTheme.ts | 20 ++++++------ src/view/com/composer/Composer.tsx | 15 ++++----- src/view/com/composer/ComposerReplyTo.tsx | 3 +- src/view/shell/Composer.tsx | 38 +++++++++++++++++++---- 4 files changed, 51 insertions(+), 25 deletions(-) diff --git a/src/alf/util/useColorModeTheme.ts b/src/alf/util/useColorModeTheme.ts index 301c993dd4..ce15587478 100644 --- a/src/alf/util/useColorModeTheme.ts +++ b/src/alf/util/useColorModeTheme.ts @@ -7,19 +7,21 @@ import {useThemePrefs} from 'state/shell' import {dark, dim, light, ThemeName} from '#/alf/themes' export function useColorModeTheme(): ThemeName { - const colorScheme = useColorScheme() - const {colorMode, darkTheme} = useThemePrefs() + const theme = useThemeName() React.useLayoutEffect(() => { - const theme = getThemeName(colorScheme, colorMode, darkTheme) updateDocument(theme) SystemUI.setBackgroundColorAsync(getBackgroundColor(theme)) - }, [colorMode, colorScheme, darkTheme]) + }, [theme]) + + return theme +} + +export function useThemeName(): ThemeName { + const colorScheme = useColorScheme() + const {colorMode, darkTheme} = useThemePrefs() - return React.useMemo( - () => getThemeName(colorScheme, colorMode, darkTheme), - [colorScheme, colorMode, darkTheme], - ) + return getThemeName(colorScheme, colorMode, darkTheme) } function getThemeName( @@ -53,7 +55,7 @@ function updateDocument(theme: ThemeName) { } } -function getBackgroundColor(theme: ThemeName): string { +export function getBackgroundColor(theme: ThemeName): string { switch (theme) { case 'light': return light.atoms.bg.backgroundColor diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 4911adf2c4..2618c51a3d 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -54,7 +54,7 @@ import {useAgent, useSession} from '#/state/session' import {useComposerControls} from '#/state/shell/composer' import {useAnalytics} from 'lib/analytics/analytics' import * as apilib from 'lib/api/index' -import {MAX_GRAPHEME_LENGTH} from 'lib/constants' +import {HITSLOP_10, MAX_GRAPHEME_LENGTH} from 'lib/constants' import {useIsKeyboardVisible} from 'lib/hooks/useIsKeyboardVisible' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' @@ -165,9 +165,8 @@ export const ComposePost = observer(function ComposePost({ () => ({ paddingBottom: isAndroid || (isIOS && !isKeyboardVisible) ? insets.bottom : 0, - paddingTop: isMobile && isWeb ? 15 : insets.top, }), - [insets, isKeyboardVisible, isMobile], + [insets, isKeyboardVisible], ) const hasScrolled = useSharedValue(0) @@ -422,7 +421,8 @@ export const ComposePost = observer(function ComposePost({ accessibilityLabel={_(msg`Cancel`)} accessibilityHint={_( msg`Closes post composer and discards post draft`, - )}> + )} + hitSlop={HITSLOP_10}> Cancel @@ -622,10 +622,8 @@ const styles = StyleSheet.create({ topbar: { flexDirection: 'row', alignItems: 'center', - marginTop: -10, - paddingHorizontal: 4, marginHorizontal: 16, - height: 44, + height: 54, gap: 4, borderBottomWidth: StyleSheet.hairlineWidth, }, @@ -633,7 +631,6 @@ const styles = StyleSheet.create({ paddingTop: 10, paddingBottom: 10, height: 50, - marginTop: 0, }, postBtn: { borderRadius: 20, @@ -676,7 +673,7 @@ const styles = StyleSheet.create({ }, textInputLayout: { flexDirection: 'row', - paddingTop: 16, + paddingTop: 4, }, textInputLayoutMobile: { flex: 1, diff --git a/src/view/com/composer/ComposerReplyTo.tsx b/src/view/com/composer/ComposerReplyTo.tsx index 1bb4a5c21f..902d60a460 100644 --- a/src/view/com/composer/ComposerReplyTo.tsx +++ b/src/view/com/composer/ComposerReplyTo.tsx @@ -223,8 +223,9 @@ const styles = StyleSheet.create({ flexDirection: 'row', alignItems: 'flex-start', borderBottomWidth: StyleSheet.hairlineWidth, - paddingTop: 16, + paddingTop: 4, paddingBottom: 16, + marginBottom: 12, }, replyToPost: { flex: 1, diff --git a/src/view/shell/Composer.tsx b/src/view/shell/Composer.tsx index 17348a30ca..ce53ffc01d 100644 --- a/src/view/shell/Composer.tsx +++ b/src/view/shell/Composer.tsx @@ -1,11 +1,15 @@ -import React from 'react' +import React, {useLayoutEffect} from 'react' import {Modal, View} from 'react-native' +import {StatusBar} from 'expo-status-bar' +import * as SystemUI from 'expo-system-ui' import {observer} from 'mobx-react-lite' +import {isIOS} from '#/platform/detection' import {Provider as LegacyModalProvider} from '#/state/modals' -import {useComposerState} from 'state/shell/composer' +import {useComposerState} from '#/state/shell/composer' import {ModalsContainer as LegacyModalsContainer} from '#/view/com/modals/Modal' -import {useTheme} from '#/alf' +import {atoms as a, useTheme} from '#/alf' +import {getBackgroundColor, useThemeName} from '#/alf/util/useColorModeTheme' import { Outlet as PortalOutlet, Provider as PortalProvider, @@ -19,15 +23,17 @@ export const Composer = observer(function ComposerImpl({}: { const state = useComposerState() const ref = useComposerCancelRef() + const open = !!state + return ( ref.current?.onPressCancel()}> - + + {isIOS && } ) }) + +// Generally, the backdrop of the app is the theme color, but when this is open +// we want it to be black due to the modal being a form sheet. +function IOSModalBackground({active}: {active: boolean}) { + const theme = useThemeName() + + useLayoutEffect(() => { + SystemUI.setBackgroundColorAsync('black') + + return () => { + SystemUI.setBackgroundColorAsync(getBackgroundColor(theme)) + } + }, [theme]) + + // Set the status bar to light - however, only if the modal is active + // If we rely on this component being mounted to set this, + // there'll be a delay before it switches back to default. + return active ? : null +}