Fix bottomSheet bottom insets (#8331)

* Fix bottomSheet bottom insets

* fix search team picker on android

* ux review

* fix footer padding for message priority modal on iPad
This commit is contained in:
Elias Nahum 2024-11-29 12:50:09 +08:00 committed by GitHub
parent d25c6fe245
commit 7cb2ee75b3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
56 changed files with 155 additions and 194 deletions

View file

@ -9,7 +9,6 @@ import {
View,
} from 'react-native';
import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {dismissAnnouncement} from '@actions/local/systems';
import CompassIcon from '@components/compass_icon';
@ -85,7 +84,6 @@ const AnnouncementBanner = ({
const intl = useIntl();
const serverUrl = useServerUrl();
const height = useSharedValue(0);
const {bottom} = useSafeAreaInsets();
const theme = useTheme();
const [visible, setVisible] = useState(false);
const style = getStyle(theme);
@ -107,7 +105,6 @@ const AnnouncementBanner = ({
const snapPoint = bottomSheetSnapPoint(
1,
SNAP_POINT_WITHOUT_DISMISS + (allowDismissal ? DISMISS_BUTTON_HEIGHT : 0),
bottom,
);
bottomSheet({
@ -117,7 +114,7 @@ const AnnouncementBanner = ({
snapPoints: [1, snapPoint],
theme,
});
}, [theme.sidebarHeaderTextColor, intl.locale, renderContent, allowDismissal, bottom]);
}, [theme.sidebarHeaderTextColor, intl.locale, renderContent, allowDismissal]);
const handleDismiss = useCallback(() => {
dismissAnnouncement(serverUrl, bannerText);

View file

@ -3,14 +3,13 @@
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {Alert, View, type Insets} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {Alert, Platform, View, type Insets} from 'react-native';
import Button from '@components/button';
import {ITEM_HEIGHT} from '@components/option_item';
import {Screens} from '@constants';
import {useTheme} from '@context/theme';
import {TITLE_HEIGHT} from '@screens/bottom_sheet';
import {BOTTOM_SHEET_ANDROID_OFFSET, TITLE_HEIGHT} from '@screens/bottom_sheet';
import {bottomSheet, showModal} from '@screens/navigation';
import {bottomSheetSnapPoint} from '@utils/helpers';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
@ -81,7 +80,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => ({
const AddBookmark = ({bookmarksCount, channelId, currentUserId, canUploadFiles, showLarge}: Props) => {
const theme = useTheme();
const {formatMessage} = useIntl();
const {bottom} = useSafeAreaInsets();
const styles = getStyleSheet(theme);
const onPress = useCallback(() => {
@ -126,14 +124,19 @@ const AddBookmark = ({bookmarksCount, channelId, currentUserId, canUploadFiles,
/>
);
let height = bottomSheetSnapPoint(1, (2 * ITEM_HEIGHT)) + TITLE_HEIGHT;
if (Platform.OS === 'android') {
height += BOTTOM_SHEET_ANDROID_OFFSET;
}
bottomSheet({
title: formatMessage({id: 'channel_info.add_bookmark', defaultMessage: 'Add a bookmark'}),
renderContent,
snapPoints: [1, bottomSheetSnapPoint(1, (2 * ITEM_HEIGHT), bottom) + TITLE_HEIGHT],
snapPoints: [1, height],
theme,
closeButtonId: 'close-channel-quick-actions',
});
}, [bottom, bookmarksCount, canUploadFiles, currentUserId, channelId, theme]);
}, [bookmarksCount, canUploadFiles, formatMessage, theme, channelId, currentUserId]);
const button = (
<Button

View file

@ -7,7 +7,6 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {useIntl, type IntlShape} from 'react-intl';
import {Alert, StyleSheet} from 'react-native';
import Animated from 'react-native-reanimated';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {ITEM_HEIGHT} from '@components/option_item';
import {useServerUrl} from '@context/server';
@ -90,7 +89,6 @@ const ChannelBookmark = ({
const managedConfig = useManagedConfig<ManagedConfig>();
const serverUrl = useServerUrl();
const intl = useIntl();
const {bottom} = useSafeAreaInsets();
const [action, setAction] = useState<GalleryAction>('none');
const isDocumentFile = useMemo(() => isDocument(file), [file]);
const canCopyPublicLink = Boolean((bookmark.type === 'link' || (file?.id && publicLinkEnabled)) && managedConfig.copyAndPasteProtection !== 'true');
@ -124,11 +122,11 @@ const ChannelBookmark = ({
bottomSheet({
title: bookmark.displayName,
renderContent,
snapPoints: [1, bottomSheetSnapPoint(1, (count * ITEM_HEIGHT), bottom) + TITLE_HEIGHT],
snapPoints: [1, bottomSheetSnapPoint(1, (count * ITEM_HEIGHT)) + TITLE_HEIGHT],
theme,
closeButtonId: 'close-channel-bookmark-actions',
});
}, [bookmark, bottom, canCopyPublicLink, canDeleteBookmarks, canDownloadFiles, canEditBookmarks, file, theme]);
}, [bookmark, canCopyPublicLink, canDeleteBookmarks, canDownloadFiles, canEditBookmarks, file, theme]);
const {onGestureEvent, ref} = useGalleryItem(galleryIdentifier, index || 0, handlePress);

View file

@ -101,8 +101,9 @@ const ChannelBookmarks = ({
/>
);
}, [
attachmentIndex, bookmarks, canDownloadFiles, canDeleteBookmarks, canEditBookmarks,
handlePreviewPress, publicLinkEnabled,
canDeleteBookmarks, canDownloadFiles, canEditBookmarks,
galleryIdentifier, attachmentIndex, handlePreviewPress,
publicLinkEnabled,
]);
const renderItemSeparator = useCallback(() => (<View style={styles.emptyItemSeparator}/>), []);

View file

@ -10,11 +10,9 @@ import Header, {HEADER_HEIGHT} from './header';
import OptionMenus from './option_menus';
import type {GalleryAction} from '@typings/screens/gallery';
import type {EdgeInsets} from 'react-native-safe-area-context';
type Props = {
fileInfo: FileInfo;
insets: EdgeInsets;
numOptions: number;
setAction: (action: GalleryAction) => void;
theme: Theme;
@ -22,7 +20,6 @@ type Props = {
export const showMobileOptionsBottomSheet = ({
fileInfo,
insets,
numOptions,
setAction,
theme,
@ -42,7 +39,7 @@ export const showMobileOptionsBottomSheet = ({
renderContent,
snapPoints: [
1,
bottomSheetSnapPoint(numOptions, ITEM_HEIGHT, insets.bottom) + HEADER_HEIGHT,
bottomSheetSnapPoint(numOptions, ITEM_HEIGHT) + HEADER_HEIGHT,
],
theme,
title: '',

View file

@ -99,7 +99,6 @@ const FileResults = ({
if (!isTablet) {
showMobileOptionsBottomSheet({
fileInfo: fInfo,
insets,
numOptions,
setAction,
theme,

View file

@ -6,7 +6,6 @@ import Clipboard from '@react-native-clipboard/clipboard';
import React, {useCallback, useEffect, useMemo} from 'react';
import {useIntl} from 'react-intl';
import {type GestureResponderEvent, Keyboard, type StyleProp, StyleSheet, Text, type TextStyle, View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {fetchUserOrGroupsByMentionsInBatch} from '@actions/remote/user';
import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item';
@ -62,7 +61,6 @@ const AtMention = ({
const intl = useIntl();
const managedConfig = useManagedConfig<ManagedConfig>();
const theme = useTheme();
const {bottom} = useSafeAreaInsets();
const serverUrl = useServerUrl();
const user = useMemoMentionedUser(users, mentionName);
@ -144,12 +142,12 @@ const AtMention = ({
bottomSheet({
closeButtonId: 'close-at-mention',
renderContent,
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT, bottom)],
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT)],
title: intl.formatMessage({id: 'post.options.title', defaultMessage: 'Options'}),
theme,
});
}
}, [managedConfig, intl, theme, bottom]);
}, [managedConfig?.copyAndPasteProtection, intl, theme, mentionName, user?.username]);
const mentionTextStyle: StyleProp<TextStyle> = [];

View file

@ -6,7 +6,6 @@ import Clipboard from '@react-native-clipboard/clipboard';
import React, {useCallback, useMemo} from 'react';
import {useIntl} from 'react-intl';
import {Keyboard, StyleSheet, Text, type TextStyle, TouchableOpacity, View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import FormattedText from '@components/formatted_text';
import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item';
@ -71,7 +70,6 @@ const MarkdownCodeBlock = ({language = '', content, textStyle}: MarkdownCodeBloc
const intl = useIntl();
const managedConfig = useManagedConfig<ManagedConfig>();
const theme = useTheme();
const {bottom} = useSafeAreaInsets();
const style = getStyleSheet(theme);
const SyntaxHighlighter = useMemo(() => {
if (!syntaxHighlighter) {
@ -147,12 +145,12 @@ const MarkdownCodeBlock = ({language = '', content, textStyle}: MarkdownCodeBloc
bottomSheet({
closeButtonId: 'close-code-block',
renderContent,
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT, bottom)],
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT)],
title: intl.formatMessage({id: 'post.options.title', defaultMessage: 'Options'}),
theme,
});
}
}, [managedConfig, intl, bottom, theme]);
}, [managedConfig?.copyAndPasteProtection, intl, theme, style.bottomSheet, content]);
const trimContent = (text: string) => {
const lines = text.split('\n');

View file

@ -7,7 +7,6 @@ import React, {useCallback, useMemo, useRef, useState} from 'react';
import {useIntl} from 'react-intl';
import {Alert, Platform, type StyleProp, Text, type TextStyle, TouchableWithoutFeedback, View} from 'react-native';
import Animated from 'react-native-reanimated';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {SvgUri} from 'react-native-svg';
import parseUrl from 'url-parse';
@ -76,7 +75,6 @@ const MarkdownImage = ({
}: MarkdownImageProps) => {
const intl = useIntl();
const isTablet = useIsTablet();
const {bottom} = useSafeAreaInsets();
const theme = useTheme();
const style = getStyleSheet(theme);
const managedConfig = useManagedConfig<ManagedConfig>();
@ -182,12 +180,12 @@ const MarkdownImage = ({
bottomSheet({
closeButtonId: 'close-mardown-image',
renderContent,
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT, bottom)],
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT)],
title: intl.formatMessage({id: 'post.options.title', defaultMessage: 'Options'}),
theme,
});
}
}, [managedConfig, intl.locale, bottom, theme]);
}, [managedConfig?.copyAndPasteProtection, intl, theme, style.bottomSheet, linkDestination, source]);
const handleOnError = useCallback(() => {
setFailed(true);

View file

@ -6,7 +6,6 @@ import Clipboard from '@react-native-clipboard/clipboard';
import React, {useCallback, useMemo} from 'react';
import {useIntl} from 'react-intl';
import {Keyboard, View, Text, StyleSheet, Platform} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import FormattedText from '@components/formatted_text';
import ErrorBoundary from '@components/markdown/error_boundary';
@ -90,7 +89,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
const LatexCodeBlock = ({content, theme}: Props) => {
const intl = useIntl();
const {bottom} = useSafeAreaInsets();
const managedConfig = useManagedConfig<ManagedConfig>();
const styles = getStyleSheet(theme);
const languageDisplayName = getHighlightLanguageName('latex');
@ -161,12 +159,12 @@ const LatexCodeBlock = ({content, theme}: Props) => {
bottomSheet({
closeButtonId: 'close-code-block',
renderContent,
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT, bottom)],
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT)],
title: intl.formatMessage({id: 'post.options.title', defaultMessage: 'Options'}),
theme,
});
}
}, [managedConfig?.copyAndPasteProtection, intl, bottom, theme]);
}, [managedConfig?.copyAndPasteProtection, intl, theme, styles.bottomSheet, content]);
const onRenderErrorMessage = useCallback(({error}: {error: Error}) => {
return <Text style={styles.errorText}>{'Render error: ' + error.message}</Text>;

View file

@ -6,7 +6,6 @@ import Clipboard from '@react-native-clipboard/clipboard';
import React, {Children, type ReactElement, useCallback} from 'react';
import {useIntl} from 'react-intl';
import {Alert, StyleSheet, Text, View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import urlParse from 'url-parse';
import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item';
@ -47,7 +46,6 @@ const parseLinkLiteral = (literal: string) => {
const MarkdownLink = ({children, experimentalNormalizeMarkdownLinks, href, siteURL, onLinkLongPress}: MarkdownLinkProps) => {
const intl = useIntl();
const {bottom} = useSafeAreaInsets();
const managedConfig = useManagedConfig<ManagedConfig>();
const serverUrl = useServerUrl();
const theme = useTheme();
@ -146,12 +144,12 @@ const MarkdownLink = ({children, experimentalNormalizeMarkdownLinks, href, siteU
bottomSheet({
closeButtonId: 'close-mardown-link',
renderContent,
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT, bottom)],
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT)],
title: intl.formatMessage({id: 'post.options.title', defaultMessage: 'Options'}),
theme,
});
}
}, [managedConfig, intl, bottom, theme, onLinkLongPress]);
}, [managedConfig?.copyAndPasteProtection, onLinkLongPress, intl, theme, href]);
const renderChildren = experimentalNormalizeMarkdownLinks ? parseChildren() : children;

