diff --git a/native/chat/fullscreen-thread-media-gallery.react.js b/native/chat/fullscreen-thread-media-gallery.react.js
--- a/native/chat/fullscreen-thread-media-gallery.react.js
+++ b/native/chat/fullscreen-thread-media-gallery.react.js
@@ -1,17 +1,57 @@
// @flow
import * as React from 'react';
-import { Text } from 'react-native';
+import { Text, View, TouchableOpacity } from 'react-native';
import type { ThreadInfo } from 'lib/types/thread-types.js';
import type { ChatNavigationProp } from './chat.react.js';
+import ThreadSettingsMediaGallery from './settings/thread-settings-media-gallery.react.js';
import type { NavigationRoute } from '../navigation/route-names.js';
+import { useStyles } from '../themes/colors.js';
+import type { VerticalBounds } from '../types/layout-types.js';
export type FullScreenThreadMediaGalleryParams = {
+threadInfo: ThreadInfo,
+ +verticalBounds: ?VerticalBounds,
};
+const TABS = {
+ ALL: 'ALL',
+ IMAGES: 'IMAGES',
+ VIDEOS: 'VIDEOS',
+};
+
+type FilterBarProps = {
+ +setActiveTab: (tab: string) => void,
+ +activeTab: string,
+};
+
+function FilterBar(props: FilterBarProps): React.Node {
+ const styles = useStyles(unboundStyles);
+ const { setActiveTab, activeTab } = props;
+
+ const filterBar = React.useMemo(() => {
+ return (
+
+
+ {Object.values(TABS).map(tab => (
+ setActiveTab(String(tab))}
+ >
+ {String(tab)}
+
+ ))}
+
+
+ );
+ }, [activeTab, setActiveTab, styles]);
+
+ return filterBar;
+}
+
type FullScreenThreadMediaGalleryProps = {
+navigation: ChatNavigationProp<'FullScreenThreadMediaGallery'>,
+route: NavigationRoute<'FullScreenThreadMediaGallery'>,
@@ -20,8 +60,65 @@
function FullScreenThreadMediaGallery(
props: FullScreenThreadMediaGalleryProps,
): React.Node {
- const { id } = props.route.params.threadInfo;
- return {id};
+ const { threadInfo, verticalBounds } = props.route.params;
+ const { id } = threadInfo;
+ const styles = useStyles(unboundStyles);
+
+ const [activeTab, setActiveTab] = React.useState(TABS.ALL);
+
+ return (
+
+
+
+
+ );
}
+const unboundStyles = {
+ container: {
+ marginBottom: 120,
+ },
+ filterBar: {
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ marginTop: 20,
+ marginBottom: 40,
+ },
+ tabNavigator: {
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'flex-start',
+ position: 'absolute',
+ width: '90%',
+ padding: 0,
+ },
+ tabActiveItem: {
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: 'floatingButtonBackground',
+ flex: 1,
+ height: 30,
+ borderRadius: 8,
+ },
+ tabItem: {
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: 'tabBarInactiveBackground',
+ flex: 1,
+ height: 30,
+ },
+ tabText: {
+ color: 'floatingButtonLabel',
+ },
+};
+
export default FullScreenThreadMediaGallery;
diff --git a/native/chat/settings/thread-settings-media-gallery.react.js b/native/chat/settings/thread-settings-media-gallery.react.js
--- a/native/chat/settings/thread-settings-media-gallery.react.js
+++ b/native/chat/settings/thread-settings-media-gallery.react.js
@@ -28,6 +28,8 @@
+threadID: string,
+limit: number,
+verticalBounds: ?VerticalBounds,
+ +offset?: number,
+ +activeTab?: string,
};
function ThreadSettingsMediaGallery(
@@ -47,8 +49,7 @@
// E.g. 16px, media, galleryItemGap, media, galleryItemGap, media, 16px
const galleryItemWidth =
(width - 32 - (numColumns - 1) * galleryItemGap) / numColumns;
-
- const { threadID, limit, verticalBounds } = props;
+ const { threadID, limit, verticalBounds, offset, activeTab } = props;
const [mediaInfos, setMediaInfos] = React.useState([]);
const callFetchThreadMedia = useServerCall(fetchThreadMedia);
@@ -175,12 +176,43 @@
],
);
+ const filteredMediaInfos = React.useMemo(() => {
+ if (!activeTab || activeTab === 'ALL') {
+ return mediaInfos;
+ } else if (activeTab === 'IMAGES') {
+ return mediaInfos.filter(mediaInfo => mediaInfo.type === 'photo');
+ } else if (activeTab === 'VIDEOS') {
+ return mediaInfos.filter(mediaInfo => mediaInfo.type === 'video');
+ }
+ }, [activeTab, mediaInfos]);
+
+ const onEndReached = React.useCallback(() => {
+ // Offset will be undefined if the media gallery is rendered in the
+ // thread settings (since no offset prop is passed in). If rendered in
+ // the full screen media gallery, offset will be defined and onEndReached
+ // will actually do something.
+ if (offset === undefined) {
+ return;
+ }
+
+ // As the FlatList fetches more media, we set the offset to be the length
+ // of mediaInfos. This will ensure that the next set of media is retrieved
+ // from the starting point.
+ callFetchThreadMedia({ threadID, limit, offset: mediaInfos.length }).then(
+ result => {
+ setMediaInfos([...mediaInfos, ...result.media]);
+ },
+ );
+ }, [callFetchThreadMedia, mediaInfos, threadID, limit, offset]);
+
return (
);
diff --git a/native/chat/settings/thread-settings.react.js b/native/chat/settings/thread-settings.react.js
--- a/native/chat/settings/thread-settings.react.js
+++ b/native/chat/settings/thread-settings.react.js
@@ -1046,6 +1046,7 @@
onPressSeeMoreMediaGallery = () => {
this.props.navigation.navigate(FullScreenThreadMediaGalleryRouteName, {
threadInfo: this.props.threadInfo,
+ verticalBounds: this.state.verticalBounds,
});
};
}
diff --git a/native/themes/colors.js b/native/themes/colors.js
--- a/native/themes/colors.js
+++ b/native/themes/colors.js
@@ -74,6 +74,7 @@
tabBarAccent: '#7E57C2',
tabBarBackground: '#F5F5F5',
tabBarActiveTintColor: '#7E57C2',
+ tabBarInactiveBackground: '#1F1F1F',
vibrantGreenButton: '#00C853',
vibrantRedButton: '#F53100',
tooltipBackground: '#E0E0E0',
@@ -158,6 +159,7 @@
tabBarAccent: '#AE94DB',
tabBarBackground: '#0A0A0A',
tabBarActiveTintColor: '#AE94DB',
+ tabBarInactiveBackground: '#1F1F1F',
vibrantGreenButton: '#00C853',
vibrantRedButton: '#F53100',
tooltipBackground: '#1F1F1F',