Skip to content

Commit

Permalink
Merge pull request #2725 from GetStream/develop
Browse files Browse the repository at this point in the history
Next Release
  • Loading branch information
khushal87 authored Oct 24, 2024
2 parents 5ff6ad4 + 2a7cee3 commit 98abaed
Show file tree
Hide file tree
Showing 16 changed files with 156 additions and 85 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Boolean to enable/disable the message underlay background when there are unread messages in the Message List.

| Type | Default |
| ---------------------- | ------- |
| `boolean`\|`undefined` | `true` |
5 changes: 5 additions & 0 deletions docusaurus/docs/reactnative/contexts/messages-context.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import OverlayReactionList from '../common-content/ui-components/overlay-provide
import ReactionList from '../common-content/ui-components/channel/props/reaction-list.mdx';
import Reply from '../common-content/ui-components/channel/props/reply.mdx';
import ScrollToBottomButton from '../common-content/ui-components/channel/props/scroll-to-bottom-button.mdx';
import ShouldShowUnreadUnderlay from '../common-content/ui-components/channel/props/should_show_unread_underlay.mdx';
import SelectReaction from '../common-content/ui-components/channel/props/select_reaction.mdx';
import SupportedReactions from '../common-content/ui-components/channel/props/supported_reactions.mdx';
import TypingIndicator from '../common-content/ui-components/channel/props/typing_indicator.mdx';
Expand Down Expand Up @@ -235,6 +236,10 @@ Enables quoted-reply state on given message.
| ------------------- |
| `(message) => void` |

### <div class="label description">_forwarded from [Channel](../../core-components/channel#shouldshowunreadunderlay)_ props</div> shouldShowUnreadUnderlay {#shouldshowunreadunderlay}

<ShouldShowUnreadUnderlay />

### <div class="label description">_forwarded from [Channel](../../core-components/channel#supportedreactions)_ props</div> supportedReactions {#supportedreactions}

