Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
537cd20
fix: extract `stickToBottom` style to global stylesheet
chrispader Mar 14, 2025
300abcf
fix: make offline indicator translucent on edge-to-edge mode
chrispader Mar 14, 2025
0e81308
fix: make OfflineIndicator bottom sticky
chrispader Mar 14, 2025
e88ee6f
fix: use bottom safe area padding for navigation bar height instead o…
chrispader Mar 14, 2025
9eb3b3e
feat: add more customization to `useBottomSafeSafeAreaPaddingStyle`
chrispader Mar 14, 2025
819e202
refactor: use `useBottomSafeSafeAreaPaddingStyle` instead of custom l…
chrispader Mar 14, 2025
4bdb458
feat: add additional prop for applying extra offline indicator padding
chrispader Mar 14, 2025
a8ecc6b
fix: extract OfflineIndicator properties to variables
chrispader Mar 14, 2025
87537e5
fix: simplify offlineindicator styles
chrispader Mar 14, 2025
06ce141
fix: offline indicator on gesture bar
chrispader Mar 14, 2025
fd8cbb8
refactor: remove offline indicator variables
chrispader Mar 14, 2025
790add1
fix: simplify logic around sticky mobile offline indicator
chrispader Mar 14, 2025
b81d77f
Merge branch 'main' into @chrispader/fix-offline-indicator-positionin…
chrispader Mar 14, 2025
a29f061
fix: allow disabling offline indicator translucency
chrispader Mar 15, 2025
c17f484
fix: add missing safe area padding on iOS and fix background style
chrispader Mar 17, 2025
ba40cfb
fix: add offline indicator content padding by default
chrispader Mar 17, 2025
edb1c0a
Update useBottomSafeSafeAreaPaddingStyle.ts
chrispader Mar 17, 2025
4a36adb
Merge branch '@chrispader/form-wrapper-legacy-bottom-safe-area-handli…
chrispader Mar 18, 2025
f253538
Merge branch 'main' into @chrispader/fix-offline-indicator-positionin…
chrispader Mar 18, 2025
273f820
fix: only apply bottom safe area padding if bottom content is not app…
chrispader Mar 18, 2025
622abb9
fix: only show offline indicator when offline
chrispader Mar 18, 2025
c2139f0
Merge branch 'main' into @chrispader/fix-offline-indicator-positionin…
chrispader Mar 18, 2025
2588f37
docs: add `styleProperty` comment
chrispader Mar 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6860,6 +6860,8 @@ const CONST = {
SKIPPABLE_COLLECTION_MEMBER_IDS: [String(DEFAULT_NUMBER_ID), '-1', 'undefined', 'null', 'NaN'] as string[],
SETUP_SPECIALIST_LOGIN: 'Setup Specialist',
ILLUSTRATION_ASPECT_RATIO: 39 / 22,

OFFLINE_INDICATOR_HEIGHT: 25,
} as const;

type Country = keyof typeof CONST.ALL_COUNTRIES;
Expand Down
6 changes: 5 additions & 1 deletion src/components/BlockingViews/BlockingView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ type BaseBlockingViewProps = {

/** Whether to add bottom safe area padding to the view. */
addBottomSafeAreaPadding?: boolean;

/** Whether to add bottom safe area padding to the content. */
addOfflineIndicatorBottomSafeAreaPadding?: boolean;
};

