diff --git a/native/chat/chat-thread-list-item.react.js b/native/chat/chat-thread-list-item.react.js
index c95bf8082..7ed332645 100644
--- a/native/chat/chat-thread-list-item.react.js
+++ b/native/chat/chat-thread-list-item.react.js
@@ -1,328 +1,308 @@
// @flow
import Icon from '@expo/vector-icons/FontAwesome.js';
import * as React from 'react';
import { Text, View } from 'react-native';
import type { ChatThreadItem } from 'lib/selectors/chat-selectors.js';
import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js';
import { threadTypeIsThick } from 'lib/types/thread-types-enum.js';
import type { UserInfo } from 'lib/types/user-types.js';
import { shortAbsoluteDate } from 'lib/utils/date-utils.js';
import { useResolvedThreadInfo } from 'lib/utils/entity-helpers.js';
import ChatThreadListSeeMoreSidebars from './chat-thread-list-see-more-sidebars.react.js';
import ChatThreadListSidebar from './chat-thread-list-sidebar.react.js';
import MessagePreview from './message-preview.react.js';
import SwipeableThread from './swipeable-thread.react.js';
import ThreadAvatar from '../avatars/thread-avatar.react.js';
import Button from '../components/button.react.js';
import SingleLine from '../components/single-line.react.js';
import ThreadAncestorsLabel from '../components/thread-ancestors-label.react.js';
import UnreadDot from '../components/unread-dot.react.js';
import { useColors, useStyles } from '../themes/colors.js';
type Props = {
+data: ChatThreadItem,
+onPressItem: (
threadInfo: ThreadInfo,
pendingPersonalThreadUserInfo?: UserInfo,
) => void,
+onPressSeeMoreSidebars: (threadInfo: ThreadInfo) => void,
+onSwipeableWillOpen: (threadInfo: ThreadInfo) => void,
+currentlyOpenedSwipeableId: string,
};
function ChatThreadListItem({
data,
onPressItem,
onPressSeeMoreSidebars,
onSwipeableWillOpen,
currentlyOpenedSwipeableId,
}: Props): React.Node {
const styles = useStyles(unboundStyles);
const colors = useColors();
- const lastMessage = React.useMemo(() => {
- const mostRecentMessageInfo = data.mostRecentMessageInfo;
- if (!mostRecentMessageInfo) {
- return (
-
- No messages
-
- );
- }
- return (
-
- );
- }, [data.mostRecentMessageInfo, data.threadInfo, styles]);
-
const numOfSidebarsWithExtendedArrow =
data.sidebars.filter(sidebarItem => sidebarItem.type === 'sidebar').length -
1;
const sidebars = React.useMemo(
() =>
data.sidebars.map((sidebarItem, index) => {
if (sidebarItem.type === 'sidebar') {
const { type, ...sidebarInfo } = sidebarItem;
return (
);
} else if (sidebarItem.type === 'seeMore') {
return (
);
} else {
return ;
}
}),
[
currentlyOpenedSwipeableId,
data.sidebars,
data.threadInfo,
numOfSidebarsWithExtendedArrow,
onPressItem,
onPressSeeMoreSidebars,
onSwipeableWillOpen,
styles.spacer,
],
);
const onPress = React.useCallback(() => {
onPressItem(data.threadInfo, data.pendingPersonalThreadUserInfo);
}, [onPressItem, data.threadInfo, data.pendingPersonalThreadUserInfo]);
const threadNameStyle = React.useMemo(() => {
if (!data.threadInfo.currentUser.unread) {
return styles.threadName;
}
return [styles.threadName, styles.unreadThreadName];
}, [
data.threadInfo.currentUser.unread,
styles.threadName,
styles.unreadThreadName,
]);
const lastActivity = shortAbsoluteDate(data.lastUpdatedTime);
const lastActivityStyle = React.useMemo(() => {
if (!data.threadInfo.currentUser.unread) {
return styles.lastActivity;
}
return [styles.lastActivity, styles.unreadLastActivity];
}, [
data.threadInfo.currentUser.unread,
styles.lastActivity,
styles.unreadLastActivity,
]);
const resolvedThreadInfo = useResolvedThreadInfo(data.threadInfo);
const unreadDot = React.useMemo(
() => (
),
[data.threadInfo.currentUser.unread, styles.avatarContainer],
);
const threadAvatar = React.useMemo(
() => (
),
[data.threadInfo, styles.avatarContainer],
);
const isThick = threadTypeIsThick(data.threadInfo.type);
const iconStyle = data.threadInfo.currentUser.unread
? styles.iconUnread
: styles.iconRead;
const iconName = isThick ? 'lock' : 'server';
const threadDetails = React.useMemo(
() => (
{resolvedThreadInfo.uiName}
- {lastMessage}
+
{lastActivity}
),
[
iconStyle,
data.threadInfo,
iconName,
lastActivity,
lastActivityStyle,
- lastMessage,
resolvedThreadInfo.uiName,
styles.header,
styles.iconContainer,
styles.row,
styles.threadDetails,
threadNameStyle,
+ data.mostRecentMessageInfo,
],
);
const swipeableThreadContent = React.useMemo(
() => (
),
[
colors.listIosHighlightUnderlay,
onPress,
styles.container,
styles.content,
threadAvatar,
threadDetails,
unreadDot,
],
);
const swipeableThread = React.useMemo(
() => (
{swipeableThreadContent}
),
[
currentlyOpenedSwipeableId,
data.mostRecentNonLocalMessage,
data.threadInfo,
onSwipeableWillOpen,
swipeableThreadContent,
],
);
const chatThreadListItem = React.useMemo(
() => (
<>
{swipeableThread}
{sidebars}
>
),
[sidebars, swipeableThread],
);
return chatThreadListItem;
}
const chatThreadListItemHeight = 70;
const spacerHeight = 6;
const unboundStyles = {
container: {
height: chatThreadListItemHeight,
justifyContent: 'center',
backgroundColor: 'listBackground',
},
content: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
avatarContainer: {
marginLeft: 6,
marginBottom: 12,
},
threadDetails: {
paddingLeft: 12,
paddingRight: 18,
justifyContent: 'center',
flex: 1,
marginTop: 5,
},
lastActivity: {
color: 'listForegroundTertiaryLabel',
fontSize: 14,
marginLeft: 10,
},
unreadLastActivity: {
color: 'listForegroundLabel',
fontWeight: 'bold',
},
- noMessages: {
- color: 'listForegroundTertiaryLabel',
- flex: 1,
- fontSize: 14,
- fontStyle: 'italic',
- },
row: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
threadName: {
color: 'listForegroundSecondaryLabel',
flex: 1,
fontSize: 21,
},
unreadThreadName: {
color: 'listForegroundLabel',
fontWeight: '500',
},
spacer: {
height: spacerHeight,
},
header: {
flexDirection: 'row',
alignItems: 'center',
},
iconContainer: {
marginRight: 6,
},
iconRead: {
color: 'listForegroundTertiaryLabel',
},
iconUnread: {
color: 'listForegroundLabel',
},
};
export { ChatThreadListItem, chatThreadListItemHeight, spacerHeight };
diff --git a/native/chat/message-preview.react.js b/native/chat/message-preview.react.js
index bd37943e6..3469c3fa2 100644
--- a/native/chat/message-preview.react.js
+++ b/native/chat/message-preview.react.js
@@ -1,93 +1,102 @@
// @flow
import invariant from 'invariant';
import * as React from 'react';
import { Text } from 'react-native';
import { useThreadChatMentionCandidates } from 'lib/hooks/chat-mention-hooks.js';
import { useMessagePreview } from 'lib/shared/message-utils.js';
import { type MessageInfo } from 'lib/types/message-types.js';
import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js';
import SingleLine from '../components/single-line.react.js';
import { getDefaultTextMessageRules } from '../markdown/rules.react.js';
import { useStyles } from '../themes/colors.js';
type Props = {
- +messageInfo: MessageInfo,
+ +messageInfo: ?MessageInfo,
+threadInfo: ThreadInfo,
};
function MessagePreview(props: Props): React.Node {
const { messageInfo, threadInfo } = props;
const chatMentionCandidates = useThreadChatMentionCandidates(threadInfo);
const messagePreviewResult = useMessagePreview(
messageInfo,
threadInfo,
getDefaultTextMessageRules(chatMentionCandidates).simpleMarkdownRules,
);
- invariant(
- messagePreviewResult,
- 'useMessagePreview should only return falsey if pass null or undefined',
- );
+ const styles = useStyles(unboundStyles);
+ if (!messagePreviewResult) {
+ return (
+
+ No messages
+
+ );
+ }
const { message, username } = messagePreviewResult;
let messageStyle;
- const styles = useStyles(unboundStyles);
if (message.style === 'unread') {
messageStyle = styles.unread;
} else if (message.style === 'primary') {
messageStyle = styles.primary;
} else if (message.style === 'secondary') {
messageStyle = styles.secondary;
}
invariant(
messageStyle,
`MessagePreview doesn't support ${message.style} style for message, ` +
'only unread, primary, and secondary',
);
if (!username) {
return (
{message.text}
);
}
let usernameStyle;
if (username.style === 'unread') {
usernameStyle = styles.unread;
} else if (username.style === 'secondary') {
usernameStyle = styles.secondary;
}
invariant(
usernameStyle,
`MessagePreview doesn't support ${username.style} style for username, ` +
'only unread and secondary',
);
return (
{`${username.text}: `}
{message.text}
);
}
const unboundStyles = {
lastMessage: {
flex: 1,
fontSize: 14,
},
primary: {
color: 'listForegroundTertiaryLabel',
},
secondary: {
color: 'listForegroundTertiaryLabel',
},
unread: {
color: 'listForegroundLabel',
},
+ noMessages: {
+ color: 'listForegroundTertiaryLabel',
+ flex: 1,
+ fontSize: 14,
+ fontStyle: 'italic',
+ },
};
export default MessagePreview;
diff --git a/native/chat/subchannel-item.react.js b/native/chat/subchannel-item.react.js
index f25727da1..c2c5e8cbd 100644
--- a/native/chat/subchannel-item.react.js
+++ b/native/chat/subchannel-item.react.js
@@ -1,109 +1,90 @@
// @flow
import * as React from 'react';
import { Text, View } from 'react-native';
import type { ChatThreadItem } from 'lib/selectors/chat-selectors.js';
import { shortAbsoluteDate } from 'lib/utils/date-utils.js';
import { useResolvedThreadInfo } from 'lib/utils/entity-helpers.js';
import MessagePreview from './message-preview.react.js';
import SingleLine from '../components/single-line.react.js';
import SWMansionIcon from '../components/swmansion-icon.react.js';
import { useStyles } from '../themes/colors.js';
type Props = {
+subchannelInfo: ChatThreadItem,
};
function SubchannelItem(props: Props): React.Node {
const { lastUpdatedTime, threadInfo, mostRecentMessageInfo } =
props.subchannelInfo;
const { uiName } = useResolvedThreadInfo(threadInfo);
const lastActivity = shortAbsoluteDate(lastUpdatedTime);
const styles = useStyles(unboundStyles);
const unreadStyle = threadInfo.currentUser.unread ? styles.unread : null;
- const lastMessage = React.useMemo(() => {
- if (!mostRecentMessageInfo) {
- return (
-
- No messages
-
- );
- }
- return (
-
- );
- }, [mostRecentMessageInfo, threadInfo, styles]);
-
return (
{uiName}
- {lastMessage}
+
{lastActivity}
);
}
const fontSize = 14;
const unboundStyles = {
outerView: {
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
paddingVertical: 8,
paddingHorizontal: 8,
height: 60,
},
itemRowContainer: {
flexDirection: 'row',
alignItems: 'center',
},
unread: {
color: 'listForegroundLabel',
fontWeight: 'bold',
},
name: {
color: 'listForegroundSecondaryLabel',
flex: 1,
fontSize: 16,
paddingBottom: 8,
},
lastActivity: {
color: 'listForegroundTertiaryLabel',
fontSize,
marginLeft: 10,
},
iconWrapper: {
marginRight: 8,
alignItems: 'center',
},
icon: {
fontSize: 22,
color: 'listForegroundSecondaryLabel',
alignItems: 'center',
height: 24,
},
- noMessages: {
- color: 'listForegroundTertiaryLabel',
- flex: 1,
- fontSize,
- fontStyle: 'italic',
- },
};
export default SubchannelItem;