<SupportedReactions />
Expand Down
4 changes: 4 additions & 0 deletions docusaurus/docs/reactnative/core-components/channel-list.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ export const App = () => <OverlayProvider>
</OverlayProvider>;
```

:::note
When receiving channel information from channel events, the filters are not respected; the reason for this is that channel filters can get very complex, and implementing that filtering logic that supports all of the custom filter would be very hard to do. Implementing this on the backend side isn't an option as it is inefficient and has to cater to different filters. So, to help you with it, you will have to override the `notification.message_new` event using the [`onNewMessageNotification`](./channel-list.mdx#onnewmessagenotification) and `message.new` event handlers using the [`onNewMessage`](./channel-list.mdx#onnewmessage) prop of the `ChannelList` component.
:::

## Context Providers

`ChannelList` contains the provider for the `ChannelsContext`. This can be accessed using the corresponding hook.
Expand Down
5 changes: 5 additions & 0 deletions docusaurus/docs/reactnative/core-components/channel.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ import ScrollToBottomButton from '../common-content/ui-components/channel/props/
import SelectReaction from '../common-content/ui-components/channel/props/select_reaction.mdx';
import SendButton from '../common-content/ui-components/channel/props/send_button.mdx';
import SendMessageDisallowedIndicator from '../common-content/ui-components/channel/props/send_message_disallowed_indicator.mdx';
import ShouldShowUnreadUnderlay from '../common-content/ui-components/channel/props/should_show_unread_underlay.mdx';
import ShowThreadMessageInChannelButton from '../common-content/ui-components/channel/props/show_thread_message_in_channel_button.mdx';
import StartAudioRecordingButton from '../common-content/ui-components/channel/props/start_audio_recording_button.mdx';
import StateUpdateThrottleInterval from '../common-content/ui-components/channel/props/state_update_throttle_interval.mdx';
Expand Down Expand Up @@ -702,6 +703,10 @@ Callback function to set the [ref](https://reactjs.org/docs/refs-and-the-dom.htm
| --------- | -------------------- |
| ref | ref of the TextInput |

### `shouldShowUnreadUnderlay`

<ShouldShowUnreadUnderlay />

### stateUpdateThrottleInterval

<StateUpdateThrottleInterval />
Expand Down
3 changes: 3 additions & 0 deletions package/src/components/Channel/Channel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ export type ChannelPropsWithContext<
| 'OverlayReactionList'
| 'ReactionList'
| 'Reply'
| 'shouldShowUnreadUnderlay'
| 'ScrollToBottomButton'
| 'selectReaction'
| 'supportedReactions'
Expand Down Expand Up @@ -582,6 +583,7 @@ const ChannelWithContext = <
setTyping,
setWatcherCount,
setWatchers,
shouldShowUnreadUnderlay = true,
shouldSyncChannel,
ShowThreadMessageInChannelButton = ShowThreadMessageInChannelButtonDefault,
StartAudioRecordingButton = AudioRecordingButtonDefault,
Expand Down Expand Up @@ -2412,6 +2414,7 @@ const ChannelWithContext = <
sendReaction,
setEditingState,
setQuotedMessageState,
shouldShowUnreadUnderlay,
supportedReactions,
targetedMessage,
TypingIndicator,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export const useCreateMessagesContext = <
sendReaction,
setEditingState,
setQuotedMessageState,
shouldShowUnreadUnderlay,
supportedReactions,
targetedMessage,
TypingIndicator,
Expand Down Expand Up @@ -183,6 +184,7 @@ export const useCreateMessagesContext = <
sendReaction,
setEditingState,
setQuotedMessageState,
shouldShowUnreadUnderlay,
supportedReactions,
targetedMessage,
TypingIndicator,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const styles = StyleSheet.create({
},
innerContainer: {
flexDirection: 'row',
height: 56,
minHeight: 56,
},
leftContainer: {
flex: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const styles = StyleSheet.create({
},
innerContainer: {
flexDirection: 'row',
height: 56,
minHeight: 56,
},
leftContainer: {
flex: 1,
Expand Down
6 changes: 3 additions & 3 deletions package/src/components/Message/Message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,8 @@ const MessageWithContext = <
const { client } = chatContext;
const {
theme: {
colors: { bg_gradient_start, targetedMessageBackground },
messageSimple: { targetedMessageContainer, targetedMessageUnderlay },
colors: { targetedMessageBackground },
messageSimple: { targetedMessageContainer, targetedMessageUnderlay, unreadUnderlayColor },
},
} = useTheme();

Expand Down Expand Up @@ -762,7 +762,7 @@ const MessageWithContext = <
style={[
style,
{
backgroundColor: showUnreadUnderlay ? bg_gradient_start : undefined,
backgroundColor: showUnreadUnderlay ? unreadUnderlayColor : undefined,
},
]}
>
Expand Down
9 changes: 8 additions & 1 deletion package/src/components/MessageList/MessageList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ type MessageListPropsWithContext<
| 'ScrollToBottomButton'
| 'MessageSystem'
| 'myMessageTheme'
| 'shouldShowUnreadUnderlay'
| 'TypingIndicator'
| 'TypingIndicatorContainer'
> &
Expand Down Expand Up @@ -270,6 +271,7 @@ const MessageListWithContext = <
setMessages,
setSelectedPicker,
setTargetedMessage,
shouldShowUnreadUnderlay,
StickyHeader,
targetedMessage,
thread,
Expand Down Expand Up @@ -630,7 +632,10 @@ const MessageListWithContext = <

const isCurrentMessageUnread = isMessageUnread(index);
const showUnreadUnderlay =
!channel.muteStatus().muted && isCurrentMessageUnread && scrollToBottomButtonVisible;
!!shouldShowUnreadUnderlay &&
!channel.muteStatus().muted &&
isCurrentMessageUnread &&
scrollToBottomButtonVisible;
const insertInlineUnreadIndicator = showUnreadUnderlay && !isMessageUnread(index + 1); // show only if previous message is read

if (message.type === 'system') {
Expand Down Expand Up @@ -1260,6 +1265,7 @@ export const MessageList = <
MessageSystem,
myMessageTheme,
ScrollToBottomButton,
shouldShowUnreadUnderlay,
TypingIndicator,
TypingIndicatorContainer,
} = useMessagesContext<StreamChatGenerics>();
Expand Down Expand Up @@ -1309,6 +1315,7 @@ export const MessageList = <
setMessages,
setSelectedPicker,
setTargetedMessage,
shouldShowUnreadUnderlay,
StickyHeader,
targetedMessage,
thread,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,13 @@ export const getDateSeparators = <
const isDeletedMessageVisibleToSender =
deletedMessagesVisibilityType === 'sender' || deletedMessagesVisibilityType === 'always';

const isDeletedMessageVisibleToReceiver =
deletedMessagesVisibilityType === 'receiver' || deletedMessagesVisibilityType === 'always';

return (
!isMessageTypeDeleted || (userId === message.user?.id && isDeletedMessageVisibleToSender)
!isMessageTypeDeleted ||
(userId === message.user?.id && isDeletedMessageVisibleToSender) ||
(userId !== message.user?.id && isDeletedMessageVisibleToReceiver)
);
});

Expand Down
168 changes: 93 additions & 75 deletions package/src/components/MessageList/utils/getGroupStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { PaginatedMessageListContextValue } from '../../../contexts/paginat
import type { ThreadContextValue } from '../../../contexts/threadContext/ThreadContext';
import type { DefaultStreamChatGenerics } from '../../../types/types';
import { isEditedMessage } from '../../../utils/utils';
import type { GroupType } from '../hooks/useMessageList';
import type { GroupType, MessageType } from '../hooks/useMessageList';

export type GetGroupStylesParams<
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
Expand All @@ -19,6 +19,88 @@ export type GetGroupStylesParams<
userId?: string;
};

export type GroupStyle = '' | 'middle' | 'top' | 'bottom' | 'single';

const getGroupStyle = <
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
>(
dateSeparators: DateSeparators,
message: MessageType<StreamChatGenerics>,
previousMessage: MessageType<StreamChatGenerics>,
nextMessage: MessageType<StreamChatGenerics>,
hideDateSeparators?: boolean,
maxTimeBetweenGroupedMessages?: number,
): GroupStyle[] => {
const groupStyles: GroupStyle[] = [];

const isPrevMessageTypeDeleted = previousMessage?.type === 'deleted';
const isNextMessageTypeDeleted = nextMessage?.type === 'deleted';

const userId = message?.user?.id || null;

const isTopMessage =
!previousMessage ||
previousMessage.type === 'system' ||
previousMessage.type === 'error' ||
userId !== previousMessage?.user?.id ||
!!isPrevMessageTypeDeleted ||
(!hideDateSeparators && dateSeparators[message.id]) ||
isEditedMessage(previousMessage);

const isBottomMessage =
!nextMessage ||
nextMessage.type === 'system' ||
nextMessage.type === 'error' ||
userId !== nextMessage?.user?.id ||
!!isNextMessageTypeDeleted ||
(!hideDateSeparators && dateSeparators[nextMessage.id]) ||
(maxTimeBetweenGroupedMessages !== undefined &&
(nextMessage.created_at as Date).getTime() - (message.created_at as Date).getTime() >
maxTimeBetweenGroupedMessages) ||
isEditedMessage(message);

/**
* Add group styles key for top message
*/
if (isTopMessage) {
groupStyles.push('top');
}

/**
* Add group styles key for bottom message
*/

const isMessageTypeDeleted = message.type === 'deleted';
if (isBottomMessage) {
/**
* If the bottom message is also the top, or deleted, or an error,
* add the key for single message instead of bottom
*/
if (isTopMessage || isMessageTypeDeleted || message.type === 'error') {
groupStyles.splice(0, groupStyles.length);
groupStyles.push('single');
} else {
groupStyles.push('bottom');
}
}

/**
* Add the key for all non top or bottom messages, if the message is
* deleted or an error add the key for single otherwise middle
*/
if (!isTopMessage && !isBottomMessage) {
if (isMessageTypeDeleted || message.type === 'error') {
groupStyles.splice(0, groupStyles.length);
groupStyles.push('single');
} else {
groupStyles.splice(0, groupStyles.length);
groupStyles.push('middle');
}
}

return groupStyles;
};

export const getGroupStyles = <
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
>(
Expand All @@ -43,83 +125,19 @@ export const getGroupStyles = <
});

for (let i = 0; i < messagesFilteredForNonUser.length; i++) {
const previousMessage = messagesFilteredForNonUser[i - 1] as
| (typeof messagesFilteredForNonUser)[0]
| undefined;
const previousMessage = messagesFilteredForNonUser[i - 1];
const message = messagesFilteredForNonUser[i];
const nextMessage = messagesFilteredForNonUser[i + 1] as
| (typeof messagesFilteredForNonUser)[0]
| undefined;
const groupStyles: GroupType[] = [];

const isPrevMessageTypeDeleted = previousMessage?.type === 'deleted';
const isNextMessageTypeDeleted = nextMessage?.type === 'deleted';

const userId = message?.user?.id || null;

const isTopMessage =
!previousMessage ||
previousMessage.type === 'system' ||
previousMessage.type === 'error' ||
userId !== previousMessage?.user?.id ||
!!isPrevMessageTypeDeleted ||
(!hideDateSeparators && dateSeparators[message.id]) ||
messageGroupStyles[previousMessage.id]?.includes('bottom') ||
isEditedMessage(previousMessage);

const isBottomMessage =
!nextMessage ||
nextMessage.type === 'system' ||
nextMessage.type === 'error' ||
userId !== nextMessage?.user?.id ||
!!isNextMessageTypeDeleted ||
(!hideDateSeparators && dateSeparators[nextMessage.id]) ||
(maxTimeBetweenGroupedMessages !== undefined &&
nextMessage.created_at.getTime() - message.created_at.getTime() >
maxTimeBetweenGroupedMessages) ||
isEditedMessage(message);

/**
* Add group styles key for top message
*/
if (isTopMessage) {
groupStyles.push('top');
}

/**
* Add group styles key for bottom message
*/

const isMessageTypeDeleted = message.type === 'deleted';
if (isBottomMessage) {
/**
* If the bottom message is also the top, or deleted, or an error,
* add the key for single message instead of bottom
*/
if (isTopMessage || isMessageTypeDeleted || message.type === 'error') {
groupStyles.splice(0, groupStyles.length);
groupStyles.push('single');
} else {
groupStyles.push('bottom');
}
}

/**
* Add the key for all non top or bottom messages, if the message is
* deleted or an error add the key for single otherwise middle
*/
if (!isTopMessage && !isBottomMessage) {
if (isMessageTypeDeleted || message.type === 'error') {
groupStyles.splice(0, groupStyles.length);
groupStyles.push('single');
} else {
groupStyles.splice(0, groupStyles.length);
groupStyles.push('middle');
}
}
const nextMessage = messagesFilteredForNonUser[i + 1];

if (message.id) {
messageGroupStyles[message.id] = groupStyles;
messageGroupStyles[message.id] = getGroupStyle(
dateSeparators,
message,
previousMessage,
nextMessage,
hideDateSeparators,
maxTimeBetweenGroupedMessages,
);
}
}

Expand Down
Loading

0 comments on commit 98abaed

Please sign in to comment.