[Gekidou] Add saved messages to bottom tab (#6367)

This commit is contained in:
Elias Nahum 2022-06-09 15:19:24 -04:00 committed by GitHub
parent ecd877b5e4
commit 6906a9f863
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 303 additions and 317 deletions

View file

@ -111,7 +111,7 @@ const Body = ({
}, []);
const onLayout = useCallback((e: LayoutChangeEvent) => {
if (location === Screens.SAVED_POSTS) {
if (location === Screens.SAVED_MESSAGES) {
setLayoutWidth(e.nativeEvent.layout.width);
}
}, [location]);

View file

@ -133,7 +133,7 @@ const Post = ({
}, [isConsecutivePost, post, previousPost, isFirstReply]);
const handlePostPress = () => {
if ([Screens.SAVED_POSTS, Screens.MENTIONS, Screens.SEARCH, Screens.PINNED_MESSAGES].includes(location)) {
if ([Screens.SAVED_MESSAGES, Screens.MENTIONS, Screens.SEARCH, Screens.PINNED_MESSAGES].includes(location)) {
showPermalink(serverUrl, '', post.id, intl);
return;
}

View file

@ -37,7 +37,7 @@ export const PERMALINK = 'Permalink';
export const PINNED_MESSAGES = 'PinnedMessages';
export const POST_OPTIONS = 'PostOptions';
export const REACTIONS = 'Reactions';
export const SAVED_POSTS = 'SavedPosts';
export const SAVED_MESSAGES = 'SavedMessages';
export const SEARCH = 'Search';
export const SELECT_TEAM = 'SelectTeam';
export const SERVER = 'Server';
@ -91,7 +91,7 @@ export default {
PINNED_MESSAGES,
POST_OPTIONS,
REACTIONS,
SAVED_POSTS,
SAVED_MESSAGES,
SEARCH,
SELECT_TEAM,
SERVER,
@ -124,7 +124,6 @@ export const MODAL_SCREENS_WITHOUT_BACK = [
GALLERY,
PERMALINK,
REACTIONS,
SAVED_POSTS,
];
export const NOT_READY = [

View file

@ -3,14 +3,14 @@
import React, {useCallback, useMemo} from 'react';
import {useIntl} from 'react-intl';
import {DeviceEventEmitter, Keyboard, Platform, Text, View} from 'react-native';
import {Keyboard, Platform, Text, View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import CompassIcon from '@components/compass_icon';
import CustomStatusEmoji from '@components/custom_status/custom_status_emoji';
import NavigationHeader from '@components/navigation_header';
import RoundedHeaderContext from '@components/rounded_header_context';
import {General, Navigation, Screens} from '@constants';
import {General, Screens} from '@constants';
import {QUICK_OPTIONS_HEIGHT} from '@constants/view';
import {useTheme} from '@context/theme';
import {useIsTablet} from '@hooks/device';
@ -140,19 +140,22 @@ const ChannelHeader = ({
});
}, [channelId, channelType, isTablet, onTitlePress, theme]);
const rightButtons: HeaderRightButton[] = useMemo(() => ([{
iconName: 'magnify',
onPress: () => {
DeviceEventEmitter.emit(Navigation.NAVIGATE_TO_TAB, {screen: 'Search', params: {searchTerm: `in: ${searchTerm}`}});
if (!isTablet) {
popTopScreen(componentId);
}
},
}, {
iconName: Platform.select({android: 'dots-vertical', default: 'dots-horizontal'}),
onPress: onChannelQuickAction,
buttonType: 'opacity',
}]), [isTablet, searchTerm, onChannelQuickAction]);
const rightButtons: HeaderRightButton[] = useMemo(() => ([
// {
// iconName: 'magnify',
// onPress: () => {
// DeviceEventEmitter.emit(Navigation.NAVIGATE_TO_TAB, {screen: 'Search', params: {searchTerm: `in: ${searchTerm}`}});
// if (!isTablet) {
// popTopScreen(componentId);
// }
// },
// },
{
iconName: Platform.select({android: 'dots-vertical', default: 'dots-horizontal'}),
onPress: onChannelQuickAction,
buttonType: 'opacity',
}]), [isTablet, searchTerm, onChannelQuickAction]);
let title = displayName;
if (isOwnDirectMessage) {

View file

@ -10,7 +10,6 @@ import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import CustomStatus from './custom_status';
import Logout from './logout';
import SavedMessages from './saved_messages';
import Settings from './settings';
import UserPresence from './user_presence';
import YourProfile from './your_profile';
@ -82,11 +81,11 @@ const AccountOptions = ({user, enableCustomUserStatuses, isCustomStatusExpirySup
style={styles.menuLabel}
theme={theme}
/>
<SavedMessages
{/* <SavedMessages
isTablet={isTablet}
style={styles.menuLabel}
theme={theme}
/>
/> */}
<Settings
isTablet={isTablet}
style={styles.menuLabel}

View file

@ -1,65 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {DeviceEventEmitter, TextStyle} from 'react-native';
import CompassIcon from '@components/compass_icon';
import FormattedText from '@components/formatted_text';
import MenuItem from '@components/menu_item';
import {Events, Screens} from '@constants';
import {showModal} from '@screens/navigation';
import {preventDoubleTap} from '@utils/tap';
type Props = {
isTablet: boolean;
style: TextStyle;
theme: Theme;
}
const SavedMessages = ({isTablet, style, theme}: Props) => {
const intl = useIntl();
const openSavedMessages = useCallback(preventDoubleTap(() => {
if (isTablet) {
DeviceEventEmitter.emit(Events.ACCOUNT_SELECT_TABLET_VIEW, Screens.SAVED_POSTS);
} else {
const closeButtonId = 'close-saved-posts';
const icon = CompassIcon.getImageSourceSync('close', 24, theme.centerChannelColor);
const options = {
topBar: {
leftButtons: [{
id: closeButtonId,
testID: closeButtonId,
icon,
}],
},
};
showModal(
Screens.SAVED_POSTS,
intl.formatMessage({id: 'mobile.screen.saved_posts', defaultMessage: 'Saved Messages'}),
{closeButtonId},
options,
);
}
}), [isTablet]);
return (
<MenuItem
testID='account.saved_messages.action'
labelComponent={
<FormattedText
id='account.saved_messages'
defaultMessage='Saved Messages'
style={style}
/>
}
iconName='bookmark-outline'
onPress={openSavedMessages}
separator={false}
theme={theme}
/>
);
};
export default SavedMessages;

View file

@ -7,7 +7,6 @@ import {DeviceEventEmitter} from 'react-native';
import {Events, Screens} from '@constants';
import CustomStatus from '@screens/custom_status';
import EditProfile from '@screens/edit_profile';
import SavedPosts from '@screens/saved_posts';
type SelectedView = {
id: string;
@ -17,7 +16,6 @@ type SelectedView = {
const TabletView: Record<string, React.ReactNode> = {
[Screens.CUSTOM_STATUS]: CustomStatus,
[Screens.EDIT_PROFILE]: EditProfile,
[Screens.SAVED_POSTS]: SavedPosts,
};
const AccountTabletView = () => {

View file

@ -19,9 +19,11 @@ import {notificationError} from '@utils/notification';
import Account from './account';
import ChannelList from './channel_list';
import RecentMentions from './recent_mentions';
import Search from './search';
import SavedMessages from './saved_messages';
import TabBar from './tab_bar';
// import Search from './search';
import type {LaunchProps} from '@typings/launch';
if (Platform.OS === 'ios') {
@ -116,16 +118,21 @@ export default function HomeScreen(props: HomeProps) {
>
{() => <ChannelList {...props}/>}
</Tab.Screen>
<Tab.Screen
{/* <Tab.Screen
name={Screens.SEARCH}
component={Search}
options={{unmountOnBlur: false, lazy: true, tabBarTestID: 'tab_bar.search.tab'}}
/>
/> */}
<Tab.Screen
name={Screens.MENTIONS}
component={RecentMentions}
options={{tabBarTestID: 'tab_bar.mentions.tab', lazy: true, unmountOnBlur: false}}
/>
<Tab.Screen
name={Screens.SAVED_MESSAGES}
component={SavedMessages}
options={{unmountOnBlur: false, lazy: true, tabBarTestID: 'tab_bar.saved_messages.tab'}}
/>
<Tab.Screen
name={Screens.ACCOUNT}
component={Account}

View file

@ -4,7 +4,7 @@
import {useIsFocused, useRoute} from '@react-navigation/native';
import React, {useCallback, useState, useEffect, useMemo} from 'react';
import {useIntl} from 'react-intl';
import {ActivityIndicator, DeviceEventEmitter, FlatList, StyleSheet, View} from 'react-native';
import {ActivityIndicator, DeviceEventEmitter, FlatList, Platform, StyleSheet, View} from 'react-native';
import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import {SafeAreaView, Edge, useSafeAreaInsets} from 'react-native-safe-area-context';
@ -15,6 +15,7 @@ import DateSeparator from '@components/post_list/date_separator';
import PostWithChannelInfo from '@components/post_with_channel_info';
import RoundedHeaderContext from '@components/rounded_header_context';
import {Events, Screens} from '@constants';
import {BOTTOM_TAB_HEIGHT} from '@constants/view';
import {useServerUrl} from '@context/server';
import {useTheme} from '@context/theme';
import {useCollapsibleHeader} from '@hooks/header';
@ -38,6 +39,10 @@ const styles = StyleSheet.create({
flex: {
flex: 1,
},
container: {
flex: 1,
marginBottom: Platform.select({ios: BOTTOM_TAB_HEIGHT}),
},
empty: {
alignItems: 'center',
flex: 1,
@ -74,11 +79,13 @@ const RecentMentionsScreen = ({mentions, currentTimezone, isTimezoneEnabled}: Pr
}, [isFocused]);
useEffect(() => {
setLoading(true);
fetchRecentMentions(serverUrl).finally(() => {
setLoading(false);
});
}, [serverUrl]);
if (isFocused) {
setLoading(true);
fetchRecentMentions(serverUrl).finally(() => {
setLoading(false);
});
}
}, [serverUrl, isFocused]);
const {scrollPaddingTop, scrollRef, scrollValue, onScroll, headerHeight} = useCollapsibleHeader<FlatList<string>>(true, onSnap);
const paddingTop = useMemo(() => ({paddingTop: scrollPaddingTop - insets.top, flexGrow: 1}), [scrollPaddingTop, insets.top]);
@ -168,7 +175,7 @@ const RecentMentionsScreen = ({mentions, currentTimezone, isTimezoneEnabled}: Pr
style={styles.flex}
edges={EDGES}
>
<Animated.View style={[styles.flex, animated]}>
<Animated.View style={[styles.container, animated]}>
<Animated.View style={top}>
<RoundedHeaderContext/>
</Animated.View>

View file

@ -35,7 +35,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => ({
},
}));
function EmptySavedPosts() {
function EmptySavedMessages() {
const theme = useTheme();
const styles = getStyleSheet(theme);
@ -44,18 +44,18 @@ function EmptySavedPosts() {
<SavedPostsIcon style={styles.icon}/>
<FormattedText
defaultMessage='No saved messages yet'
id='saved_posts.empty.title'
id='saved_messages.empty.title'
style={styles.title}
testID='saved_posts.empty.title'
testID='saved_messages.empty.title'
/>
<FormattedText
defaultMessage={'To save something for later, long-press on a message and choose Save from the menu. Saved messages are only visible to you.'}
id='saved_posts.empty.paragraph'
id='saved_messages.empty.paragraph'
style={styles.paragraph}
testID='saved_posts.empty.paragraph'
testID='saved_messages.empty.paragraph'
/>
</View>
);
}
export default EmptySavedPosts;
export default EmptySavedMessages;

View file

@ -0,0 +1,207 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {useIsFocused, useRoute} from '@react-navigation/native';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {useIntl} from 'react-intl';
import {DeviceEventEmitter, FlatList, Platform, StyleSheet, View} from 'react-native';
import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import {Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
import {fetchSavedPosts} from '@actions/remote/post';
import FreezeScreen from '@components/freeze_screen';
import Loading from '@components/loading';
import NavigationHeader from '@components/navigation_header';
import DateSeparator from '@components/post_list/date_separator';
import PostWithChannelInfo from '@components/post_with_channel_info';
import RoundedHeaderContext from '@components/rounded_header_context';
import {Events, Screens} from '@constants';
import {BOTTOM_TAB_HEIGHT} from '@constants/view';
import {useServerUrl} from '@context/server';
import {useTheme} from '@context/theme';
import {useCollapsibleHeader} from '@hooks/header';
import {isDateLine, getDateForDateLine, selectOrderedPosts} from '@utils/post_list';
import EmptyState from './components/empty';
import type {ViewableItemsChanged} from '@typings/components/post_list';
import type PostModel from '@typings/database/models/servers/post';
type Props = {
currentTimezone: string | null;
isTimezoneEnabled: boolean;
posts: PostModel[];
}
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
const edges: Edge[] = ['bottom', 'left', 'right'];
const styles = StyleSheet.create({
flex: {
flex: 1,
},
container: {
flex: 1,
marginBottom: Platform.select({ios: BOTTOM_TAB_HEIGHT}),
},
empty: {
alignItems: 'center',
flex: 1,
justifyContent: 'center',
},
});
function SavedMessages({posts, currentTimezone, isTimezoneEnabled}: Props) {
const intl = useIntl();
const [loading, setLoading] = useState(!posts.length);
const [refreshing, setRefreshing] = useState(false);
const theme = useTheme();
const serverUrl = useServerUrl();
const route = useRoute();
const isFocused = useIsFocused();
const insets = useSafeAreaInsets();
const params = route.params as {direction: string};
const toLeft = params.direction === 'left';
const translateSide = toLeft ? -25 : 25;
const opacity = useSharedValue(isFocused ? 1 : 0);
const translateX = useSharedValue(isFocused ? 0 : translateSide);
const title = intl.formatMessage({id: 'screen.saved_messages.title', defaultMessage: 'Saved Messages'});
const subtitle = intl.formatMessage({id: 'screen.saved_messages.subtitle', defaultMessage: 'All messages you\'ve saved for follow up'});
const onSnap = (offset: number) => {
scrollRef.current?.scrollToOffset({offset, animated: true});
};
useEffect(() => {
opacity.value = isFocused ? 1 : 0;
translateX.value = isFocused ? 0 : translateSide;
}, [isFocused]);
useEffect(() => {
if (isFocused) {
setLoading(true);
fetchSavedPosts(serverUrl).finally(() => {
setLoading(false);
});
}
}, [serverUrl, isFocused]);
const {scrollPaddingTop, scrollRef, scrollValue, onScroll, headerHeight} = useCollapsibleHeader<FlatList<string>>(true, onSnap);
const paddingTop = useMemo(() => ({paddingTop: scrollPaddingTop - insets.top, flexGrow: 1}), [scrollPaddingTop, insets.top]);
const scrollViewStyle = useMemo(() => ({top: insets.top}), [insets.top]);
const data = useMemo(() => selectOrderedPosts(posts, 0, false, '', '', false, isTimezoneEnabled, currentTimezone, false).reverse(), [posts]);
const animated = useAnimatedStyle(() => {
return {
opacity: withTiming(opacity.value, {duration: 150}),
transform: [{translateX: withTiming(translateX.value, {duration: 150})}],
};
}, []);
const top = useAnimatedStyle(() => {
return {
top: headerHeight.value,
};
});
const onViewableItemsChanged = useCallback(({viewableItems}: ViewableItemsChanged) => {
if (!viewableItems.length) {
return;
}
const viewableItemsMap = viewableItems.reduce((acc: Record<string, boolean>, {item, isViewable}) => {
if (isViewable) {
acc[`${Screens.SAVED_MESSAGES}-${item.id}`] = true;
}
return acc;
}, {});
DeviceEventEmitter.emit(Events.ITEM_IN_VIEWPORT, viewableItemsMap);
}, []);
const handleRefresh = useCallback(async () => {
setRefreshing(true);
await fetchSavedPosts(serverUrl);
setRefreshing(false);
}, [serverUrl]);
const emptyList = useMemo(() => (
<View style={styles.empty}>
{loading ? (
<Loading
color={theme.buttonBg}
size='large'
/>
) : (
<EmptyState/>
)}
</View>
), [loading, theme.buttonBg]);
const renderItem = useCallback(({item}) => {
if (typeof item === 'string') {
if (isDateLine(item)) {
return (
<DateSeparator
date={getDateForDateLine(item)}
theme={theme}
timezone={isTimezoneEnabled ? currentTimezone : null}
/>
);
}
return null;
}
return (
<PostWithChannelInfo
location={Screens.SAVED_MESSAGES}
post={item}
/>
);
}, [currentTimezone, isTimezoneEnabled, theme]);
return (
<FreezeScreen freeze={!isFocused}>
<NavigationHeader
isLargeTitle={true}
showBackButton={false}
subtitle={subtitle}
title={title}
hasSearch={false}
scrollValue={scrollValue}
/>
<SafeAreaView
edges={edges}
style={styles.flex}
>
<Animated.View style={[styles.container, animated]}>
<Animated.View style={top}>
<RoundedHeaderContext/>
</Animated.View>
<AnimatedFlatList
ref={scrollRef}
contentContainerStyle={paddingTop}
ListEmptyComponent={emptyList}
data={data}
onRefresh={handleRefresh}
refreshing={refreshing}
renderItem={renderItem}
scrollToOverflowEnabled={true}
showsVerticalScrollIndicator={false}
progressViewOffset={scrollPaddingTop}
scrollEventThrottle={16}
indicatorStyle='black'
onScroll={onScroll}
removeClippedSubviews={true}
onViewableItemsChanged={onViewableItemsChanged}
style={scrollViewStyle}
/>
</Animated.View>
</SafeAreaView>
</FreezeScreen>
);
}
export default SavedMessages;

View file

@ -14,6 +14,7 @@ import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import Account from './account';
import Home from './home';
import Mentions from './mentions';
import SavedMessages from './saved_messages';
import Search from './search';
import type {BottomTabBarProps} from '@react-navigation/bottom-tabs';
@ -55,6 +56,7 @@ const TabComponents: Record<string, any> = {
Account,
Home,
Mentions,
SavedMessages,
Search,
};

View file

@ -0,0 +1,28 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {View} from 'react-native';
import CompassIcon from '@components/compass_icon';
import {BOTTOM_TAB_ICON_SIZE} from '@constants/view';
import {changeOpacity} from '@utils/theme';
type Props = {
isFocused: boolean;
theme: Theme;
}
const SaveMessages = ({isFocused, theme}: Props) => {
return (
<View>
<CompassIcon
size={BOTTOM_TAB_ICON_SIZE}
name='bookmark-outline'
color={isFocused ? theme.buttonBg : changeOpacity(theme.centerChannelColor, 0.48)}
/>
</View>
);
};
export default SaveMessages;

View file

@ -161,9 +161,6 @@ Navigation.setLazyComponentRegistrator((screenName) => {
case Screens.REACTIONS:
screen = withServerDatabase(require('@screens/reactions').default);
break;
case Screens.SAVED_POSTS:
screen = withServerDatabase((require('@screens/saved_posts').default));
break;
case Screens.SETTINGS:
screen = withServerDatabase(require('@screens/settings').default);
break;

View file

@ -1,203 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {useIntl} from 'react-intl';
import {BackHandler, DeviceEventEmitter, FlatList, StyleSheet, View} from 'react-native';
import {EventSubscription, Navigation} from 'react-native-navigation';
import {Edge, SafeAreaView} from 'react-native-safe-area-context';
import {fetchSavedPosts} from '@actions/remote/post';
import Loading from '@components/loading';
import DateSeparator from '@components/post_list/date_separator';
import PostWithChannelInfo from '@components/post_with_channel_info';
import TabletTitle from '@components/tablet_title';
import {Events, Screens} from '@constants';
import {useServerUrl} from '@context/server';
import {useTheme} from '@context/theme';
import {dismissModal} from '@screens/navigation';
import EphemeralStore from '@store/ephemeral_store';
import {isDateLine, getDateForDateLine, selectOrderedPosts} from '@utils/post_list';
import EmptyState from './components/empty';
import type {ViewableItemsChanged} from '@typings/components/post_list';
import type PostModel from '@typings/database/models/servers/post';
type Props = {
componentId?: string;
closeButtonId?: string;
currentTimezone: string | null;
isTimezoneEnabled: boolean;
isTablet?: boolean;
posts: PostModel[];
}
const edges: Edge[] = ['bottom', 'left', 'right'];
const styles = StyleSheet.create({
flex: {
flex: 1,
},
empty: {
alignItems: 'center',
flex: 1,
justifyContent: 'center',
},
list: {
paddingVertical: 8,
},
loading: {
height: 40,
width: 40,
justifyContent: 'center' as const,
},
});
function SavedMessages({
componentId,
closeButtonId,
posts,
currentTimezone,
isTimezoneEnabled,
isTablet,
}: Props) {
const intl = useIntl();
const [loading, setLoading] = useState(!posts.length);
const [refreshing, setRefreshing] = useState(false);
const theme = useTheme();
const serverUrl = useServerUrl();
const data = useMemo(() => selectOrderedPosts(posts, 0, false, '', '', false, isTimezoneEnabled, currentTimezone, false).reverse(), [posts]);
const close = () => {
if (componentId) {
dismissModal({componentId});
}
};
useEffect(() => {
fetchSavedPosts(serverUrl).finally(() => {
setLoading(false);
});
}, []);
useEffect(() => {
let unsubscribe: EventSubscription | undefined;
if (componentId && closeButtonId) {
unsubscribe = Navigation.events().registerComponentListener({
navigationButtonPressed: ({buttonId}: { buttonId: string }) => {
switch (buttonId) {
case closeButtonId:
close();
break;
}
},
}, componentId);
}
return () => {
unsubscribe?.remove();
};
}, [componentId, closeButtonId]);
useEffect(() => {
let listener: EventSubscription|undefined;
if (!isTablet && componentId) {
listener = BackHandler.addEventListener('hardwareBackPress', () => {
if (EphemeralStore.getNavigationTopComponentId() === componentId) {
close();
return true;
}
return false;
});
}
return () => listener?.remove();
}, [componentId, isTablet]);
const onViewableItemsChanged = useCallback(({viewableItems}: ViewableItemsChanged) => {
if (!viewableItems.length) {
return;
}
const viewableItemsMap = viewableItems.reduce((acc: Record<string, boolean>, {item, isViewable}) => {
if (isViewable) {
acc[`${Screens.SAVED_POSTS}-${item.id}`] = true;
}
return acc;
}, {});
DeviceEventEmitter.emit(Events.ITEM_IN_VIEWPORT, viewableItemsMap);
}, []);
const handleRefresh = useCallback(async () => {
setRefreshing(true);
await fetchSavedPosts(serverUrl);
setRefreshing(false);
}, [serverUrl]);
const emptyList = useMemo(() => (
<View style={styles.empty}>
{loading ? (
<Loading
color={theme.buttonBg}
size='large'
/>
) : (
<EmptyState/>
)}
</View>
), [loading, theme.buttonBg]);
const renderItem = useCallback(({item}) => {
if (typeof item === 'string') {
if (isDateLine(item)) {
return (
<DateSeparator
date={getDateForDateLine(item)}
theme={theme}
timezone={isTimezoneEnabled ? currentTimezone : null}
/>
);
}
return null;
}
return (
<PostWithChannelInfo
location={Screens.SAVED_POSTS}
post={item}
/>
);
}, [currentTimezone, isTimezoneEnabled, theme]);
return (
<>
{isTablet &&
<TabletTitle
testID='custom_status.done.button'
title={intl.formatMessage({id: 'mobile.screen.saved_posts', defaultMessage: 'Saved Messages'})}
/>
}
<SafeAreaView
edges={edges}
style={styles.flex}
>
<FlatList
contentContainerStyle={data.length ? styles.list : [styles.empty]}
ListEmptyComponent={emptyList}
data={data}
onRefresh={handleRefresh}
refreshing={refreshing}
renderItem={renderItem}
scrollToOverflowEnabled={true}
onViewableItemsChanged={onViewableItemsChanged}
/>
</SafeAreaView>
</>
);
}
export default SavedMessages;

View file

@ -104,7 +104,7 @@ const SnackBar = ({barType, componentId, onAction, sourceScreen}: SnackBarProps)
marginBottom: 30,
};
break;
case sourceScreen === Screens.SAVED_POSTS :
case sourceScreen === Screens.SAVED_MESSAGES :
tabletStyle = {
marginBottom: 20,
marginLeft: TABLET_SIDEBAR_WIDTH,

View file

@ -11,7 +11,6 @@
"about.teamEditiont1": "Enterprise Edition",
"account.logout": "Log out",
"account.logout_from": "Log out of {serverName}",
"account.saved_messages": "Saved Messages",
"account.settings": "Settings",
"account.user_status.title": "User Presence",
"account.your_profile": "Your Profile",
@ -129,16 +128,22 @@
"channel_info.leave_channel": "Leave channel",
"channel_info.leave_private_channel": "Are you sure you want to leave the private channel {displayName}? You cannot rejoin the channel unless you're invited again.",
"channel_info.leave_public_channel": "Are you sure you want to leave the public channel {displayName}? You can always rejoin.",
"channel_info.local_time": "Local Time",
"channel_info.members": "Members",
"channel_info.mention": "Mention",
"channel_info.mobile_notifications": "Mobile Notifications",
"channel_info.muted": "Mute",
"channel_info.nickname": "Nickname",
"channel_info.notification.all": "All",
"channel_info.notification.default": "Default",
"channel_info.notification.mention": "Mentions",
"channel_info.notification.none": "Never",
"channel_info.pinned_messages": "Pinned Messages",
"channel_info.position": "Position",
"channel_info.private_channel": "Private Channel",
"channel_info.public_channel": "Public Channel",
"channel_info.send_a_mesasge": "Send a message",
"channel_info.send_mesasge": "Send message",
"channel_info.set_header": "Set Header",
"channel_info.unarchive": "Unarchive Channel",
"channel_info.unarchive_description": "Are you sure you want to unarchive the {term} {name}?",
@ -498,7 +503,6 @@
"mobile.routes.custom_status": "Set a Status",
"mobile.routes.table": "Table",
"mobile.routes.user_profile": "Profile",
"mobile.screen.saved_posts": "Saved Messages",
"mobile.screen.settings": "Settings",
"mobile.screen.your_profile": "Your Profile",
"mobile.search.jump": "Jump to recent messages",
@ -621,10 +625,12 @@
"post.reactions.title": "Reactions",
"posts_view.newMsg": "New Messages",
"public_link_copied": "Link copied to clipboard",
"saved_posts.empty.paragraph": "To save something for later, long-press on a message and choose Save from the menu. Saved messages are only visible to you.",
"saved_posts.empty.title": "No saved messages yet",
"saved_messages.empty.paragraph": "To save something for later, long-press on a message and choose Save from the menu. Saved messages are only visible to you.",
"saved_messages.empty.title": "No saved messages yet",
"screen.mentions.subtitle": "Messages you've been mentioned in",
"screen.mentions.title": "Recent Mentions",
"screen.saved_messages.subtitle": "All messages you've saved for follow up",
"screen.saved_messages.title": "Saved Messages",
"screen.search.header.files": "Files",
"screen.search.header.messages": "Messages",
"screen.search.placeholder": "Search messages & files",
@ -712,6 +718,7 @@
"user.settings.general.nickname": "Nickname",
"user.settings.general.position": "Position",
"user.settings.general.username": "Username",
"user.tutorial.long_press": "Long-press on an item to view a user's profile",
"video.download": "Download video",
"video.failed_description": "An error occurred while trying to play the video.\n",
"video.failed_title": "Video playback failed",