View file

@ -4,7 +4,6 @@
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {Alert, StyleSheet} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import CompassIcon from '@components/compass_icon';
import {ITEM_HEIGHT} from '@components/slide_up_panel_item';
@ -40,7 +39,6 @@ export default function CameraQuickAction({
}: QuickActionAttachmentProps) {
const intl = useIntl();
const theme = useTheme();
const {bottom} = useSafeAreaInsets();
const handleButtonPress = useCallback((options: CameraOptions) => {
const picker = new PickerUtil(intl,
@ -72,11 +70,11 @@ export default function CameraQuickAction({
bottomSheet({
title: intl.formatMessage({id: 'mobile.camera_type.title', defaultMessage: 'Camera options'}),
renderContent,
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT, bottom) + TITLE_HEIGHT],
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT) + TITLE_HEIGHT],
theme,
closeButtonId: 'camera-close-id',
});
}, [intl, theme, renderContent, maxFilesReached, maxFileCount, bottom]);
}, [intl, theme, renderContent, maxFilesReached, maxFileCount]);
const actionTestID = disabled ? `${testID}.disabled` : testID;
const color = disabled ? changeOpacity(theme.centerChannelColor, 0.16) : changeOpacity(theme.centerChannelColor, 0.64);

View file

@ -55,7 +55,7 @@ export default function PostPriorityAction({
closeButtonId: POST_PRIORITY_PICKER_BUTTON,
},
});
}, [intl, postPriority, updatePostPriority, theme]);
}, [isTablet, intl, theme, postPriority, updatePostPriority]);
const iconName = 'alert-circle-outline';
const iconColor = changeOpacity(theme.centerChannelColor, 0.64);

View file