type BlockingViewIconProps = {
Expand Down Expand Up @@ -100,6 +103,7 @@ function BlockingView({
contentFitImage,
containerStyle: containerStyleProp,
addBottomSafeAreaPadding = false,
addOfflineIndicatorBottomSafeAreaPadding = addBottomSafeAreaPadding,
}: BlockingViewProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
Expand Down Expand Up @@ -137,7 +141,7 @@ function BlockingView({
);
}, [styles, subtitleText, shouldEmbedLinkWithSubtitle, CustomSubtitle]);

const containerStyle = useBottomSafeSafeAreaPaddingStyle({addBottomSafeAreaPadding, style: containerStyleProp});
const containerStyle = useBottomSafeSafeAreaPaddingStyle({addBottomSafeAreaPadding, addOfflineIndicatorBottomSafeAreaPadding, style: containerStyleProp});

return (
<View style={[styles.flex1, styles.alignItemsCenter, styles.justifyContentCenter, styles.ph10, containerStyle]}>
Expand Down
5 changes: 5 additions & 0 deletions src/components/BlockingViews/FullPageNotFoundView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ type FullPageNotFoundViewProps = {

/** Whether to add bottom safe area padding to the view. */
addBottomSafeAreaPadding?: boolean;

/** Whether to add bottom safe area padding to the content. */
addOfflineIndicatorBottomSafeAreaPadding?: boolean;
};

// eslint-disable-next-line rulesdir/no-negated-variables
Expand All @@ -71,6 +74,7 @@ function FullPageNotFoundView({
subtitleStyle,
shouldDisplaySearchRouter,
addBottomSafeAreaPadding = true,
addOfflineIndicatorBottomSafeAreaPadding = addBottomSafeAreaPadding,
}: FullPageNotFoundViewProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
Expand Down Expand Up @@ -98,6 +102,7 @@ function FullPageNotFoundView({
onLinkPress={onLinkPress}
subtitleStyle={subtitleStyle}
addBottomSafeAreaPadding={addBottomSafeAreaPadding}
addOfflineIndicatorBottomSafeAreaPadding={addOfflineIndicatorBottomSafeAreaPadding}
/>
</View>
</ForceFullScreenView>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ import BlockingView from './BlockingView';
type FullPageOfflineBlockingViewProps = ChildrenProps & {
/** Whether to add bottom safe area padding to the view. */
addBottomSafeAreaPadding?: boolean;

/** Whether to add bottom safe area padding to the content. */
addOfflineIndicatorBottomSafeAreaPadding?: boolean;
};

function FullPageOfflineBlockingView({children, addBottomSafeAreaPadding = true}: FullPageOfflineBlockingViewProps) {
function FullPageOfflineBlockingView({children, addBottomSafeAreaPadding = true, addOfflineIndicatorBottomSafeAreaPadding = addBottomSafeAreaPadding}: FullPageOfflineBlockingViewProps) {
const {translate} = useLocalize();
const {isOffline} = useNetwork();

Expand All @@ -25,6 +28,7 @@ function FullPageOfflineBlockingView({children, addBottomSafeAreaPadding = true}
title={translate('common.youAppearToBeOffline')}
subtitle={translate('common.thisFeatureRequiresInternet')}
addBottomSafeAreaPadding={addBottomSafeAreaPadding}
addOfflineIndicatorBottomSafeAreaPadding={addOfflineIndicatorBottomSafeAreaPadding}
/>
);
}
Expand Down
2 changes: 2 additions & 0 deletions src/components/EmptyStateComponent/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ function EmptyStateComponent({
showsVerticalScrollIndicator,
minModalHeight = 400,
addBottomSafeAreaPadding = false,
addOfflineIndicatorBottomSafeAreaPadding = addBottomSafeAreaPadding,
}: EmptyStateComponentProps) {
const styles = useThemeStyles();
const [videoAspectRatio, setVideoAspectRatio] = useState(VIDEO_ASPECT_RATIO);
Expand Down Expand Up @@ -90,6 +91,7 @@ function EmptyStateComponent({
contentContainerStyle={[{minHeight: minModalHeight}, styles.flexGrow1, styles.flexShrink0, containerStyles]}
style={styles.flex1}
addBottomSafeAreaPadding={addBottomSafeAreaPadding}
addOfflineIndicatorBottomSafeAreaPadding={addOfflineIndicatorBottomSafeAreaPadding}
>
<View style={[styles.skeletonBackground, styles.overflowHidden]}>
<SkeletonComponent
Expand Down
3 changes: 3 additions & 0 deletions src/components/EmptyStateComponent/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ type SharedProps<T> = {

/** Whether to add bottom safe area padding to the view. */
addBottomSafeAreaPadding?: boolean;

/** Whether to add bottom safe area padding to the content. */
addOfflineIndicatorBottomSafeAreaPadding?: boolean;
};

type MediaType<HeaderMedia, T extends MediaTypes> = SharedProps<T> & {
Expand Down
42 changes: 22 additions & 20 deletions src/components/FixedFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type {ReactNode} from 'react';
import React, {useMemo} from 'react';
import type {StyleProp, ViewStyle} from 'react-native';
import {View} from 'react-native';
import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
import useBottomSafeSafeAreaPaddingStyle from '@hooks/useBottomSafeSafeAreaPaddingStyle';
import useThemeStyles from '@hooks/useThemeStyles';

type FixedFooterProps = {
Expand All @@ -15,31 +15,33 @@ type FixedFooterProps = {
/** Whether to add bottom safe area padding to the content. */
addBottomSafeAreaPadding?: boolean;

/** Whether to add bottom safe area padding to the content. */
addOfflineIndicatorBottomSafeAreaPadding?: boolean;

/** Whether to stick the footer to the bottom of the screen. */
shouldStickToBottom?: boolean;
};

function FixedFooter({style, children, addBottomSafeAreaPadding = false, shouldStickToBottom = false}: FixedFooterProps) {
function FixedFooter({
style,
children,
addBottomSafeAreaPadding = false,
addOfflineIndicatorBottomSafeAreaPadding = addBottomSafeAreaPadding,
shouldStickToBottom = false,
}: FixedFooterProps) {
const styles = useThemeStyles();
const {paddingBottom} = useSafeAreaPaddings(true);

const footerStyle = useMemo<StyleProp<ViewStyle>>(() => {
const totalPaddingBottom = styles.pb5.paddingBottom + paddingBottom;

// If the footer should stick to the bottom, we use absolute positioning instead of flex.
// In this case, we need to use style.bottom instead of style.paddingBottom.
if (shouldStickToBottom) {
return {position: 'absolute', left: 0, right: 0, bottom: addBottomSafeAreaPadding ? totalPaddingBottom : styles.pb5.paddingBottom};
}

// If the footer should not stick to the bottom, we use flex and add the safe area padding in styles.paddingBottom.
if (addBottomSafeAreaPadding) {
return {paddingBottom: totalPaddingBottom};
}

// Otherwise, we just use the default bottom padding.
return styles.pb5;
}, [addBottomSafeAreaPadding, paddingBottom, shouldStickToBottom, styles.pb5]);
const bottomSafeAreaPaddingStyle = useBottomSafeSafeAreaPaddingStyle({
addBottomSafeAreaPadding,
addOfflineIndicatorBottomSafeAreaPadding,
additionalPaddingBottom: styles.pb5.paddingBottom,
styleProperty: shouldStickToBottom ? 'bottom' : 'paddingBottom',
});

const footerStyle = useMemo<StyleProp<ViewStyle>>(
() => [shouldStickToBottom && styles.stickToBottom, bottomSafeAreaPaddingStyle],
[bottomSafeAreaPaddingStyle, shouldStickToBottom, styles.stickToBottom],
);

if (!children) {
return null;
Expand Down
3 changes: 3 additions & 0 deletions src/components/Form/FormProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ type FormProviderProps<TFormID extends OnyxFormKey = OnyxFormKey> = FormProps<TF
/** Whether to add bottom safe area padding to the content. */
addBottomSafeAreaPadding?: boolean;

/** Whether to add bottom safe area padding to the content. */
addOfflineIndicatorBottomSafeAreaPadding?: boolean;

/** Whether the submit button should stick to the bottom of the screen. */
shouldSubmitButtonStickToBottom?: boolean;
};
Expand Down
12 changes: 9 additions & 3 deletions src/components/Form/FormWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ type FormWrapperProps = ChildrenProps &
/** If enabled, the content will have a bottom padding equal to account for the safe bottom area inset. */
addBottomSafeAreaPadding?: boolean;

/** Whether to add bottom safe area padding to the content. */
addOfflineIndicatorBottomSafeAreaPadding?: boolean;

/** Whether the submit button should stick to the bottom of the screen. */
shouldSubmitButtonStickToBottom?: boolean;
};
Expand All @@ -69,6 +72,7 @@ function FormWrapper({
isLoading = false,
shouldScrollToEnd = false,
addBottomSafeAreaPadding,
addOfflineIndicatorBottomSafeAreaPadding: addOfflineIndicatorBottomSafeAreaPaddingProp,
shouldSubmitButtonStickToBottom: shouldSubmitButtonStickToBottomProp,
}: FormWrapperProps) {
const styles = useThemeStyles();
Expand Down Expand Up @@ -121,6 +125,7 @@ function FormWrapper({
// If the paddingBottom is 0, it has already been applied to a parent component and we don't want to apply the padding again.
const isLegacyBottomSafeAreaPaddingAlreadyApplied = paddingBottom === 0;
const shouldApplyBottomSafeAreaPadding = addBottomSafeAreaPadding ?? !isLegacyBottomSafeAreaPaddingAlreadyApplied;
const addOfflineIndicatorBottomSafeAreaPadding = addOfflineIndicatorBottomSafeAreaPaddingProp ?? addBottomSafeAreaPadding === true;

const SubmitButton = useMemo(
() =>
Expand All @@ -141,10 +146,8 @@ function FormWrapper({
submitButtonStyles,
shouldSubmitButtonStickToBottom
? [
styles.stickToBottom,
{
position: 'absolute',
left: 0,
right: 0,
bottom: styles.pb5.paddingBottom + paddingBottom,
},
style,
Expand Down Expand Up @@ -180,6 +183,7 @@ function FormWrapper({
styles.mh0,
styles.mt5,
styles.pb5.paddingBottom,
styles.stickToBottom,
submitButtonStyles,
submitButtonText,
submitFlexEnabled,
Expand Down Expand Up @@ -231,6 +235,7 @@ function FormWrapper({
contentContainerStyle={styles.flexGrow1}
keyboardShouldPersistTaps="handled"
addBottomSafeAreaPadding={shouldApplyBottomSafeAreaPadding}
addOfflineIndicatorBottomSafeAreaPadding={addOfflineIndicatorBottomSafeAreaPadding}
ref={formRef}
>
{scrollViewContent()}
Expand All @@ -241,6 +246,7 @@ function FormWrapper({
contentContainerStyle={styles.flexGrow1}
keyboardShouldPersistTaps="handled"
addBottomSafeAreaPadding={shouldApplyBottomSafeAreaPadding}
addOfflineIndicatorBottomSafeAreaPadding={addOfflineIndicatorBottomSafeAreaPadding}
ref={formRef}
>
{scrollViewContent()}
Expand Down
9 changes: 4 additions & 5 deletions src/components/NavigationBar/index.android.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@ import {useMemo} from 'react';
import {View} from 'react-native';
import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';

/** NavigationBar renders a semi-translucent background behind the three-button navigation bar on Android. */
function NavigationBar() {
const theme = useTheme();
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {insets} = useSafeAreaPaddings();
const {insets, paddingBottom} = useSafeAreaPaddings();

const navigationBarType = useMemo(() => StyleUtils.getNavigationBarType(insets), [StyleUtils, insets]);

const isSoftKeyNavigation = navigationBarType === CONST.NAVIGATION_BAR_TYPE.SOFT_KEYS;

return isSoftKeyNavigation ? <View style={[{position: 'absolute', bottom: 0, left: 0, right: 0, height: insets.bottom, backgroundColor: theme.navigationBarBackgroundColor}]} /> : null;
return isSoftKeyNavigation ? <View style={[styles.navigationBarBG, styles.stickToBottom, {height: paddingBottom}]} /> : null;
}
NavigationBar.displayName = 'NavigationBar';

Expand Down
16 changes: 9 additions & 7 deletions src/components/OfflineIndicator.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React from 'react';
import React, {useMemo} from 'react';
import type {StyleProp, ViewStyle} from 'react-native';
import {View} from 'react-native';
import useBottomSafeSafeAreaPaddingStyle from '@hooks/useBottomSafeSafeAreaPaddingStyle';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import variables from '@styles/variables';
Expand All @@ -21,26 +20,29 @@ type OfflineIndicatorProps = {

/** Whether to add bottom safe area padding to the view. */
addBottomSafeAreaPadding?: boolean;

/** Whether to make the indicator translucent. */
isTranslucent?: boolean;
};

function OfflineIndicator({style, containerStyles, addBottomSafeAreaPadding = false}: OfflineIndicatorProps) {
function OfflineIndicator({style, containerStyles: containerStylesProp, addBottomSafeAreaPadding = false, isTranslucent = false}: OfflineIndicatorProps) {
const theme = useTheme();
const styles = useThemeStyles();
const {translate} = useLocalize();
const {isOffline} = useNetwork();
const {shouldUseNarrowLayout} = useResponsiveLayout();

const computedStyles = useBottomSafeSafeAreaPaddingStyle({
const fallbackStyle = useMemo(() => [styles.offlineIndicatorContainer, containerStylesProp], [styles.offlineIndicatorContainer, containerStylesProp]);
const containerStyles = useBottomSafeSafeAreaPaddingStyle({
addBottomSafeAreaPadding,
style: containerStyles ?? (shouldUseNarrowLayout ? styles.offlineIndicatorMobile : styles.offlineIndicator),
style: fallbackStyle,
});

if (!isOffline) {
return null;
}

return (
<View style={[computedStyles, styles.flexRow, styles.alignItemsCenter, style]}>
<View style={[containerStyles, isTranslucent && styles.navigationBarBG, styles.flexRow, styles.alignItemsCenter, style]}>
<Icon
fill={theme.icon}
src={Expensicons.OfflineCloud}
Expand Down
Loading