mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 05:25:40 +09:00
fix(app): keep unsent messages and stop the unread jump on reconnect (#1861)
This commit is contained in:
1 parent
2af0405317
commit
b7f75e25ad
16 files changed
+295
-312
No files matched your search
@@ -11,7 +11,6 @@ import {ChannelMessages} from '@app/features/messaging/state/ChannelMessages';
|
||||
import type {ReactionEmoji} from '@app/features/messaging/utils/ReactionUtils';
|
||||
import SelectedChannel from '@app/features/navigation/state/SelectedChannel';
|
||||
import SelectedGuild from '@app/features/navigation/state/SelectedGuild';
|
||||
import type {UnreadJumpAnchor} from '@app/features/read_state/state/ReadStates';
|
||||
import Relationships from '@app/features/relationship/state/Relationships';
|
||||
import Dimension from '@app/features/ui/state/Dimension';
|
||||
import Users from '@app/features/user/state/Users';
|
||||
@@ -39,7 +38,7 @@ export interface PendingJumpDispatch {
|
||||
messageId: string;
|
||||
flash?: boolean;
|
||||
offset?: number;
|
||||
returnTargetId?: string;
|
||||
returnToMessageId?: string;
|
||||
returnChannelId?: string | null;
|
||||
returnGuildId?: string | null;
|
||||
jumpType?: JumpType;
|
||||
@@ -201,6 +200,10 @@ class Messages {
|
||||
return ChannelMessages.get(channelId);
|
||||
}
|
||||
|
||||
private hasLoadedPage(messages: ChannelMessages): boolean {
|
||||
return messages.ready && messages.length > 0;
|
||||
}
|
||||
|
||||
shouldPreloadLatestPage(channelId: string): boolean {
|
||||
if (!GatewayConnection.isConnected || !Channels.getChannel(channelId)) {
|
||||
return false;
|
||||
@@ -210,13 +213,13 @@ class Messages {
|
||||
}
|
||||
|
||||
@action
|
||||
preloadLatestPage(channelId: string, guildId?: string | null, unreadAnchor?: UnreadJumpAnchor | null): boolean {
|
||||
preloadLatestPage(channelId: string, guildId?: string | 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, unreadAnchor});
|
||||
this.handleChannelSelect({guildId: resolvedGuildId ?? undefined, channelId});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -225,19 +228,19 @@ class Messages {
|
||||
}
|
||||
|
||||
getLastEditableMessage(channelId: string): Message | undefined {
|
||||
return this.getMessages(channelId).findNewest((message) => {
|
||||
return this.getMessages(channelId).searchFromNewest((message) => {
|
||||
return message.isCurrentUserAuthor() && message.state === MessageStates.SENT && message.isUserMessage();
|
||||
});
|
||||
}
|
||||
|
||||
jumpedMessageId(channelId: string): string | null | undefined {
|
||||
const channel = ChannelMessages.get(channelId);
|
||||
return channel?.jumpTargetId;
|
||||
return channel?.jumpDestinationId;
|
||||
}
|
||||
|
||||
hasPresent(channelId: string): boolean {
|
||||
hasNewestMessages(channelId: string): boolean {
|
||||
const channel = ChannelMessages.get(channelId);
|
||||
return channel?.hasPresent() ?? false;
|
||||
return channel?.hasNewestMessages() ?? false;
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -257,7 +260,7 @@ class Messages {
|
||||
let didUpdate = false;
|
||||
ChannelMessages.forEach((messages) => {
|
||||
if (messages.loadingMore) {
|
||||
this.commitMessages(messages.mutate({loadingMore: false}));
|
||||
this.commitMessages(messages.withPatch({loadingMore: false}));
|
||||
didUpdate = true;
|
||||
}
|
||||
});
|
||||
@@ -286,14 +289,14 @@ class Messages {
|
||||
@action
|
||||
handleResumed(): boolean {
|
||||
ChannelMessages.forEach((messages) => {
|
||||
this.commitMessages(messages.mutate({ready: true}));
|
||||
this.commitMessages(messages.withPatch({ready: true}));
|
||||
});
|
||||
this.notifyChange();
|
||||
return true;
|
||||
}
|
||||
|
||||
@action
|
||||
handleConnectionOpen(resolveUnreadAnchor: (channelId: string) => UnreadJumpAnchor | null): boolean {
|
||||
handleConnectionOpen(): boolean {
|
||||
const selectedChannelId = SelectedChannel.currentChannelId;
|
||||
let didHydrateSelectedChannel = false;
|
||||
if (selectedChannelId) {
|
||||
@@ -307,14 +310,10 @@ class Messages {
|
||||
}
|
||||
ChannelMessages.forEach((messages) => {
|
||||
if (messages.channelId === selectedChannelId && Channels.getChannel(messages.channelId) != null) {
|
||||
this.startChannelHydration(messages.channelId, {
|
||||
forceScrollToBottom: this.pendingFullHydration,
|
||||
unreadAnchor: resolveUnreadAnchor(messages.channelId),
|
||||
});
|
||||
this.startChannelHydration(messages.channelId, {forceScrollToBottom: this.pendingFullHydration});
|
||||
didHydrateSelectedChannel = true;
|
||||
} else {
|
||||
this.clearMessages(messages.channelId);
|
||||
Dimension.forgetChannelDimensions(messages.channelId);
|
||||
this.commitMessages(messages.withPatch({ready: false, loadingMore: false}));
|
||||
}
|
||||
});
|
||||
if (this.pendingFullHydration && !didHydrateSelectedChannel && selectedChannelId) {
|
||||
@@ -325,19 +324,8 @@ class Messages {
|
||||
if (!didHydrateSelectedChannel && selectedChannelId && Channels.getChannel(selectedChannelId)) {
|
||||
const messages = ChannelMessages.getOrCreate(selectedChannelId);
|
||||
if (!messages.ready && !messages.loadingMore && messages.length === 0) {
|
||||
this.commitMessages(messages.mutate({loadingMore: true}));
|
||||
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);
|
||||
}
|
||||
this.commitMessages(messages.withPatch({loadingMore: true}));
|
||||
MessageCommands.fetchMessages(selectedChannelId, null, null, MAX_MESSAGES_PER_CHANNEL);
|
||||
didHydrateSelectedChannel = true;
|
||||
}
|
||||
}
|
||||
@@ -345,42 +333,19 @@ class Messages {
|
||||
return didHydrateSelectedChannel;
|
||||
}
|
||||
|
||||
private startChannelHydration(
|
||||
channelId: string,
|
||||
options: {
|
||||
forceScrollToBottom?: boolean;
|
||||
unreadAnchor?: UnreadJumpAnchor | null;
|
||||
} = {},
|
||||
): void {
|
||||
private startChannelHydration(channelId: string, options: {forceScrollToBottom?: boolean} = {}): void {
|
||||
if (!Channels.getChannel(channelId)) return;
|
||||
const {forceScrollToBottom = false, unreadAnchor = null} = options;
|
||||
const {forceScrollToBottom = false} = options;
|
||||
const messages = ChannelMessages.getOrCreate(channelId);
|
||||
this.commitMessages(messages.mutate({loadingMore: true, ready: false, error: false}));
|
||||
this.commitMessages(messages.withPatch({loadingMore: true, ready: false, error: false}));
|
||||
if (forceScrollToBottom) {
|
||||
Dimension.recordChannelDimensions(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);
|
||||
}
|
||||
|
||||
@action
|
||||
handleChannelSelect(action: {
|
||||
guildId?: string;
|
||||
channelId?: string | null;
|
||||
messageId?: string;
|
||||
unreadAnchor?: UnreadJumpAnchor | null;
|
||||
}): boolean {
|
||||
handleChannelSelect(action: {guildId?: string; channelId?: string | null; messageId?: string}): boolean {
|
||||
const channelId = action.channelId ?? action.guildId;
|
||||
if (channelId == null || channelId === ME) {
|
||||
return false;
|
||||
@@ -401,9 +366,9 @@ class Messages {
|
||||
MessageCommands.jumpToMessage({channelId, ...dispatch});
|
||||
return false;
|
||||
}
|
||||
if (!GatewayConnection.isConnected || messages.loadingMore || messages.ready) {
|
||||
if (messages.ready && Dimension.channelPinnedToEnd(channelId)) {
|
||||
this.commitMessages(messages.truncateTop(MAX_MESSAGES_PER_CHANNEL));
|
||||
if (!GatewayConnection.isConnected || messages.loadingMore || this.hasLoadedPage(messages)) {
|
||||
if (this.hasLoadedPage(messages) && Dimension.channelPinnedToEnd(channelId)) {
|
||||
this.commitMessages(messages.trimOldest(MAX_MESSAGES_PER_CHANNEL));
|
||||
this.notifyChange();
|
||||
}
|
||||
return false;
|
||||
@@ -421,19 +386,8 @@ class Messages {
|
||||
if (!isNonGuildChannel && !guildExists) {
|
||||
return false;
|
||||
}
|
||||
this.commitMessages(messages.mutate({loadingMore: true}));
|
||||
this.commitMessages(messages.withPatch({loadingMore: true}));
|
||||
this.notifyChange();
|
||||
const unreadAnchor = action.unreadAnchor ?? null;
|
||||
if (unreadAnchor != null) {
|
||||
MessageCommands.jumpToMessage({
|
||||
channelId,
|
||||
messageId: unreadAnchor.messageId,
|
||||
offset: unreadAnchor.offset,
|
||||
flash: false,
|
||||
jumpType: JumpTypes.INSTANT,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
MessageCommands.fetchMessages(channelId, null, null, MAX_MESSAGES_PER_CHANNEL);
|
||||
return false;
|
||||
}
|
||||
@@ -486,7 +440,7 @@ class Messages {
|
||||
messageId: undefined,
|
||||
});
|
||||
if (!didChannelSelect && currentMessages && currentMessages.length === 0 && !currentMessages.ready) {
|
||||
this.commitMessages(currentMessages.mutate({loadingMore: true}));
|
||||
this.commitMessages(currentMessages.withPatch({loadingMore: true}));
|
||||
MessageCommands.fetchMessages(selectedChannelId, null, null, MAX_MESSAGES_PER_CHANNEL);
|
||||
this.notifyChange();
|
||||
return true;
|
||||
@@ -497,16 +451,16 @@ class Messages {
|
||||
@action
|
||||
handleLoadMessages(action: {channelId: string; jump?: JumpOptions}): boolean {
|
||||
const messages = ChannelMessages.getOrCreate(action.channelId);
|
||||
this.commitMessages(messages.loadStart(action.jump));
|
||||
this.commitMessages(messages.beginLoad(action.jump));
|
||||
this.notifyChange();
|
||||
return false;
|
||||
}
|
||||
|
||||
@action
|
||||
handleTruncateMessages(action: {channelId: string; truncateBottom?: boolean; truncateTop?: boolean}): boolean {
|
||||
const messages = ChannelMessages.getOrCreate(action.channelId).truncate(
|
||||
action.truncateBottom ?? false,
|
||||
action.truncateTop ?? false,
|
||||
handleTruncateMessages(action: {channelId: string; trimNewest?: boolean; trimOldest?: boolean}): boolean {
|
||||
const messages = ChannelMessages.getOrCreate(action.channelId).trimToWindow(
|
||||
action.trimNewest ?? false,
|
||||
action.trimOldest ?? false,
|
||||
);
|
||||
this.commitMessages(messages);
|
||||
this.notifyChange();
|
||||
@@ -523,19 +477,19 @@ class Messages {
|
||||
}): boolean {
|
||||
let messages = ChannelMessages.getOrCreate(action.channelId);
|
||||
if (action.jump?.present) {
|
||||
messages = messages.jumpToPresent(action.limit);
|
||||
messages = messages.jumpToLiveEdge(action.limit);
|
||||
} else if (action.jump?.messageId) {
|
||||
messages = messages.jumpToMessage({
|
||||
messageId: action.jump.messageId,
|
||||
flash: action.jump.flash,
|
||||
offset: action.jump.offset,
|
||||
returnTargetId: action.jump.returnMessageId,
|
||||
returnToMessageId: action.jump.returnToMessageId,
|
||||
returnChannelId: action.jump.returnChannelId,
|
||||
returnGuildId: action.jump.returnGuildId,
|
||||
jumpType: action.jump.jumpType,
|
||||
});
|
||||
} else if (action.before || action.after) {
|
||||
messages = messages.loadFromCache(action.before != null, action.limit);
|
||||
messages = messages.drainBufferedSide(action.before != null, action.limit);
|
||||
}
|
||||
this.commitMessages(messages);
|
||||
this.notifyChange();
|
||||
@@ -553,8 +507,8 @@ class Messages {
|
||||
cached?: boolean;
|
||||
messages: Array<WireMessage>;
|
||||
}): boolean {
|
||||
const messages = ChannelMessages.getOrCreate(action.channelId).loadComplete({
|
||||
newMessages: action.messages,
|
||||
const messages = ChannelMessages.getOrCreate(action.channelId).applyLoadedWindow({
|
||||
windowMessages: action.messages,
|
||||
isBefore: action.isBefore,
|
||||
isAfter: action.isAfter,
|
||||
jump: action.jump,
|
||||
@@ -570,7 +524,7 @@ class Messages {
|
||||
@action
|
||||
handleLoadMessagesFailure(action: {channelId: string}): boolean {
|
||||
const messages = ChannelMessages.getOrCreate(action.channelId);
|
||||
this.commitMessages(messages.mutate({loadingMore: false, error: true}));
|
||||
this.commitMessages(messages.withPatch({loadingMore: false, error: true}));
|
||||
this.notifyChange();
|
||||
return false;
|
||||
}
|
||||
@@ -581,7 +535,7 @@ class Messages {
|
||||
if (!messages.loadingMore && !messages.error) {
|
||||
return false;
|
||||
}
|
||||
this.commitMessages(messages.mutate({loadingMore: false, error: false}));
|
||||
this.commitMessages(messages.withPatch({loadingMore: false, error: false}));
|
||||
this.notifyChange();
|
||||
return true;
|
||||
}
|
||||
@@ -593,7 +547,7 @@ class Messages {
|
||||
if (!existing?.ready) {
|
||||
return false;
|
||||
}
|
||||
const updated = existing.receiveMessage(action.message, Dimension.channelPinnedToEnd(action.channelId));
|
||||
const updated = existing.applyIncomingMessage(action.message, Dimension.channelPinnedToEnd(action.channelId));
|
||||
this.commitMessages(updated);
|
||||
this.notifyChange();
|
||||
return false;
|
||||
@@ -626,9 +580,9 @@ class Messages {
|
||||
return false;
|
||||
}
|
||||
let messages = existing;
|
||||
if (messages.revealedMessageId === action.id) {
|
||||
const messageAfter = messages.getAfter(action.id);
|
||||
messages = messages.mutate({revealedMessageId: messageAfter?.id ?? null});
|
||||
if (messages.unblurredMessageId === action.id) {
|
||||
const messageAfter = messages.nextAfter(action.id);
|
||||
messages = messages.withPatch({unblurredMessageId: messageAfter?.id ?? null});
|
||||
}
|
||||
messages = messages.remove(action.id);
|
||||
this.commitMessages(messages);
|
||||
@@ -640,11 +594,11 @@ class Messages {
|
||||
handleMessageDeleteBulk(action: {ids: Array<string>; channelId: string}): boolean {
|
||||
const existing = ChannelMessages.get(action.channelId);
|
||||
if (!existing) return false;
|
||||
let messages = existing.removeMany(action.ids);
|
||||
let messages = existing.removeIds(action.ids);
|
||||
if (messages === existing) return false;
|
||||
if (messages.revealedMessageId != null && action.ids.includes(messages.revealedMessageId)) {
|
||||
const after = messages.getAfter(messages.revealedMessageId);
|
||||
messages = messages.mutate({revealedMessageId: after?.id ?? null});
|
||||
if (messages.unblurredMessageId != null && action.ids.includes(messages.unblurredMessageId)) {
|
||||
const after = messages.nextAfter(messages.unblurredMessageId);
|
||||
messages = messages.withPatch({unblurredMessageId: after?.id ?? null});
|
||||
}
|
||||
this.commitMessages(messages);
|
||||
this.notifyChange();
|
||||
@@ -752,7 +706,7 @@ class Messages {
|
||||
@action
|
||||
handleMessageReveal(action: {channelId: string; messageId: string | null}): boolean {
|
||||
const messages = ChannelMessages.getOrCreate(action.channelId);
|
||||
this.commitMessages(messages.mutate({revealedMessageId: action.messageId}));
|
||||
this.commitMessages(messages.withPatch({unblurredMessageId: action.messageId}));
|
||||
this.notifyChange();
|
||||
return true;
|
||||
}
|
||||
@@ -762,9 +716,9 @@ class Messages {
|
||||
const messages = ChannelMessages.get(action.channelId);
|
||||
if (
|
||||
messages &&
|
||||
(messages.jumpTargetId != null ||
|
||||
messages.jumped ||
|
||||
(action.clearReturnTarget === true && messages.jumpReturnTargetId != null))
|
||||
(messages.jumpDestinationId != null ||
|
||||
messages.hasJumped ||
|
||||
(action.clearReturnTarget === true && messages.jumpReturnMessageId != null))
|
||||
) {
|
||||
this.commitMessages(messages.clearJumpTarget({clearReturnTarget: action.clearReturnTarget}));
|
||||
this.notifyChange();
|
||||
@@ -829,7 +783,7 @@ class Messages {
|
||||
Channels.handleMessageCreate({message: messageData});
|
||||
const channelMessages = ChannelMessages.getOrCreate(channelId);
|
||||
if (!channelMessages.has(messageData.id)) {
|
||||
this.commitMessages(channelMessages.receiveMessage(messageData, false));
|
||||
this.commitMessages(channelMessages.applyIncomingMessage(messageData, false));
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user