@ -4,7 +4,6 @@
import React, {useCallback, useMemo} from 'react';
import {useIntl} from 'react-intl';
import {View, Text, TouchableOpacity, useWindowDimensions} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {acknowledgePost, unacknowledgePost} from '@actions/remote/post';
import {fetchMissingProfilesByIds} from '@actions/remote/user';
@ -75,7 +74,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
const Acknowledgements = ({currentUserId, currentUserTimezone, hasReactions, location, post, theme}: Props) => {
const intl = useIntl();
const isTablet = useIsTablet();
const {bottom} = useSafeAreaInsets();
const serverUrl = useServerUrl();
const {height} = useWindowDimensions();
@ -143,7 +141,7 @@ const Acknowledgements = ({currentUserId, currentUserTimezone, hasReactions, loc
</>
);
const snapPoint1 = bottomSheetSnapPoint(Math.min(userIds.length, 5), USER_ROW_HEIGHT, bottom) + TITLE_HEIGHT;
const snapPoint1 = bottomSheetSnapPoint(Math.min(userIds.length, 5), USER_ROW_HEIGHT) + TITLE_HEIGHT;
const snapPoint2 = height * 0.8;
const snapPoints: number[] = [1, Math.min(snapPoint1, snapPoint2)];
if (userIds.length > 5 && snapPoint1 < snapPoint2) {
@ -158,7 +156,11 @@ const Acknowledgements = ({currentUserId, currentUserTimezone, hasReactions, loc
title: intl.formatMessage({id: 'mobile.acknowledgements.header', defaultMessage: 'Acknowledgements'}),
theme,
});
}, [bottom, intl, isTablet, acknowledgements, theme, location, post.channelId, currentUserTimezone]);
}, [
acknowledgements, height, intl,
theme, serverUrl, isTablet, style.listHeaderText,
post.channelId, location, currentUserTimezone,
]);
return (
<>

View file

@ -62,7 +62,7 @@ const UserListItem = ({
Keyboard.dismiss();
openAsBottomSheet({screen, title, theme, closeButtonId, props});
}
}, [channelId, location]);
}, [channelId, intl, location, theme]);
return (
<UserItem

View file

@ -4,7 +4,6 @@
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {StyleSheet, TouchableOpacity, View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {removePost} from '@actions/local/post';
import {retryFailedPost} from '@actions/remote/post';
@ -33,7 +32,6 @@ const styles = StyleSheet.create({
const Failed = ({post, theme}: FailedProps) => {
const intl = useIntl();
const {bottom} = useSafeAreaInsets();
const serverUrl = useServerUrl();
const onPress = useCallback(() => {
@ -69,11 +67,11 @@ const Failed = ({post, theme}: FailedProps) => {
bottomSheet({
closeButtonId: 'close-post-failed',
renderContent,
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT, bottom)],
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT)],
title: intl.formatMessage({id: 'post.options.title', defaultMessage: 'Options'}),
theme,
});
}, [bottom]);
}, [intl, post, serverUrl, theme]);
return (
<TouchableOpacity

View file

@ -98,7 +98,7 @@ const Reactions = ({currentUserId, canAddReaction, canRemoveReaction, disabled,
}, new Map<string, ReactionModel[]>());
return {reactionsByName, highlightedReactions};
}, [sortedReactions, reactions]);
}, [reactions, currentUserId]);
const handleToggleReactionToPost = (emoji: string) => {
toggleReaction(serverUrl, postId, emoji);

View file

@ -152,7 +152,7 @@ const Footer = ({channelId, location, participants, teamId, thread}: Props) => {
return orderedParticipantsList;
}
return [];
}, [participants.length]);
}, [participants]);
let userAvatarsStack;
if (participantsList.length) {

View file

@ -10,7 +10,7 @@ import Button from '@components/button';
import {USER_CHIP_BOTTOM_MARGIN, USER_CHIP_HEIGHT} from '@components/selected_chip';
import Toast from '@components/toast';
import {useTheme} from '@context/theme';
import {useKeyboardHeightWithDuration} from '@hooks/device';
import {useIsTablet, useKeyboardHeightWithDuration} from '@hooks/device';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import SelectedUser from './selected_user';
@ -92,7 +92,7 @@ const SCROLL_MARGIN_BOTTOM = 12;
const USERS_CHIPS_MAX_HEIGHT = (CHIP_HEIGHT_WITH_MARGIN * MAX_CHIP_ROWS) + EXPOSED_CHIP_HEIGHT;
const SCROLL_MAX_HEIGHT = USERS_CHIPS_MAX_HEIGHT + SCROLL_MARGIN_TOP + SCROLL_MARGIN_BOTTOM;
const PANEL_MAX_HEIGHT = SCROLL_MAX_HEIGHT + BUTTON_HEIGHT;
const TABLET_MARGIN_BOTTOM = 20;
const MARGIN_BOTTOM = 20;
const TOAST_BOTTOM_MARGIN = 24;
const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
@ -155,6 +155,7 @@ export default function SelectedUsers({
const theme = useTheme();
const style = getStyleFromTheme(theme);
const keyboard = useKeyboardHeightWithDuration();
const isTablet = useIsTablet();
const insets = useSafeAreaInsets();
const usersChipsHeight = useSharedValue(0);
@ -179,12 +180,10 @@ export default function SelectedUsers({
);
}
return u;
}, [selectedIds, teammateNameDisplay, onRemove]);
}, [selectedIds, teammateNameDisplay, onRemove, testID]);
const totalPanelHeight = useDerivedValue(() => (
isVisible ?
usersChipsHeight.value + SCROLL_MARGIN_BOTTOM + SCROLL_MARGIN_TOP + BUTTON_HEIGHT :
0
isVisible ? usersChipsHeight.value + SCROLL_MARGIN_BOTTOM + SCROLL_MARGIN_TOP + BUTTON_HEIGHT : 0
), [isVisible]);
const handlePress = useCallback(() => {
@ -205,10 +204,10 @@ export default function SelectedUsers({
});
const animatedContainerStyle = useAnimatedStyle(() => ({
marginBottom: withTiming(keyboardOverlap + TABLET_MARGIN_BOTTOM, {duration: keyboard.duration}),
marginBottom: withTiming(keyboardOverlap + ((Platform.OS === 'android' || isTablet) ? MARGIN_BOTTOM : -MARGIN_BOTTOM), {duration: keyboard.duration}),
backgroundColor: isVisible ? theme.centerChannelBg : 'transparent',
...androidMaxHeight,
}), [keyboardOverlap, keyboard.duration, isVisible, theme.centerChannelBg]);
}), [keyboardOverlap, keyboard.duration, isVisible, isTablet, theme.centerChannelBg]);
const animatedToastStyle = useAnimatedStyle(() => {
return {

View file

@ -78,6 +78,7 @@ export default function TeamList({
testID={`${testID}.flat_list`}
onEndReached={onEndReached}
ListFooterComponent={footer}
scrollEnabled={teams.length > 3}
/>
</View>
);

View file

@ -3,12 +3,12 @@
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {type StyleProp, Text, type TextStyle, TouchableOpacity, View, type ViewStyle} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {Platform, type StyleProp, Text, type TextStyle, TouchableOpacity, View, type ViewStyle} from 'react-native';
import FormattedText from '@components/formatted_text';
import {useTheme} from '@context/theme';
import {useIsTablet} from '@hooks/device';
import {BOTTOM_SHEET_ANDROID_OFFSET} from '@screens/bottom_sheet';
import {TITLE_HEIGHT} from '@screens/bottom_sheet/content';
import {bottomSheet} from '@screens/navigation';
import {bottomSheetSnapPoint} from '@utils/helpers';
@ -102,7 +102,6 @@ const UserAvatarsStack = ({
const theme = useTheme();
const intl = useIntl();
const isTablet = useIsTablet();
const {bottom} = useSafeAreaInsets();
const showParticipantsList = useCallback(preventDoubleTap(() => {
const renderContent = () => (
@ -124,7 +123,12 @@ const UserAvatarsStack = ({
</>
);
const snapPoints: Array<string | number> = [1, bottomSheetSnapPoint(Math.min(users.length, 5), USER_ROW_HEIGHT, bottom) + TITLE_HEIGHT];
let height = bottomSheetSnapPoint(Math.min(users.length, 5), USER_ROW_HEIGHT) + TITLE_HEIGHT;
if (Platform.OS === 'android') {
height += BOTTOM_SHEET_ANDROID_OFFSET;
}
const snapPoints: Array<string | number> = [1, height];
if (users.length > 5) {
snapPoints.push('80%');
}
@ -137,7 +141,7 @@ const UserAvatarsStack = ({
title: intl.formatMessage({id: 'mobile.participants.header', defaultMessage: 'Thread Participants'}),
theme,
});
}), [isTablet, theme, users, channelId, location, bottom]);
}), [isTablet, theme, users, channelId, location]);
const displayUsers = users.slice(0, breakAt);
const overflowUsersCount = Math.min(users.length - displayUsers.length, OVERFLOW_DISPLAY_LIMIT);

View file

@ -221,7 +221,7 @@ export default function UserList({
}
return createProfilesSections(intl, profiles, channelMembers);
}, [channelMembers, loading, profiles, term]);
}, [channelMembers, intl, loading, profiles, term]);
const openUserProfile = useCallback(async (profile: UserProfile | UserModel) => {
let user: UserModel;
@ -246,7 +246,7 @@ export default function UserList({
Keyboard.dismiss();
openAsBottomSheet({screen, title, theme, closeButtonId, props});
}, []);
}, [intl, serverUrl, theme]);
const renderItem = useCallback(({item, index, section}: RenderItemType) => {
// The list will re-render when the selection changes because it's passed into the list as extraData
@ -275,7 +275,7 @@ export default function UserList({
includeMargin={includeUserMargin}
/>
);
}, [selectedIds, handleSelectProfile, showManageMode, manageMode, tutorialWatched, includeUserMargin]);
}, [selectedIds, currentUserId, manageMode, handleSelectProfile, openUserProfile, showManageMode, tutorialWatched, includeUserMargin]);
const renderLoading = useCallback(() => {
if (!loading) {

View file

@ -4,7 +4,6 @@
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {Pressable, type StyleProp, Text, type TextStyle, View, type ViewStyle} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {setPreferredAudioRoute} from '@calls/actions/calls';
import {AudioDevice, type CurrentCall} from '@calls/types/calls';
@ -33,7 +32,6 @@ export const AudioDeviceButton = ({pressableStyle, iconStyle, buttonTextStyle, c
const intl = useIntl();
const theme = useTheme();
const style = getStyleFromTheme(theme);
const {bottom} = useSafeAreaInsets();
const isTablet = Device.IS_TABLET; // not `useIsTablet` because even if we're in splitView, we're still using a tablet.
const color = theme.awayIndicator;
const audioDeviceInfo = currentCall.audioDeviceInfo;
@ -109,7 +107,7 @@ export const AudioDeviceButton = ({pressableStyle, iconStyle, buttonTextStyle, c
bottomSheet({
closeButtonId: 'close-other-actions',
renderContent,
snapPoints: [1, bottomSheetSnapPoint(available.length + 1, ITEM_HEIGHT, bottom)],
snapPoints: [1, bottomSheetSnapPoint(available.length + 1, ITEM_HEIGHT)],
title: intl.formatMessage({id: 'mobile.calls_audio_device', defaultMessage: 'Select audio device'}),
theme,
});

View file

@ -208,7 +208,7 @@ export const useHostMenus = () => {
const props = {closeButtonId: closeHostControls, session};
openAsBottomSheet({screen, title, theme, closeButtonId: closeHostControls, props});
}, [theme]);
}, [intl, theme]);
const openUserProfile = useCallback(async (session: CallSession) => {
const screen = Screens.USER_PROFILE;
@ -217,7 +217,7 @@ export const useHostMenus = () => {
const props = {closeButtonId: closeUserProfile, location: '', userId: session.userId};
openAsBottomSheet({screen, title, theme, closeButtonId: closeUserProfile, props});
}, [theme, currentCall?.channelId]);
}, [intl, theme]);
const onPress = useCallback((session: CallSession) => () => {
// Show host controls when allowed and I'm host or admin,

View file

@ -19,7 +19,6 @@ import {
View,
} from 'react-native';
import {Navigation} from 'react-native-navigation';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {RTCView} from 'react-native-webrtc';
import {muteMyself, unmuteMyself} from '@calls/actions';
@ -330,7 +329,6 @@ const CallScreen = ({
}: Props) => {
const intl = useIntl();
const theme = useTheme();
const {bottom} = useSafeAreaInsets();
const {width, height} = useWindowDimensions();
const isTablet = useIsTablet();
const serverUrl = useServerUrl();
@ -504,7 +502,7 @@ const CallScreen = ({
Keyboard.dismiss();
openAsBottomSheet({screen, title, theme, closeButtonId});
}, [theme]);
}, [intl, theme]);
const showOtherActions = useCallback(async () => {
const renderContent = () => {
@ -552,11 +550,11 @@ const CallScreen = ({
bottomSheet({
closeButtonId: 'close-other-actions',
renderContent,
snapPoints: [1, bottomSheetSnapPoint(items, ITEM_HEIGHT, bottom)],
snapPoints: [1, bottomSheetSnapPoint(items, ITEM_HEIGHT)],
title: intl.formatMessage({id: 'post.options.title', defaultMessage: 'Options'}),
theme,
});
}, [bottom, intl, theme, isHost, EnableRecordings, waitingForRecording, recording, startRecording,
}, [intl, theme, isHost, EnableRecordings, waitingForRecording, recording, startRecording,
recordOptionTitle, stopRecording, stopRecordingOptionTitle, style, switchToThread,
callThreadOptionTitle, openChannelOptionTitle, ccAvailable, toggleCC, showCC, hideCCTitle,
showCCTitle]);

View file

@ -4,7 +4,6 @@
import React, {useCallback, useMemo} from 'react';
import {useIntl} from 'react-intl';
import {Platform, View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {hostLowerHand, hostMake, hostMuteSession, hostStopScreenshare} from '@calls/actions/calls';
import {removeFromCall} from '@calls/alerts';
@ -56,7 +55,6 @@ export const HostControls = ({
}: Props) => {
const intl = useIntl();
const theme = useTheme();
const {bottom} = useSafeAreaInsets();
const {openUserProfile} = useHostMenus();
const styles = getStyleFromTheme(theme);
@ -85,7 +83,7 @@ export const HostControls = ({
const profilePress = useCallback(async () => {
await dismissBottomSheet();
openUserProfile(session);
}, [session]);
}, [openUserProfile, session]);
const removePress = useCallback(async () => {
const displayName = displayUsername(session.userModel, intl.locale, teammateNameDisplay, true);
@ -96,9 +94,9 @@ export const HostControls = ({
const items = 3 + (session.muted ? 0 : 1) + (sharingScreen ? 1 : 0) + (session.raisedHand ? 1 : 0);
return [
1,
bottomSheetSnapPoint(items, ITEM_HEIGHT, bottom) + TITLE_HEIGHT + SEPARATOR_HEIGHT + (Platform.OS === 'android' ? ANDROID_BUMP_HEIGHT : 0),
bottomSheetSnapPoint(items, ITEM_HEIGHT) + TITLE_HEIGHT + SEPARATOR_HEIGHT + (Platform.OS === 'android' ? ANDROID_BUMP_HEIGHT : 0),
];
}, [bottom, session.muted, sharingScreen, session.raisedHand]);
}, [session.muted, sharingScreen, session.raisedHand]);
const makeHostText = intl.formatMessage({id: 'mobile.calls_make_host', defaultMessage: 'Make host'});
const muteText = intl.formatMessage({id: 'mobile.calls_mute_participant', defaultMessage: 'Mute participant'});

View file

@ -6,7 +6,6 @@ import React, {useCallback, useMemo} from 'react';
import {useIntl} from 'react-intl';
import {type ListRenderItemInfo, Text, TouchableOpacity, useWindowDimensions, View} from 'react-native';
import {FlatList} from 'react-native-gesture-handler';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {hostMuteOthers} from '@calls/actions/calls';
import {useHostControlsAvailable, useHostMenus} from '@calls/hooks';
@ -79,14 +78,13 @@ export const ParticipantsList = ({
const theme = useTheme();
const {onPress} = useHostMenus();
const hostControlsAvailable = useHostControlsAvailable();
const {bottom} = useSafeAreaInsets();
const {height} = useWindowDimensions();
const isTablet = useIsTablet();
const List = useMemo(() => (isTablet ? FlatList : BottomSheetFlatList), [isTablet]);
const styles = getStyleSheet(theme);
const sessions = sortSessions(intl.locale, teammateNameDisplay, sessionsDict);
const snapPoint1 = bottomSheetSnapPoint(Math.min(sessions.length, MIN_ROWS), ROW_HEIGHT, bottom) + HEADER_HEIGHT;
const snapPoint1 = bottomSheetSnapPoint(Math.min(sessions.length, MIN_ROWS), ROW_HEIGHT) + HEADER_HEIGHT;
const snapPoint2 = height * 0.8;
const snapPoints = [1, Math.min(snapPoint1, snapPoint2)];
if (sessions.length > MIN_ROWS && snapPoint1 < snapPoint2) {
@ -141,7 +139,6 @@ export const ParticipantsList = ({
renderItem={renderItem}
overScrollMode={'auto'}
/>
<View style={{height: bottom}}/>
</>
);
};

View file

@ -88,7 +88,7 @@ function BottomSheetButton({disabled = false, onPress, icon, testID, text}: Prop
)}
</TouchableWithFeedback>
<View style={{paddingBottom: Platform.select({ios: (isTablet ? 20 : 32), android: 20})}}/>
<View style={{paddingBottom: Platform.select({ios: (isTablet ? 20 : 0), android: 20})}}/>
</View>
</View>
);

View file

@ -5,6 +5,7 @@ import BottomSheetM, {BottomSheetBackdrop, type BottomSheetBackdropProps} from '
import React, {type ReactNode, useCallback, useEffect, useMemo, useRef} from 'react';
import {DeviceEventEmitter, type Handle, InteractionManager, Keyboard, type StyleProp, View, type ViewStyle} from 'react-native';
import {ReduceMotion, type WithSpringConfig} from 'react-native-reanimated';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {Events} from '@constants';
import {useTheme} from '@context/theme';
@ -22,6 +23,8 @@ import type {AvailableScreens} from '@typings/screens/navigation';
export {default as BottomSheetButton, BUTTON_HEIGHT} from './button';
export {default as BottomSheetContent, TITLE_HEIGHT} from './content';
export const BOTTOM_SHEET_ANDROID_OFFSET = 12;
type Props = {
closeButtonId?: string;
componentId: AvailableScreens;
@ -93,6 +96,7 @@ const BottomSheet = ({
}: Props) => {
const sheetRef = useRef<BottomSheetM>(null);
const isTablet = useIsTablet();
const insets = useSafeAreaInsets();
const theme = useTheme();
const styles = getStyleSheet(theme);
const interaction = useRef<Handle>();
@ -216,6 +220,7 @@ const BottomSheet = ({
keyboardBehavior='extend'
keyboardBlurBehavior='restore'
onClose={close}
bottomInset={insets.bottom}
>
{renderContainerContent()}
</BottomSheetM>

View file

@ -4,7 +4,6 @@
import React from 'react';
import {useIntl} from 'react-intl';
import {View, Text} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import CompassIcon from '@components/compass_icon';
import {ITEM_HEIGHT} from '@components/slide_up_panel_item';
@ -48,7 +47,6 @@ export default function ChannelDropdown({
sharedChannelsEnabled,
}: Props) {
const intl = useIntl();
const {bottom} = useSafeAreaInsets();
const theme = useTheme();
const style = getStyleFromTheme(theme);
@ -73,7 +71,7 @@ export default function ChannelDropdown({
items += 1;
}
const itemsSnap = bottomSheetSnapPoint(items, ITEM_HEIGHT, bottom) + TITLE_HEIGHT;
const itemsSnap = bottomSheetSnapPoint(items, ITEM_HEIGHT) + TITLE_HEIGHT;
bottomSheet({
title: intl.formatMessage({id: 'browse_channels.dropdownTitle', defaultMessage: 'Show'}),
renderContent,

View file

@ -39,7 +39,7 @@ const Member = ({channelId, containerStyle, size = 72, showStatus = true, theme,
Keyboard.dismiss();
openAsBottomSheet({screen, title, theme, closeButtonId, props});
}, [theme, intl.locale]);
}, [intl, user.id, channelId, theme]);
return (
<TouchableWithFeedback

View file

@ -50,7 +50,7 @@ const ChannelHeaderBookmarks = ({canAddBookmarks, channelId}: Props) => {
...styles.content,
top: defaultHeight,
zIndex: 1,
}), [defaultHeight]);
}), [defaultHeight, styles.content]);
return (
<View style={containerStyle}>

View file

@ -4,7 +4,6 @@
import React, {useCallback, useMemo} from 'react';
import {useIntl} from 'react-intl';
import {Keyboard, Platform, Text, View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {getCallsConfig} from '@calls/state';
import {CHANNEL_ACTIONS_OPTIONS_HEIGHT} from '@components/channel_actions/channel_actions';
@ -19,6 +18,7 @@ import {useServerUrl} from '@context/server';
import {useTheme} from '@context/theme';
import {useIsTablet} from '@hooks/device';
import {useDefaultHeaderHeight} from '@hooks/header';
import {BOTTOM_SHEET_ANDROID_OFFSET} from '@screens/bottom_sheet';
import {bottomSheet, popTopScreen, showModal} from '@screens/navigation';
import {isTypeDMorGM} from '@utils/channel';
import {bottomSheetSnapPoint} from '@utils/helpers';
@ -85,7 +85,6 @@ const ChannelHeader = ({
}: ChannelProps) => {
const intl = useIntl();
const isTablet = useIsTablet();
const {bottom} = useSafeAreaInsets();
const theme = useTheme();
const styles = getStyleSheet(theme);
const defaultHeight = useDefaultHeaderHeight();
@ -155,7 +154,10 @@ const ChannelHeader = ({
// When calls is enabled, we need space to move the "Copy Link" from a button to an option
const items = callsAvailable && !isDMorGM ? 3 : 2;
const height = CHANNEL_ACTIONS_OPTIONS_HEIGHT + SEPARATOR_HEIGHT + MARGIN + (items * ITEM_HEIGHT);
let height = CHANNEL_ACTIONS_OPTIONS_HEIGHT + SEPARATOR_HEIGHT + MARGIN + (items * ITEM_HEIGHT);
if (Platform.OS === 'android') {
height += BOTTOM_SHEET_ANDROID_OFFSET;
}
const renderContent = () => {
return (
@ -170,11 +172,11 @@ const ChannelHeader = ({
bottomSheet({
title: '',
renderContent,
snapPoints: [1, bottomSheetSnapPoint(1, height, bottom)],
snapPoints: [1, bottomSheetSnapPoint(1, height)],
theme,
closeButtonId: 'close-channel-quick-actions',
});
}, [bottom, channelId, isDMorGM, isTablet, onTitlePress, theme, callsAvailable]);
}, [channelId, isDMorGM, isTablet, onTitlePress, theme, callsAvailable]);
const rightButtons: HeaderRightButton[] = useMemo(() => ([

View file

@ -94,7 +94,7 @@ const BookmarkDetail = ({disabled, emoji, file, imageUrl, setBookmarkDisplayName
file,
},
});
}, [imageUrl, file, theme, setBookmarkEmoji]);
}, [theme, intl, setBookmarkEmoji, imageUrl, file]);
return (
<View style={paddingStyle}>

View file

@ -3,7 +3,6 @@
import React, {useCallback, useMemo} from 'react';
import {useIntl} from 'react-intl';
import {Text, View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import Badge from '@components/badge';
import CompassIcon from '@components/compass_icon';
@ -58,7 +57,6 @@ const Header = ({
const theme = useTheme();
const styles = getStyleFromTheme(theme);
const intl = useIntl();
const {bottom} = useSafeAreaInsets();
const isTablet = useIsTablet();
const hasFilters = selectedFilter !== FileFilters.ALL;
const messageObject = hasFilters ? {
@ -78,10 +76,9 @@ const Header = ({
bottomSheetSnapPoint(
NUMBER_FILTER_ITEMS,
FILTER_ITEM_HEIGHT,
bottom,
) + TITLE_HEIGHT + DIVIDERS_HEIGHT + (isTablet ? TITLE_SEPARATOR_MARGIN_TABLET : TITLE_SEPARATOR_MARGIN),
];
}, []);
}, [isTablet]);
const handleFilterPress = useCallback(() => {
const renderContent = () => {

View file

@ -7,7 +7,6 @@ import moment from 'moment';
import React, {useCallback, useMemo} from 'react';
import {useIntl} from 'react-intl';
import {Platform, StyleSheet, Text, View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import CustomStatusExpiry from '@components/custom_status/custom_status_expiry';
import Emoji from '@components/emoji';
@ -97,7 +96,6 @@ const onCopy = async (text: string, isLink?: boolean) => {
const Extra = ({channelId, createdAt, createdBy, customStatus, header, isCustomStatusEnabled}: Props) => {
const intl = useIntl();
const {bottom} = useSafeAreaInsets();
const theme = useTheme();
const managedConfig = useManagedConfig<ManagedConfig>();
@ -112,7 +110,7 @@ const Extra = ({channelId, createdAt, createdBy, customStatus, header, isCustomS
value={createdAt}
/>
),
}), [createdAt, createdBy, theme]);
}), [createdAt, createdBy, styles.created]);
const handleLongPress = useCallback((url?: string) => {
if (managedConfig?.copyAndPasteProtection !== 'true') {
@ -163,18 +161,12 @@ const Extra = ({channelId, createdAt, createdBy, customStatus, header, isCustomS
bottomSheet({
closeButtonId: 'close-markdown-link',
renderContent,
snapPoints: [1, bottomSheetSnapPoint(url ? 3 : 2, ITEM_HEIGHT, bottom)],
snapPoints: [1, bottomSheetSnapPoint(url ? 3 : 2, ITEM_HEIGHT)],
title: intl.formatMessage({id: 'post.options.title', defaultMessage: 'Options'}),
theme,
});
}
}, [
header,
bottom,
theme,
intl.formatMessage,
managedConfig?.copyAndPasteProtection,
]);
}, [managedConfig?.copyAndPasteProtection, intl, theme, header]);
const touchableHandleLongPress = useCallback(() => handleLongPress(), [handleLongPress]);

View file

@ -6,7 +6,6 @@ import Clipboard from '@react-native-clipboard/clipboard';
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {Platform, StyleSheet, Text, View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item';
import {SNACK_BAR_TYPE} from '@constants/snack_bar';
@ -45,7 +44,6 @@ const PublicPrivate = ({displayName, purpose}: Props) => {
const intl = useIntl();
const theme = useTheme();
const managedConfig = useManagedConfig<ManagedConfig>();
const {bottom} = useSafeAreaInsets();
const styles = getStyleSheet(theme);
const publicPrivateTestId = 'channel_info.title.public_private';
@ -85,18 +83,12 @@ const PublicPrivate = ({displayName, purpose}: Props) => {
bottomSheet({
closeButtonId: 'close-mardown-link',
renderContent,
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT, bottom)],
snapPoints: [1, bottomSheetSnapPoint(2, ITEM_HEIGHT)],
title: intl.formatMessage({id: 'post.options.title', defaultMessage: 'Options'}),
theme,
});
}
}, [
bottom,
theme,
onCopy,
intl.formatMessage,
managedConfig?.copyAndPasteProtection,
]);
}, [managedConfig?.copyAndPasteProtection, intl, theme, onCopy]);
return (
<>

View file

@ -143,7 +143,7 @@ export default function CreateDirectMessage({
}
return !result.error;
}, [selectedIds, intl.locale, teammateNameDisplay, serverUrl]);
}, [selectedIds, intl, teammateNameDisplay, serverUrl]);
const createGroupChannel = useCallback(async (ids: string[]): Promise<boolean> => {
const result = await makeGroupChannel(serverUrl, ids);
@ -153,7 +153,7 @@ export default function CreateDirectMessage({
}
return !result.error;
}, [serverUrl]);
}, [intl, serverUrl]);
const startConversation = useCallback(async (selectedId?: {[id: string]: boolean}, selectedUser?: UserProfile) => {
if (startingConversation) {
@ -208,7 +208,7 @@ export default function CreateDirectMessage({
return newSelectedIds;
});
}
}, [currentUserId, clearSearch]);
}, [currentUserId, startConversation, clearSearch, selectedCount]);
const onLayout = useCallback((e: LayoutChangeEvent) => {
setContainerHeight(e.nativeEvent.layout.height);
@ -223,7 +223,7 @@ export default function CreateDirectMessage({
testID: 'close.create_direct_message.button',
}],
});
}, [intl.locale, theme]);
}, [componentId, theme.sidebarHeaderTextColor]);
const onChangeText = useCallback((searchTerm: string) => {
setTerm(searchTerm);
@ -273,7 +273,7 @@ export default function CreateDirectMessage({
return true;
};
}, [selectedCount > 0, currentUserId]);
}, [currentUserId, selectedCount]);
useNavButtonPressed(CLOSE_BUTTON, componentId, close, [close]);
useAndroidHardwareBackHandler(componentId, close);
@ -284,7 +284,7 @@ export default function CreateDirectMessage({
useEffect(() => {
setShowToast(selectedCount >= General.MAX_USERS_IN_GM);
}, [selectedCount >= General.MAX_USERS_IN_GM]);
}, [selectedCount]);
if (startingConversation) {
return (
@ -300,7 +300,6 @@ export default function CreateDirectMessage({
testID='create_direct_message.screen'
onLayout={onLayout}
ref={mainView}
edges={['top', 'left', 'right']}
>
<View style={style.searchBar}>
<Search

View file

@ -304,7 +304,7 @@ const CustomStatus = ({
} else {
dismissModal({componentId});
}
}, [isTablet]);
}, [componentId, isTablet]);
useAndroidHardwareBackHandler(componentId, handleBackButton);
useNavButtonPressed(BTN_UPDATE_STATUS, componentId, handleSetStatus, [handleSetStatus]);

View file

@ -4,7 +4,6 @@
import React, {useCallback, useMemo} from 'react';
import {useIntl} from 'react-intl';
import {TouchableOpacity} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {buildProfileImageUrlFromUser} from '@actions/remote/user';
import CompassIcon from '@components/compass_icon';
@ -68,7 +67,6 @@ const ProfileImagePicker = ({
}: ImagePickerProps) => {
const theme = useTheme();
const intl = useIntl();
const {bottom} = useSafeAreaInsets();
const serverUrl = useServerUrl();
const pictureUtils = useMemo(() => new PickerUtil(intl, uploadFiles), [uploadFiles, intl]);
const canRemovePicture = hasPictureUrl(user, serverUrl);
@ -109,7 +107,7 @@ const ProfileImagePicker = ({
);
};
const snapPoint = bottomSheetSnapPoint(4, ITEM_HEIGHT, bottom) + TITLE_HEIGHT;
const snapPoint = bottomSheetSnapPoint(4, ITEM_HEIGHT) + TITLE_HEIGHT;
return bottomSheet({
closeButtonId: 'close-edit-profile',
@ -118,7 +116,7 @@ const ProfileImagePicker = ({
title: 'Change profile photo',
theme,
});
}), [canRemovePicture, onRemoveProfileImage, bottom, pictureUtils, theme]);
}), [canRemovePicture, onRemoveProfileImage, pictureUtils, theme]);
return (
<TouchableOpacity

View file

@ -35,7 +35,7 @@ const PickerFooter = (props: BottomSheetFooterProps) => {
const animatedStyle = useAnimatedStyle(() => {
const paddingBottom = withTiming(
Platform.OS === 'ios' ? 20 : 0,
Platform.OS === 'ios' ? 32 : 0,
{duration: 250},
);
return {backgroundColor: theme.centerChannelBg, paddingBottom};
@ -44,7 +44,7 @@ const PickerFooter = (props: BottomSheetFooterProps) => {
const heightAnimatedStyle = useAnimatedStyle(() => {
let height = 55;
if (keyboardHeight === 0 && Platform.OS === 'ios') {
height += 20;
height -= 10;
} else if (keyboardHeight) {
height = 0;
}

View file

@ -4,7 +4,6 @@
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {TouchableOpacity, View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {setStatus} from '@actions/remote/user';
import FormattedText from '@components/formatted_text';
@ -57,7 +56,6 @@ type Props = {
};
const UserStatus = ({currentUser}: Props) => {
const intl = useIntl();
const {bottom} = useSafeAreaInsets();
const serverUrl = useServerUrl();
const theme = useTheme();
const styles = getStyleSheet(theme);
@ -125,7 +123,7 @@ const UserStatus = ({currentUser}: Props) => {
);
};
const snapPoint = bottomSheetSnapPoint(4, ITEM_HEIGHT, bottom);
const snapPoint = bottomSheetSnapPoint(4, ITEM_HEIGHT);
bottomSheet({
closeButtonId: 'close-set-user-status',
renderContent,
@ -133,7 +131,7 @@ const UserStatus = ({currentUser}: Props) => {
title: intl.formatMessage({id: 'user_status.title', defaultMessage: 'Status'}),
theme,
});
}), [theme, bottom]);
}), [theme]);
const updateStatus = useCallback((status: string) => {
const userStatus = {

View file

@ -5,7 +5,6 @@ import React, {useCallback, useEffect} from 'react';
import {useIntl} from 'react-intl';
import {type Insets, Text, TouchableWithoutFeedback, View} from 'react-native';
import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {logout} from '@actions/remote/session';
import CompassIcon from '@components/compass_icon';
@ -115,7 +114,6 @@ const ChannelListHeader = ({
const theme = useTheme();
const isTablet = useIsTablet();
const intl = useIntl();
const {bottom} = useSafeAreaInsets();
const serverDisplayName = useServerDisplayName();
const marginLeft = useSharedValue(iconPad ? 50 : 0);
const styles = getStyles(theme);
@ -158,11 +156,11 @@ const ChannelListHeader = ({
bottomSheet({
closeButtonId,
renderContent,
snapPoints: [1, bottomSheetSnapPoint(items, ITEM_HEIGHT, bottom) + (separators * SEPARATOR_HEIGHT)],
snapPoints: [1, bottomSheetSnapPoint(items, ITEM_HEIGHT) + (separators * SEPARATOR_HEIGHT)],
theme,
title: intl.formatMessage({id: 'home.header.plus_menu', defaultMessage: 'Options'}),
});
}), [intl, bottom, isTablet, theme]);
}), [intl, isTablet, theme]);
const onPushAlertPress = useCallback(() => {
if (pushProxyStatus === PUSH_PROXY_STATUS_NOT_AVAILABLE) {

View file

@ -4,7 +4,6 @@
import React, {useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react';
import {useIntl} from 'react-intl';
import {Dimensions, StyleSheet} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import ServerIcon from '@components/server_icon';
import {useServerUrl} from '@context/server';
@ -49,7 +48,6 @@ const Servers = React.forwardRef<ServersRef>((_, ref) => {
const registeredServers = useRef<ServersModel[]|undefined>();
const currentServerUrl = useServerUrl();
const isTablet = useIsTablet();
const {bottom} = useSafeAreaInsets();
const theme = useTheme();
const updateTotal = () => {
@ -119,7 +117,7 @@ const Servers = React.forwardRef<ServersRef>((_, ref) => {
const maxScreenHeight = Math.ceil(0.6 * Dimensions.get('window').height);
const maxSnapPoint = Math.min(
maxScreenHeight,
bottomSheetSnapPoint(registeredServers.current.length, SERVER_ITEM_HEIGHT, bottom) + TITLE_HEIGHT + BUTTON_HEIGHT +
bottomSheetSnapPoint(registeredServers.current.length, SERVER_ITEM_HEIGHT) + TITLE_HEIGHT + BUTTON_HEIGHT +
(registeredServers.current.filter((s: ServersModel) => s.lastActiveAt).length * PUSH_ALERT_TEXT_HEIGHT),
);
@ -141,7 +139,7 @@ const Servers = React.forwardRef<ServersRef>((_, ref) => {
title: intl.formatMessage({id: 'your.servers', defaultMessage: 'Your servers'}),
});
}
}, [bottom, isTablet, theme]);
}, [intl, isTablet, theme]);
useImperativeHandle(ref, () => ({
openServers: onPress,

View file

@ -3,7 +3,6 @@
import React, {useCallback, useMemo} from 'react';
import {useIntl} from 'react-intl';
import {View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import Badge from '@components/badge';
import CompassIcon from '@components/compass_icon';
@ -70,7 +69,6 @@ const Header = ({
const theme = useTheme();
const styles = getStyleFromTheme(theme);
const intl = useIntl();
const {bottom} = useSafeAreaInsets();
const isTablet = useIsTablet();
const messagesText = intl.formatMessage({id: 'screen.search.header.messages', defaultMessage: 'Messages'});
@ -94,10 +92,9 @@ const Header = ({
bottomSheetSnapPoint(
NUMBER_FILTER_ITEMS,
FILTER_ITEM_HEIGHT,
bottom,
) + TITLE_HEIGHT + DIVIDERS_HEIGHT + (isTablet ? TITLE_SEPARATOR_MARGIN_TABLET : TITLE_SEPARATOR_MARGIN),
];
}, []);
}, [isTablet]);
const handleFilterPress = useCallback(() => {
const renderContent = () => {

View file

@ -4,7 +4,6 @@
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import CompassIcon from '@components/compass_icon';
import {ITEM_HEIGHT} from '@components/slide_up_panel_item';
@ -57,7 +56,6 @@ const TeamPickerIcon = ({size = 24, divider = false, setTeamId, teams, teamId}:
const intl = useIntl();
const theme = useTheme();
const styles = getStyleFromTheme(theme);
const {bottom} = useSafeAreaInsets();
const selectedTeam = teams.find((t) => t.id === teamId);
@ -77,7 +75,7 @@ const TeamPickerIcon = ({size = 24, divider = false, setTeamId, teams, teamId}:
const snapPoints: Array<string | number> = [
1,
teams.length ? (bottomSheetSnapPoint(Math.min(3, teams.length), ITEM_HEIGHT, bottom) + TITLE_HEIGHT) : NO_TEAMS_HEIGHT,
teams.length ? bottomSheetSnapPoint(Math.min(3, teams.length), ITEM_HEIGHT) + (2 * TITLE_HEIGHT) : NO_TEAMS_HEIGHT,
];
if (teams.length > 3) {
@ -91,7 +89,7 @@ const TeamPickerIcon = ({size = 24, divider = false, setTeamId, teams, teamId}:
theme,
title,
});
}), [theme, setTeamId, teamId, teams, bottom]);
}), [theme, setTeamId, teamId, teams]);
return (
<>

View file

@ -130,7 +130,7 @@ export default function ManageChannelMembers({
Keyboard.dismiss();
openAsBottomSheet({screen: USER_PROFILE, title, theme, closeButtonId: CLOSE_BUTTON_ID, props});
}, [canManageAndRemoveMembers, channelId, isManageMode, currentUserId]);
}, [currentUserId, isManageMode, formatMessage, channelId, canManageAndRemoveMembers, theme, serverUrl]);
const searchUsers = useCallback(async (searchTerm: string) => {
setSearchedTerm(searchTerm);

View file

@ -5,7 +5,6 @@ import {BottomSheetScrollView} from '@gorhom/bottom-sheet';
import {useManagedConfig} from '@mattermost/react-native-emm';
import React, {useMemo} from 'react';
import {ScrollView} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {CopyPermalinkOption, FollowThreadOption, ReplyOption, SaveOption} from '@components/common_post_options';
import {ITEM_HEIGHT} from '@components/option_item';
@ -55,7 +54,6 @@ const PostOptions = ({
sourceScreen, post, thread, bindings, serverUrl,
}: PostOptionsProps) => {
const managedConfig = useManagedConfig<ManagedConfig>();
const {bottom} = useSafeAreaInsets();
const isTablet = useIsTablet();
const Scroll = useMemo(() => (isTablet ? ScrollView : BottomSheetScrollView), [isTablet]);
@ -82,7 +80,7 @@ const PostOptions = ({
return v ? acc + 1 : acc;
}, 0) + (shouldShowBindings ? 0.5 : 0);
items.push(bottomSheetSnapPoint(optionsCount, ITEM_HEIGHT, bottom) + (canAddReaction ? REACTION_PICKER_HEIGHT + REACTION_PICKER_MARGIN : 0));
items.push(bottomSheetSnapPoint(optionsCount, ITEM_HEIGHT) + (canAddReaction ? REACTION_PICKER_HEIGHT + REACTION_PICKER_MARGIN : 0));
if (shouldShowBindings) {
items.push('80%');
@ -92,7 +90,7 @@ const PostOptions = ({
}, [
canAddReaction, canCopyPermalink, canCopyText,
canDelete, canEdit, shouldRenderFollow, shouldShowBindings,
canMarkAsUnread, canPin, canReply, isSystemPost, bottom,
canMarkAsUnread, canPin, canReply, isSystemPost,
]);
const renderContent = () => {

View file

@ -69,7 +69,7 @@ const ReactionBar = ({bottomSheetId, recentEmojis = [], postId}: QuickReactionPr
title: intl.formatMessage({id: 'mobile.post_info.add_reaction', defaultMessage: 'Add Reaction'}),
props: {onEmojiPress: handleEmojiPress},
});
}, [handleEmojiPress, intl, theme]);
}, [bottomSheetId, handleEmojiPress, intl, theme]);
let containerSize = LARGE_CONTAINER_SIZE;
let iconSize = LARGE_ICON_SIZE;

View file

@ -19,7 +19,7 @@ export type Props = BottomSheetFooterProps & {
const TEXT_HEIGHT = 24; // typography 200 line height
const BUTTON_PADDING = 15;
const FOOTER_PADDING = 20;
const FOOTER_PADDING_BOTTOM_TABLET_ADJUST = 12;
const FOOTER_PADDING_BOTTOM_TABLET_ADJUST = 20;
export const FOOTER_HEIGHT = (FOOTER_PADDING * 2) + (BUTTON_PADDING * 2) + TEXT_HEIGHT;
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
@ -64,7 +64,7 @@ const PostPriorityPickerFooter = ({onCancel, onSubmit, ...props}: Props) => {
const footer = (
<View
style={[style.container, {
paddingBottom: FOOTER_PADDING + Platform.select({ios: (isTablet ? FOOTER_PADDING_BOTTOM_TABLET_ADJUST : 0), default: 0}),
paddingBottom: Platform.select({ios: (isTablet ? FOOTER_PADDING_BOTTOM_TABLET_ADJUST : 0), default: FOOTER_PADDING}),
}]}
>
<TouchableOpacity

View file

@ -3,8 +3,7 @@
import React, {useCallback, useMemo, useState} from 'react';
import {useIntl} from 'react-intl';
import {View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {Platform, View} from 'react-native';
import FormattedText from '@components/formatted_text';
import {getItemHeightWithDescription} from '@components/option_item';
@ -89,7 +88,6 @@ const PostPriorityPicker = ({
updatePostPriority,
closeButtonId,
}: Props) => {
const {bottom} = useSafeAreaInsets();
const intl = useIntl();
const isTablet = useIsTablet();
const theme = useTheme();
@ -108,8 +106,8 @@ const PostPriorityPicker = ({
const snapPoints = useMemo(() => {
const paddingBottom = 10;
const bottomSheetAdjust = 5;
let COMPONENT_HEIGHT = TITLE_HEIGHT + OPTIONS_PADDING + FOOTER_HEIGHT + bottomSheetSnapPoint(3, ITEM_HEIGHT, bottom) + paddingBottom + bottomSheetAdjust;
const bottomSheetAdjust = Platform.select({ios: 5, default: 20});
let COMPONENT_HEIGHT = TITLE_HEIGHT + OPTIONS_PADDING + FOOTER_HEIGHT + bottomSheetSnapPoint(3, ITEM_HEIGHT) + paddingBottom + bottomSheetAdjust;
if (isPostAcknowledgementEnabled) {
COMPONENT_HEIGHT += OPTIONS_SEPARATOR_HEIGHT + TOGGLE_OPTION_MARGIN_TOP + getItemHeightWithDescription(2);
@ -119,7 +117,7 @@ const PostPriorityPicker = ({
}
return [1, COMPONENT_HEIGHT];
}, [displayPersistentNotifications, isPostAcknowledgementEnabled, bottom]);
}, [displayPersistentNotifications, isPostAcknowledgementEnabled]);
const handleUpdatePriority = useCallback((priority: PostPriority['priority']) => {
setData((prevData) => ({
@ -131,16 +129,16 @@ const PostPriorityPicker = ({
const handleUpdateRequestedAck = useCallback((requested_ack: boolean) => {
setData((prevData) => ({...prevData, requested_ack}));
}, [data]);
}, []);
const handleUpdatePersistentNotifications = useCallback((persistent_notifications: boolean) => {
setData((prevData) => ({...prevData, persistent_notifications}));
}, [data]);
}, []);
const handleSubmit = useCallback(() => {
updatePostPriority(data);
closeBottomSheet();
}, [data]);
}, [closeBottomSheet, data, updatePostPriority]);
const renderContent = () => (
<View style={style.container}>

View file

@ -4,7 +4,6 @@
import {useManagedConfig} from '@mattermost/react-native-emm';
import React, {useMemo} from 'react';
import {View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {CopyPermalinkOption, FollowThreadOption, ReplyOption, SaveOption} from '@components/common_post_options';
import FormattedText from '@components/formatted_text';
@ -59,7 +58,6 @@ const ThreadOptions = ({
}: ThreadOptionsProps) => {
const theme = useTheme();
const isTablet = useIsTablet();
const {bottom} = useSafeAreaInsets();
const style = getStyleSheet(theme);
const close = () => {
@ -111,7 +109,7 @@ const ThreadOptions = ({
);
}
const snapPoint = useMemo(() => TITLE_HEIGHT + bottomSheetSnapPoint(options.length, ITEM_HEIGHT, bottom), [bottom, options.length]);
const snapPoint = useMemo(() => TITLE_HEIGHT + bottomSheetSnapPoint(options.length, ITEM_HEIGHT), [options.length]);
const renderContent = () => (
<>

View file

@ -89,10 +89,10 @@ const UserProfile = ({
}: Props) => {
const {formatMessage, locale} = useIntl();
const serverUrl = useServerUrl();
const {bottom} = useSafeAreaInsets();
const channelContext = channelContextScreens.includes(location);
const showOptions: OptionsType = channelContext && !user.isBot ? 'all' : 'message';
const override = Boolean(userIconOverride || usernameOverride);
const {bottom} = useSafeAreaInsets();
const timezone = getUserTimezone(user);
const customStatus = getUserCustomStatus(user);
let localTime: string|undefined;
@ -145,15 +145,17 @@ const UserProfile = ({
}
}
const extraHeight = manageMode ? 0 : EXTRA_HEIGHT;
const extraHeight = manageMode ? 0 : (EXTRA_HEIGHT - bottom);
return [
1,
bottomSheetSnapPoint(optionsCount, LABEL_HEIGHT, bottom) + title + extraHeight,
bottomSheetSnapPoint(optionsCount, LABEL_HEIGHT) + title + extraHeight,
];
}, [
showUserProfileOptions, showCustomStatus, showNickname,
showPosition, showLocalTime, bottom,
headerText, showUserProfileOptions, showCustomStatus,
showNickname, showPosition, showLocalTime,
manageMode, bottom, showOptions,
canChangeMemberRoles, canManageAndRemoveMembers,
]);
useEffect(() => {

View file

@ -197,9 +197,8 @@ describe('Helpers', () => {
test('should calculate bottom sheet snap point', () => {
const itemsCount = 5;
const itemHeight = 50;
const bottomInset = 20;
const result = bottomSheetSnapPoint(itemsCount, itemHeight, bottomInset);
const expected = (itemsCount * itemHeight) + bottomInset + STATUS_BAR_HEIGHT;
const result = bottomSheetSnapPoint(itemsCount, itemHeight);
const expected = (itemsCount * itemHeight) + STATUS_BAR_HEIGHT;
expect(result).toBe(expected);
});
});

View file

@ -140,9 +140,8 @@ export function isTablet() {
export const pluckUnique = (key: string) => (array: Array<{[key: string]: unknown}>) => Array.from(new Set(array.map((obj) => obj[key])));
export function bottomSheetSnapPoint(itemsCount: number, itemHeight: number, bottomInset: number) {
const bottom = Platform.select({ios: bottomInset, default: 0}) + STATUS_BAR_HEIGHT;
return (itemsCount * itemHeight) + bottom;
export function bottomSheetSnapPoint(itemsCount: number, itemHeight: number) {
return (itemsCount * itemHeight) + STATUS_BAR_HEIGHT;
}
export function hasTrailingSpaces(term: string) {

View file

@ -0,0 +1,17 @@
diff --git a/node_modules/@gorhom/bottom-sheet/src/components/bottomSheetContainer/BottomSheetContainer.tsx b/node_modules/@gorhom/bottom-sheet/src/components/bottomSheetContainer/BottomSheetContainer.tsx
index 72fe2cb..abac348 100644
--- a/node_modules/@gorhom/bottom-sheet/src/components/bottomSheetContainer/BottomSheetContainer.tsx
+++ b/node_modules/@gorhom/bottom-sheet/src/components/bottomSheetContainer/BottomSheetContainer.tsx
@@ -30,10 +30,10 @@ function BottomSheetContainerComponent({
{
top: topInset,
bottom: bottomInset,
- overflow: detached ? 'visible' : 'hidden',
+ overflow: 'visible',
},
],
- [style, detached, topInset, bottomInset]
+ [style, topInset, bottomInset]
);
//#endregion