mattermost-mobile/app/components/channel_bookmarks/channel_bookmarks.tsx
Elias Nahum 7cb2ee75b3
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
2024-11-29 12:50:09 +08:00

180 lines
6.5 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {LinearGradient} from 'expo-linear-gradient';
import React, {useCallback, useMemo, useState} from 'react';
import {FlatList, View, type ListRenderItemInfo, type NativeSyntheticEvent, type NativeScrollEvent} from 'react-native';
import Animated from 'react-native-reanimated';
import {GalleryInit} from '@context/gallery';
import {useTheme} from '@context/theme';
import {useChannelBookmarkFiles} from '@hooks/files';
import ChannelBookmarkModel from '@typings/database/models/servers/channel_bookmark';
import {fileToGalleryItem, openGalleryAtIndex} from '@utils/gallery';
import {preventDoubleTap} from '@utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import AddBookmark from './add_bookmark';
import ChannelBookmark from './channel_bookmark';
type Props = {
bookmarks: ChannelBookmarkModel[];
canAddBookmarks: boolean;
canDeleteBookmarks: boolean;
canDownloadFiles: boolean;
canEditBookmarks: boolean;
canUploadFiles: boolean;
channelId: string;
currentUserId: string;
publicLinkEnabled: boolean;
showInInfo: boolean;
separator?: boolean;
}
const GRADIENT_LOCATIONS = [0, 0.64, 1];
const SCROLL_OFFSET = 10;
const isCloseToBottom = ({layoutMeasurement, contentOffset, contentSize}: NativeScrollEvent) => {
return layoutMeasurement.width + contentOffset.x <= contentSize.width - SCROLL_OFFSET;
};
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
container: {
flexDirection: 'row',
},
separator: {
height: 1,
backgroundColor: changeOpacity(theme.centerChannelColor, 0.08),
marginTop: 8,
marginBottom: 24,
},
emptyItemSeparator: {
width: 20,
},
addContainer: {
width: 40,
alignContent: 'center',
},
gradient: {
height: 48,
width: 68,
position: 'absolute',
right: 0,
},
channelView: {
paddingHorizontal: 8,
},
}));
const ChannelBookmarks = ({
bookmarks, canAddBookmarks, canDeleteBookmarks, canDownloadFiles, canEditBookmarks, canUploadFiles,
channelId, currentUserId, publicLinkEnabled, showInInfo, separator = true,
}: Props) => {
const galleryIdentifier = `${channelId}-bookmarks`;
const theme = useTheme();
const styles = getStyleSheet(theme);
const files = useChannelBookmarkFiles(bookmarks, publicLinkEnabled);
const [allowEndFade, setAllowEndFade] = useState(true);
const attachmentIndex = useCallback((fileId: string) => {
return files.findIndex((file) => file.id === fileId) || 0;
}, [files]);
const handlePreviewPress = useCallback(preventDoubleTap((idx: number) => {
if (files.length) {
const items = files.map((f) => fileToGalleryItem(f, f.user_id));
openGalleryAtIndex(galleryIdentifier, idx, items);
}
}), [files]);
const renderItem = useCallback(({item}: ListRenderItemInfo<ChannelBookmarkModel>) => {
return (
<ChannelBookmark
bookmark={item}
canDeleteBookmarks={canDeleteBookmarks}
canDownloadFiles={canDownloadFiles}
canEditBookmarks={canEditBookmarks}
galleryIdentifier={galleryIdentifier}
index={item.fileId ? attachmentIndex(item.fileId) : undefined}
onPress={handlePreviewPress}
publicLinkEnabled={publicLinkEnabled}
/>
);
}, [
canDeleteBookmarks, canDownloadFiles, canEditBookmarks,
galleryIdentifier, attachmentIndex, handlePreviewPress,
publicLinkEnabled,
]);
const renderItemSeparator = useCallback(() => (<View style={styles.emptyItemSeparator}/>), []);
const onScrolled = useCallback((e: NativeSyntheticEvent<NativeScrollEvent>) => {
setAllowEndFade(isCloseToBottom(e.nativeEvent));
}, []);
const gradientColors = useMemo(() => [
theme.centerChannelBg,
changeOpacity(theme.centerChannelBg, 0.6458),
changeOpacity(theme.centerChannelBg, 0),
], [theme]);
if (!bookmarks.length && showInInfo && canAddBookmarks) {
return (
<AddBookmark
bookmarksCount={0}
canUploadFiles={canUploadFiles}
channelId={channelId}
currentUserId={currentUserId}
showLarge={true}
/>
);
}
if (bookmarks.length) {
return (
<GalleryInit galleryIdentifier={galleryIdentifier}>
<Animated.View>
<Animated.View style={[styles.container, showInInfo ? undefined : styles.channelView]}>
<FlatList
bounces={true}
alwaysBounceHorizontal={false}
data={bookmarks}
horizontal={true}
renderItem={renderItem}
ItemSeparatorComponent={renderItemSeparator}
onScroll={onScrolled}
showsHorizontalScrollIndicator={false}
contentContainerStyle={{height: 48, alignItems: 'center'}}
/>
{canAddBookmarks &&
<View style={styles.addContainer}>
{allowEndFade &&
<LinearGradient
locations={GRADIENT_LOCATIONS}
colors={gradientColors}
style={styles.gradient}
pointerEvents={'none'}
/>
}
<AddBookmark
bookmarksCount={bookmarks.length}
canUploadFiles={canUploadFiles}
channelId={channelId}
currentUserId={currentUserId}
showLarge={false}
/>
</View>
}
</Animated.View>
{separator &&
<View style={styles.separator}/>
}
</Animated.View>
</GalleryInit>
);
}
return null;
};
export default ChannelBookmarks;