diff --git a/fluxer_app/src/features/app/hooks/useChannelHoverPreload.ts b/fluxer_app/src/features/app/hooks/useChannelHoverPreload.ts index 05f96753a..9c7526b46 100644 --- a/fluxer_app/src/features/app/hooks/useChannelHoverPreload.ts +++ b/fluxer_app/src/features/app/hooks/useChannelHoverPreload.ts @@ -4,6 +4,7 @@ import type {Channel} from '@app/features/channel/models/Channel'; import type {Guild} from '@app/features/guild/models/Guild'; import {ensureMembersForMessages} from '@app/features/messaging/commands/MessageCommands'; import Messages from '@app/features/messaging/state/MessagingMessages'; +import ReadStates from '@app/features/read_state/state/ReadStates'; import {ChannelTypes} from '@fluxer/constants/src/ChannelConstants'; import {useCallback, useEffect, useRef} from 'react'; @@ -56,7 +57,8 @@ export function useChannelHoverPreload({ return; } if (preloadMessages) { - if (!Messages.preloadLatestPage(channel.id, guild?.id ?? channel.guildId ?? null)) { + const unreadAnchor = ReadStates.getUnreadJumpAnchor(channel.id); + if (!Messages.preloadLatestPage(channel.id, guild?.id ?? channel.guildId ?? null, unreadAnchor)) { ensureMembersForCachedChannelMessages(channel.id); } } diff --git a/fluxer_app/src/features/gateway/events/GatewayReady.ts b/fluxer_app/src/features/gateway/events/GatewayReady.ts index 4168a245b..504a2360f 100644 --- a/fluxer_app/src/features/gateway/events/GatewayReady.ts +++ b/fluxer_app/src/features/gateway/events/GatewayReady.ts @@ -185,5 +185,5 @@ function handleReadyInternal(data: ReadyPayload, context: GatewayHandlerContext) MediaEngine.handleConnectionOpen(guilds); Initialization.setReady(data); context.setReady(); - Messages.handleConnectionOpen(); + Messages.handleConnectionOpen((channelId) => ReadStates.getUnreadJumpAnchor(channelId)); } diff --git a/fluxer_app/src/features/messaging/state/MessagingMessages.ts b/fluxer_app/src/features/messaging/state/MessagingMessages.ts index d4f792fa4..bb1232a21 100644 --- a/fluxer_app/src/features/messaging/state/MessagingMessages.ts +++ b/fluxer_app/src/features/messaging/state/MessagingMessages.ts @@ -210,13 +210,13 @@ class Messages { } @action - preloadLatestPage(channelId: string, guildId?: string | null): boolean { + preloadLatestPage(channelId: string, guildId?: string | null, unreadAnchor?: UnreadJumpAnchor | null): boolean { if (!this.shouldPreloadLatestPage(channelId)) { return false; } const channel = Channels.getChannel(channelId); const resolvedGuildId = guildId ?? channel?.guildId ?? (channel?.isPrivate() ? ME : undefined); - this.handleChannelSelect({guildId: resolvedGuildId ?? undefined, channelId}); + this.handleChannelSelect({guildId: resolvedGuildId ?? undefined, channelId, unreadAnchor}); return true; } @@ -293,7 +293,7 @@ class Messages { } @action - handleConnectionOpen(): boolean { + handleConnectionOpen(resolveUnreadAnchor: (channelId: string) => UnreadJumpAnchor | null): boolean { const selectedChannelId = SelectedChannel.currentChannelId; let didHydrateSelectedChannel = false; if (selectedChannelId) { @@ -307,7 +307,10 @@ class Messages { } ChannelMessages.forEach((messages) => { if (messages.channelId === selectedChannelId && Channels.getChannel(messages.channelId) != null) { - this.startChannelHydration(messages.channelId, {forceScrollToBottom: this.pendingFullHydration}); + this.startChannelHydration(messages.channelId, { + forceScrollToBottom: this.pendingFullHydration, + unreadAnchor: resolveUnreadAnchor(messages.channelId), + }); didHydrateSelectedChannel = true; } else { this.clearMessages(messages.channelId); @@ -323,7 +326,18 @@ class Messages { const messages = ChannelMessages.getOrCreate(selectedChannelId); if (!messages.ready && !messages.loadingMore && messages.length === 0) { this.commitMessages(messages.mutate({loadingMore: true})); - MessageCommands.fetchMessages(selectedChannelId, null, null, MAX_MESSAGES_PER_CHANNEL); + const unreadAnchor = resolveUnreadAnchor(selectedChannelId); + if (unreadAnchor != null) { + MessageCommands.jumpToMessage({ + channelId: selectedChannelId, + messageId: unreadAnchor.messageId, + offset: unreadAnchor.offset, + flash: false, + jumpType: JumpTypes.INSTANT, + }); + } else { + MessageCommands.fetchMessages(selectedChannelId, null, null, MAX_MESSAGES_PER_CHANNEL); + } didHydrateSelectedChannel = true; } } @@ -335,14 +349,27 @@ class Messages { channelId: string, options: { forceScrollToBottom?: boolean; + unreadAnchor?: UnreadJumpAnchor | null; } = {}, ): void { if (!Channels.getChannel(channelId)) return; - const {forceScrollToBottom = false} = options; + const {forceScrollToBottom = false, unreadAnchor = null} = options; const messages = ChannelMessages.getOrCreate(channelId); this.commitMessages(messages.mutate({loadingMore: true, ready: false, error: false})); if (forceScrollToBottom) { Dimension.updateChannelDimensions(channelId, 1, 1, 0); + MessageCommands.fetchMessages(channelId, null, null, MAX_MESSAGES_PER_CHANNEL); + return; + } + if (unreadAnchor != null) { + MessageCommands.jumpToMessage({ + channelId, + messageId: unreadAnchor.messageId, + offset: unreadAnchor.offset, + flash: false, + jumpType: JumpTypes.INSTANT, + }); + return; } MessageCommands.fetchMessages(channelId, null, null, MAX_MESSAGES_PER_CHANNEL); }