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
@@ -24,7 +24,7 @@ export interface JumpOptions {
|
||||
offset?: number;
|
||||
present?: boolean;
|
||||
flash?: boolean;
|
||||
returnMessageId?: MessageId | null;
|
||||
returnToMessageId?: MessageId | null;
|
||||
returnChannelId?: string | null;
|
||||
returnGuildId?: string | null;
|
||||
jumpType?: JumpType;
|
||||
@@ -34,14 +34,14 @@ interface JumpToMessageOptions {
|
||||
messageId: string;
|
||||
flash?: boolean;
|
||||
offset?: number;
|
||||
returnTargetId?: MessageId | null;
|
||||
returnToMessageId?: MessageId | null;
|
||||
returnChannelId?: string | null;
|
||||
returnGuildId?: string | null;
|
||||
jumpType?: JumpType;
|
||||
}
|
||||
|
||||
interface LoadCompleteOptions {
|
||||
newMessages: Array<MessageInput>;
|
||||
windowMessages: Array<MessageInput>;
|
||||
isBefore?: boolean;
|
||||
isAfter?: boolean;
|
||||
jump?: JumpOptions | null;
|
||||
@@ -61,6 +61,10 @@ function isUploadPlaceholder(message: Message): boolean {
|
||||
return UploadingAttachment.isInSendingMessage(message);
|
||||
}
|
||||
|
||||
function unsentCorrelationKey(message: Message): string {
|
||||
return `${message.author.id}\u0000${message.messageReference?.message_id ?? ''}\u0000${message.content}`;
|
||||
}
|
||||
|
||||
function embedsEqualIgnoringId(a: unknown, b: unknown): boolean {
|
||||
if (a === b) return true;
|
||||
if (a == null || b == null) return a === b;
|
||||
@@ -182,7 +186,7 @@ class MessageBufferSegment {
|
||||
this.items = this.items.filter((m) => m.id !== id);
|
||||
}
|
||||
|
||||
removeMany(ids: Array<string>): void {
|
||||
removeIds(ids: Array<string>): void {
|
||||
if (!ids.length) return;
|
||||
const idSet = ids.length > 1 ? new Set(ids) : null;
|
||||
for (const id of ids) {
|
||||
@@ -219,9 +223,7 @@ class MessageBufferSegment {
|
||||
if (this.items.length === 0) {
|
||||
this.reachedBoundary = boundaryAtInsert;
|
||||
}
|
||||
const combinedSize = this.items.length + batch.length;
|
||||
const truncated = combinedSize > MAX_MESSAGE_CACHE_SIZE;
|
||||
if (truncated) {
|
||||
if (this.items.length + batch.length > MAX_MESSAGE_CACHE_SIZE) {
|
||||
this.reachedBoundary = false;
|
||||
if (batch.length >= MAX_MESSAGE_CACHE_SIZE) {
|
||||
this.items = this.fromOlderSide
|
||||
@@ -229,27 +231,27 @@ class MessageBufferSegment {
|
||||
: batch.slice(0, MAX_MESSAGE_CACHE_SIZE);
|
||||
} else {
|
||||
const available = MAX_MESSAGE_CACHE_SIZE - batch.length;
|
||||
this.items = this.fromOlderSide
|
||||
const kept = this.fromOlderSide
|
||||
? this.items.slice(Math.max(this.items.length - available, 0))
|
||||
: this.items.slice(0, available);
|
||||
this.items = this.fromOlderSide ? kept.concat(batch) : batch.concat(kept);
|
||||
}
|
||||
}
|
||||
if (truncated) {
|
||||
this.items = this.fromOlderSide ? this.items.concat(batch) : batch.concat(this.items);
|
||||
this.keyedById = {};
|
||||
for (const msg of this.items) {
|
||||
this.keyedById[msg.id] = msg;
|
||||
}
|
||||
} else if (this.fromOlderSide) {
|
||||
return;
|
||||
}
|
||||
if (this.fromOlderSide) {
|
||||
for (const msg of batch) {
|
||||
this.items.push(msg);
|
||||
this.keyedById[msg.id] = msg;
|
||||
}
|
||||
} else {
|
||||
this.items.unshift(...batch);
|
||||
for (const msg of batch) {
|
||||
this.keyedById[msg.id] = msg;
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.items.unshift(...batch);
|
||||
for (const msg of batch) {
|
||||
this.keyedById[msg.id] = msg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,19 +289,20 @@ export class ChannelMessages {
|
||||
readonly channelId: string;
|
||||
ready = false;
|
||||
jumpType: JumpType = JumpTypes.ANIMATED;
|
||||
jumpTargetId: string | null = null;
|
||||
jumpTargetOffset = 0;
|
||||
jumpSequenceId = 1;
|
||||
jumped = false;
|
||||
jumpDestinationId: string | null = null;
|
||||
jumpDestinationOffset = 0;
|
||||
jumpTicket = 1;
|
||||
hasJumped = false;
|
||||
jumpedToPresent = false;
|
||||
jumpFlash = true;
|
||||
jumpReturnTargetId: string | null = null;
|
||||
landedAtLiveEdge = false;
|
||||
jumpHighlight = true;
|
||||
jumpReturnMessageId: string | null = null;
|
||||
jumpReturnChannelId: string | null = null;
|
||||
jumpReturnGuildId: string | null = null;
|
||||
hasMoreBefore = true;
|
||||
hasMoreAfter = false;
|
||||
loadingMore = false;
|
||||
revealedMessageId: string | null = null;
|
||||
unblurredMessageId: string | null = null;
|
||||
cached = false;
|
||||
error = false;
|
||||
version = 0;
|
||||
@@ -318,8 +321,8 @@ export class ChannelMessages {
|
||||
return ChannelMessages.channelCache.get(channelId);
|
||||
}
|
||||
|
||||
static hasPresent(channelId: string): boolean {
|
||||
return ChannelMessages.get(channelId)?.hasPresent() ?? false;
|
||||
static hasNewestMessages(channelId: string): boolean {
|
||||
return ChannelMessages.get(channelId)?.hasNewestMessages() ?? false;
|
||||
}
|
||||
|
||||
static getOrCreate(channelId: string): ChannelMessages {
|
||||
@@ -350,7 +353,7 @@ export class ChannelMessages {
|
||||
ChannelMessages.retainedChannelIds.delete(channelId);
|
||||
}
|
||||
|
||||
static clearCache(channelId: string): void {
|
||||
static dropBuffers(channelId: string): void {
|
||||
const instance = ChannelMessages.channelCache.get(channelId);
|
||||
if (!instance) return;
|
||||
instance.beforeBuffer.clear();
|
||||
@@ -419,7 +422,7 @@ export class ChannelMessages {
|
||||
this.afterBuffer = new MessageBufferSegment(false);
|
||||
}
|
||||
|
||||
mutate(patch: Partial<ChannelMessages>): ChannelMessages {
|
||||
withPatch(patch: Partial<ChannelMessages>): ChannelMessages {
|
||||
return this.cloneAnd(patch);
|
||||
}
|
||||
|
||||
@@ -451,13 +454,13 @@ export class ChannelMessages {
|
||||
return this.messageList.reduce(reducer, initial);
|
||||
}
|
||||
|
||||
forAll(callback: (m: Message, idx: number, arr: Array<Message>) => void, thisArg?: unknown): void {
|
||||
forEachBuffered(callback: (m: Message, idx: number, arr: Array<Message>) => void, thisArg?: unknown): void {
|
||||
this.beforeBuffer.forEach(callback, thisArg);
|
||||
this.messageList.forEach(callback, thisArg);
|
||||
this.afterBuffer.forEach(callback, thisArg);
|
||||
}
|
||||
|
||||
findOldest(predicate: (m: Message) => boolean): Message | undefined {
|
||||
searchFromOldest(predicate: (m: Message) => boolean): Message | undefined {
|
||||
return (
|
||||
this.beforeBuffer.messages.find(predicate) ??
|
||||
this.messageList.find(predicate) ??
|
||||
@@ -465,7 +468,7 @@ export class ChannelMessages {
|
||||
);
|
||||
}
|
||||
|
||||
findNewest(predicate: (m: Message) => boolean): Message | undefined {
|
||||
searchFromNewest(predicate: (m: Message) => boolean): Message | undefined {
|
||||
const after = this.afterBuffer.messages;
|
||||
for (let i = after.length - 1; i >= 0; i--) {
|
||||
if (predicate(after[i])) return after[i];
|
||||
@@ -498,11 +501,11 @@ export class ChannelMessages {
|
||||
return this.beforeBuffer.get(id) ?? this.afterBuffer.get(id);
|
||||
}
|
||||
|
||||
getByIndex(index: number): Message | undefined {
|
||||
atIndex(index: number): Message | undefined {
|
||||
return this.messageList[index];
|
||||
}
|
||||
|
||||
getAfter(id: string): Message | null {
|
||||
nextAfter(id: string): Message | null {
|
||||
const current = this.get(id);
|
||||
if (!current) return null;
|
||||
const idx = this.messageList.indexOf(current);
|
||||
@@ -520,11 +523,11 @@ export class ChannelMessages {
|
||||
return this.messageList.findIndex((m) => m.id === id);
|
||||
}
|
||||
|
||||
hasPresent(): boolean {
|
||||
hasNewestMessages(): boolean {
|
||||
return (this.afterBuffer.size > 0 && this.afterBuffer.isBoundary) || !this.hasMoreAfter;
|
||||
}
|
||||
|
||||
hasBeforeCached(beforeId: string): boolean {
|
||||
canServeOlderFrom(beforeId: string): boolean {
|
||||
if (this.messageList.length === 0 || this.beforeBuffer.size === 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -532,7 +535,7 @@ export class ChannelMessages {
|
||||
return Boolean(first && first.id === beforeId);
|
||||
}
|
||||
|
||||
hasAfterCached(afterId: string): boolean {
|
||||
canServeNewerFrom(afterId: string): boolean {
|
||||
if (this.messageList.length === 0 || this.afterBuffer.size === 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -587,7 +590,7 @@ export class ChannelMessages {
|
||||
}, true);
|
||||
}
|
||||
|
||||
removeMany(ids: Array<string>): ChannelMessages {
|
||||
removeIds(ids: Array<string>): ChannelMessages {
|
||||
if (!ids.some((id) => this.has(id))) return this;
|
||||
const idSet = ids.length > 1 ? new Set(ids) : null;
|
||||
return this.cloneAnd((draft) => {
|
||||
@@ -598,8 +601,8 @@ export class ChannelMessages {
|
||||
idSet !== null
|
||||
? draft.messageList.filter((m) => !idSet.has(m.id))
|
||||
: draft.messageList.filter((m) => m.id !== ids[0]);
|
||||
draft.beforeBuffer.removeMany(ids);
|
||||
draft.afterBuffer.removeMany(ids);
|
||||
draft.beforeBuffer.removeIds(ids);
|
||||
draft.afterBuffer.removeIds(ids);
|
||||
}, true);
|
||||
}
|
||||
|
||||
@@ -651,7 +654,7 @@ export class ChannelMessages {
|
||||
}, true);
|
||||
}
|
||||
|
||||
truncateTop(maxCount: number, deepCopy = true): ChannelMessages {
|
||||
trimOldest(maxCount: number, deepCopy = true): ChannelMessages {
|
||||
const overflow = this.messageList.length - maxCount;
|
||||
if (overflow <= 0) return this;
|
||||
return this.cloneAnd((draft) => {
|
||||
@@ -664,7 +667,7 @@ export class ChannelMessages {
|
||||
}, deepCopy);
|
||||
}
|
||||
|
||||
truncateBottom(maxCount: number, deepCopy = true): ChannelMessages {
|
||||
trimNewest(maxCount: number, deepCopy = true): ChannelMessages {
|
||||
if (this.messageList.length <= maxCount) return this;
|
||||
return this.cloneAnd((draft) => {
|
||||
for (let i = maxCount; i < this.messageList.length; i++) {
|
||||
@@ -676,18 +679,18 @@ export class ChannelMessages {
|
||||
}, deepCopy);
|
||||
}
|
||||
|
||||
truncate(trimBottom: boolean, trimTop: boolean): ChannelMessages {
|
||||
trimToWindow(trimBottom: boolean, trimTop: boolean): ChannelMessages {
|
||||
if (this.length <= MAX_LOADED_MESSAGES) return this;
|
||||
if (trimBottom) {
|
||||
return this.truncateBottom(TRUNCATED_MESSAGE_VIEW_SIZE);
|
||||
return this.trimNewest(TRUNCATED_MESSAGE_VIEW_SIZE);
|
||||
}
|
||||
if (trimTop) {
|
||||
return this.truncateTop(TRUNCATED_MESSAGE_VIEW_SIZE);
|
||||
return this.trimOldest(TRUNCATED_MESSAGE_VIEW_SIZE);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
jumpToPresent(limit: number): ChannelMessages {
|
||||
jumpToLiveEdge(limit: number): ChannelMessages {
|
||||
return this.cloneAnd((draft) => {
|
||||
const allAfter = draft.afterBuffer.takeAll();
|
||||
draft.hasMoreAfter = false;
|
||||
@@ -699,15 +702,15 @@ export class ChannelMessages {
|
||||
draft.clearAllMessages();
|
||||
draft.mergeInto(visible);
|
||||
draft.hasMoreBefore = draft.beforeBuffer.size > 0;
|
||||
draft.jumped = true;
|
||||
draft.jumpTargetId = null;
|
||||
draft.jumpTargetOffset = 0;
|
||||
draft.jumpedToPresent = true;
|
||||
draft.jumpFlash = false;
|
||||
draft.jumpReturnTargetId = null;
|
||||
draft.hasJumped = true;
|
||||
draft.jumpDestinationId = null;
|
||||
draft.jumpDestinationOffset = 0;
|
||||
draft.landedAtLiveEdge = true;
|
||||
draft.jumpHighlight = false;
|
||||
draft.jumpReturnMessageId = null;
|
||||
draft.jumpReturnChannelId = null;
|
||||
draft.jumpReturnGuildId = null;
|
||||
draft.jumpSequenceId += 1;
|
||||
draft.jumpTicket += 1;
|
||||
draft.ready = true;
|
||||
draft.loadingMore = false;
|
||||
}, true);
|
||||
@@ -717,22 +720,22 @@ export class ChannelMessages {
|
||||
messageId,
|
||||
flash = true,
|
||||
offset,
|
||||
returnTargetId,
|
||||
returnToMessageId,
|
||||
returnChannelId,
|
||||
returnGuildId,
|
||||
jumpType,
|
||||
}: JumpToMessageOptions): ChannelMessages {
|
||||
return this.cloneAnd((draft) => {
|
||||
draft.jumped = true;
|
||||
draft.jumpedToPresent = false;
|
||||
draft.hasJumped = true;
|
||||
draft.landedAtLiveEdge = false;
|
||||
draft.jumpType = jumpType ?? JumpTypes.ANIMATED;
|
||||
draft.jumpTargetId = messageId;
|
||||
draft.jumpTargetOffset = messageId && offset != null ? offset : 0;
|
||||
draft.jumpSequenceId += 1;
|
||||
draft.jumpFlash = flash;
|
||||
draft.jumpReturnTargetId = returnTargetId ?? null;
|
||||
draft.jumpReturnChannelId = returnTargetId ? (returnChannelId ?? draft.channelId) : null;
|
||||
draft.jumpReturnGuildId = returnTargetId ? (returnGuildId ?? null) : null;
|
||||
draft.jumpDestinationId = messageId;
|
||||
draft.jumpDestinationOffset = messageId && offset != null ? offset : 0;
|
||||
draft.jumpTicket += 1;
|
||||
draft.jumpHighlight = flash;
|
||||
draft.jumpReturnMessageId = returnToMessageId ?? null;
|
||||
draft.jumpReturnChannelId = returnToMessageId ? (returnChannelId ?? draft.channelId) : null;
|
||||
draft.jumpReturnGuildId = returnToMessageId ? (returnGuildId ?? null) : null;
|
||||
draft.ready = true;
|
||||
draft.loadingMore = false;
|
||||
}, false);
|
||||
@@ -740,20 +743,20 @@ export class ChannelMessages {
|
||||
|
||||
clearJumpTarget(options: {clearReturnTarget?: boolean} = {}): ChannelMessages {
|
||||
const patch: Partial<ChannelMessages> = {
|
||||
jumped: false,
|
||||
jumpedToPresent: false,
|
||||
jumpTargetId: null,
|
||||
jumpTargetOffset: 0,
|
||||
hasJumped: false,
|
||||
landedAtLiveEdge: false,
|
||||
jumpDestinationId: null,
|
||||
jumpDestinationOffset: 0,
|
||||
};
|
||||
if (options.clearReturnTarget) {
|
||||
patch.jumpReturnTargetId = null;
|
||||
patch.jumpReturnMessageId = null;
|
||||
patch.jumpReturnChannelId = null;
|
||||
patch.jumpReturnGuildId = null;
|
||||
}
|
||||
return this.cloneAnd(patch);
|
||||
}
|
||||
|
||||
loadFromCache(before: boolean, limit: number): ChannelMessages {
|
||||
drainBufferedSide(before: boolean, limit: number): ChannelMessages {
|
||||
let next = this.cloneAnd((draft) => {
|
||||
const buffer = before ? draft.beforeBuffer : draft.afterBuffer;
|
||||
draft.mergeInto(buffer.take(limit), before);
|
||||
@@ -764,14 +767,14 @@ export class ChannelMessages {
|
||||
draft.loadingMore = false;
|
||||
}, true);
|
||||
if (before) {
|
||||
next = next.truncate(true, false);
|
||||
next = next.trimToWindow(true, false);
|
||||
} else {
|
||||
next = next.truncate(false, true);
|
||||
next = next.trimToWindow(false, true);
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
receiveMessage(message: MessageInput, truncateFromTop = true): ChannelMessages {
|
||||
applyIncomingMessage(message: MessageInput, truncateFromTop = true): ChannelMessages {
|
||||
const wire = toWireMessage(message);
|
||||
const possibleNonce = wire.nonce ?? null;
|
||||
const previous = possibleNonce ? this.get(possibleNonce, true) : null;
|
||||
@@ -804,15 +807,15 @@ export class ChannelMessages {
|
||||
private appendIncomingMessage(message: MessageInput, truncateFromTop: boolean): ChannelMessages {
|
||||
const merged = this.merge([hydrateMessage(this, message, 'preserve')]);
|
||||
if (truncateFromTop) {
|
||||
return merged.truncateTop(IS_MOBILE_CLIENT ? MAX_MESSAGES_PER_CHANNEL : TRUNCATED_MESSAGE_VIEW_SIZE, false);
|
||||
return merged.trimOldest(IS_MOBILE_CLIENT ? MAX_MESSAGES_PER_CHANNEL : TRUNCATED_MESSAGE_VIEW_SIZE, false);
|
||||
}
|
||||
if (this.length > MAX_LOADED_MESSAGES) {
|
||||
return merged.truncateBottom(IS_MOBILE_CLIENT ? MAX_MESSAGES_PER_CHANNEL : TRUNCATED_MESSAGE_VIEW_SIZE, false);
|
||||
return merged.trimNewest(IS_MOBILE_CLIENT ? MAX_MESSAGES_PER_CHANNEL : TRUNCATED_MESSAGE_VIEW_SIZE, false);
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
receivePushNotification(message: MessageInput): ChannelMessages {
|
||||
applyPushPreview(message: MessageInput): ChannelMessages {
|
||||
const wire = toWireMessage(message);
|
||||
const possibleNonce = wire.nonce ?? null;
|
||||
const existing = possibleNonce ? this.get(possibleNonce, true) : null;
|
||||
@@ -820,23 +823,23 @@ export class ChannelMessages {
|
||||
return this.cloneAnd({ready: true, cached: true}).merge([hydrateMessage(this, wire, 'preserve')]);
|
||||
}
|
||||
|
||||
loadStart(jump?: JumpOptions): ChannelMessages {
|
||||
beginLoad(jump?: JumpOptions): ChannelMessages {
|
||||
return this.cloneAnd({
|
||||
loadingMore: true,
|
||||
jumped: jump != null,
|
||||
jumpedToPresent: jump?.present ?? false,
|
||||
jumpTargetId: jump?.messageId ?? null,
|
||||
jumpTargetOffset: jump?.offset ?? 0,
|
||||
jumpReturnTargetId: jump?.returnMessageId ?? null,
|
||||
jumpReturnChannelId: jump?.returnMessageId ? (jump.returnChannelId ?? this.channelId) : null,
|
||||
jumpReturnGuildId: jump?.returnMessageId ? (jump.returnGuildId ?? null) : null,
|
||||
hasJumped: jump != null,
|
||||
landedAtLiveEdge: jump?.present ?? false,
|
||||
jumpDestinationId: jump?.messageId ?? null,
|
||||
jumpDestinationOffset: jump?.offset ?? 0,
|
||||
jumpReturnMessageId: jump?.returnToMessageId ?? null,
|
||||
jumpReturnChannelId: jump?.returnToMessageId ? (jump.returnChannelId ?? this.channelId) : null,
|
||||
jumpReturnGuildId: jump?.returnToMessageId ? (jump.returnGuildId ?? null) : null,
|
||||
ready: jump ? false : this.ready,
|
||||
});
|
||||
}
|
||||
|
||||
loadComplete(options: LoadCompleteOptions): ChannelMessages {
|
||||
applyLoadedWindow(options: LoadCompleteOptions): ChannelMessages {
|
||||
const {
|
||||
newMessages,
|
||||
windowMessages,
|
||||
isBefore = false,
|
||||
isAfter = false,
|
||||
jump = null,
|
||||
@@ -844,7 +847,7 @@ export class ChannelMessages {
|
||||
hasMoreAfter = false,
|
||||
cached = false,
|
||||
} = options;
|
||||
const records = [...newMessages].reverse().map((m) => hydrateMessage(this, m, 'empty'));
|
||||
const records = [...windowMessages].reverse().map((m) => hydrateMessage(this, m, 'empty'));
|
||||
const loadDecision = resolveChannelMessagesLoadDecision({
|
||||
isBefore,
|
||||
isAfter,
|
||||
@@ -853,28 +856,33 @@ export class ChannelMessages {
|
||||
});
|
||||
let next: ChannelMessages;
|
||||
if (loadDecision.mode === 'replace') {
|
||||
const isWindowReplacement = !isBefore && !isAfter && jump?.messageId == null && jump?.offset == null;
|
||||
const unsent = isWindowReplacement ? this.collectUnsentMessages(records) : null;
|
||||
next = this.reset(records);
|
||||
if (unsent && unsent.length > 0) {
|
||||
next = next.merge(unsent);
|
||||
}
|
||||
} else {
|
||||
next = this.merge(records, loadDecision.prepend, true);
|
||||
if (loadDecision.trimBottom) {
|
||||
next = next.truncate(true, false);
|
||||
next = next.trimToWindow(true, false);
|
||||
} else if (loadDecision.trimTop) {
|
||||
next = next.truncate(false, true);
|
||||
next = next.trimToWindow(false, true);
|
||||
}
|
||||
}
|
||||
next = next.cloneAnd({
|
||||
ready: true,
|
||||
loadingMore: false,
|
||||
jumpType: jump?.jumpType ?? JumpTypes.ANIMATED,
|
||||
jumpFlash: jump?.flash ?? false,
|
||||
jumped: jump != null,
|
||||
jumpedToPresent: jump?.present ?? false,
|
||||
jumpTargetId: jump?.messageId ?? null,
|
||||
jumpTargetOffset: jump && jump.messageId != null && jump.offset != null ? jump.offset : 0,
|
||||
jumpSequenceId: jump ? next.jumpSequenceId + 1 : next.jumpSequenceId,
|
||||
jumpReturnTargetId: jump?.returnMessageId ?? null,
|
||||
jumpReturnChannelId: jump?.returnMessageId ? (jump.returnChannelId ?? this.channelId) : null,
|
||||
jumpReturnGuildId: jump?.returnMessageId ? (jump.returnGuildId ?? null) : null,
|
||||
jumpHighlight: jump?.flash ?? false,
|
||||
hasJumped: jump != null,
|
||||
landedAtLiveEdge: jump?.present ?? false,
|
||||
jumpDestinationId: jump?.messageId ?? null,
|
||||
jumpDestinationOffset: jump && jump.messageId != null && jump.offset != null ? jump.offset : 0,
|
||||
jumpTicket: jump ? next.jumpTicket + 1 : next.jumpTicket,
|
||||
jumpReturnMessageId: jump?.returnToMessageId ?? null,
|
||||
jumpReturnChannelId: jump?.returnToMessageId ? (jump.returnChannelId ?? this.channelId) : null,
|
||||
jumpReturnGuildId: jump?.returnToMessageId ? (jump.returnGuildId ?? null) : null,
|
||||
hasMoreBefore: loadDecision.preserveHasMoreBefore ? next.hasMoreBefore : hasMoreBefore,
|
||||
hasMoreAfter: loadDecision.preserveHasMoreAfter ? next.hasMoreAfter : hasMoreAfter,
|
||||
cached,
|
||||
@@ -883,6 +891,25 @@ export class ChannelMessages {
|
||||
return next;
|
||||
}
|
||||
|
||||
private collectUnsentMessages(records: Array<Message>): Array<Message> {
|
||||
const unsent = this.messageList.filter((message) => message.hasFailed || message.isSending);
|
||||
if (unsent.length === 0) return unsent;
|
||||
const unseenByKey = new Map<string, number>();
|
||||
for (const record of records) {
|
||||
if (this.has(record.id)) continue;
|
||||
const key = unsentCorrelationKey(record);
|
||||
unseenByKey.set(key, (unseenByKey.get(key) ?? 0) + 1);
|
||||
}
|
||||
if (unseenByKey.size === 0) return unsent;
|
||||
return unsent.filter((message) => {
|
||||
const key = unsentCorrelationKey(message);
|
||||
const available = unseenByKey.get(key) ?? 0;
|
||||
if (available === 0) return true;
|
||||
unseenByKey.set(key, available - 1);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private clearAllMessages(): void {
|
||||
this.messageList = [];
|
||||
this.messageIndex = {};
|
||||
@@ -927,19 +954,19 @@ export class ChannelMessages {
|
||||
if (typeof mutator === 'function') {
|
||||
clone.ready = this.ready;
|
||||
clone.jumpType = this.jumpType;
|
||||
clone.jumpTargetId = this.jumpTargetId;
|
||||
clone.jumpTargetOffset = this.jumpTargetOffset;
|
||||
clone.jumpSequenceId = this.jumpSequenceId;
|
||||
clone.jumped = this.jumped;
|
||||
clone.jumpedToPresent = this.jumpedToPresent;
|
||||
clone.jumpFlash = this.jumpFlash;
|
||||
clone.jumpReturnTargetId = this.jumpReturnTargetId;
|
||||
clone.jumpDestinationId = this.jumpDestinationId;
|
||||
clone.jumpDestinationOffset = this.jumpDestinationOffset;
|
||||
clone.jumpTicket = this.jumpTicket;
|
||||
clone.hasJumped = this.hasJumped;
|
||||
clone.landedAtLiveEdge = this.landedAtLiveEdge;
|
||||
clone.jumpHighlight = this.jumpHighlight;
|
||||
clone.jumpReturnMessageId = this.jumpReturnMessageId;
|
||||
clone.jumpReturnChannelId = this.jumpReturnChannelId;
|
||||
clone.jumpReturnGuildId = this.jumpReturnGuildId;
|
||||
clone.hasMoreBefore = this.hasMoreBefore;
|
||||
clone.hasMoreAfter = this.hasMoreAfter;
|
||||
clone.loadingMore = this.loadingMore;
|
||||
clone.revealedMessageId = this.revealedMessageId;
|
||||
clone.unblurredMessageId = this.unblurredMessageId;
|
||||
clone.cached = this.cached;
|
||||
clone.error = this.error;
|
||||
mutator(clone);
|
||||
@@ -947,14 +974,16 @@ export class ChannelMessages {
|
||||
const patch = mutator as Partial<ChannelMessages>;
|
||||
clone.ready = 'ready' in patch ? !!patch.ready : this.ready;
|
||||
clone.jumpType = patch.jumpType ?? this.jumpType;
|
||||
clone.jumpTargetId = 'jumpTargetId' in patch ? (patch.jumpTargetId ?? null) : this.jumpTargetId;
|
||||
clone.jumpTargetOffset = patch.jumpTargetOffset !== undefined ? patch.jumpTargetOffset : this.jumpTargetOffset;
|
||||
clone.jumpSequenceId = patch.jumpSequenceId !== undefined ? patch.jumpSequenceId : this.jumpSequenceId;
|
||||
clone.jumped = 'jumped' in patch ? !!patch.jumped : this.jumped;
|
||||
clone.jumpedToPresent = 'jumpedToPresent' in patch ? !!patch.jumpedToPresent : this.jumpedToPresent;
|
||||
clone.jumpFlash = 'jumpFlash' in patch ? !!patch.jumpFlash : this.jumpFlash;
|
||||
clone.jumpReturnTargetId =
|
||||
'jumpReturnTargetId' in patch ? (patch.jumpReturnTargetId ?? null) : this.jumpReturnTargetId;
|
||||
clone.jumpDestinationId =
|
||||
'jumpDestinationId' in patch ? (patch.jumpDestinationId ?? null) : this.jumpDestinationId;
|
||||
clone.jumpDestinationOffset =
|
||||
patch.jumpDestinationOffset !== undefined ? patch.jumpDestinationOffset : this.jumpDestinationOffset;
|
||||
clone.jumpTicket = patch.jumpTicket !== undefined ? patch.jumpTicket : this.jumpTicket;
|
||||
clone.hasJumped = 'hasJumped' in patch ? !!patch.hasJumped : this.hasJumped;
|
||||
clone.landedAtLiveEdge = 'landedAtLiveEdge' in patch ? !!patch.landedAtLiveEdge : this.landedAtLiveEdge;
|
||||
clone.jumpHighlight = 'jumpHighlight' in patch ? !!patch.jumpHighlight : this.jumpHighlight;
|
||||
clone.jumpReturnMessageId =
|
||||
'jumpReturnMessageId' in patch ? (patch.jumpReturnMessageId ?? null) : this.jumpReturnMessageId;
|
||||
clone.jumpReturnChannelId =
|
||||
'jumpReturnChannelId' in patch ? (patch.jumpReturnChannelId ?? null) : this.jumpReturnChannelId;
|
||||
clone.jumpReturnGuildId =
|
||||
@@ -962,8 +991,8 @@ export class ChannelMessages {
|
||||
clone.hasMoreBefore = 'hasMoreBefore' in patch ? !!patch.hasMoreBefore : this.hasMoreBefore;
|
||||
clone.hasMoreAfter = 'hasMoreAfter' in patch ? !!patch.hasMoreAfter : this.hasMoreAfter;
|
||||
clone.loadingMore = patch.loadingMore !== undefined ? patch.loadingMore : this.loadingMore;
|
||||
clone.revealedMessageId =
|
||||
'revealedMessageId' in patch ? (patch.revealedMessageId ?? null) : this.revealedMessageId;
|
||||
clone.unblurredMessageId =
|
||||
'unblurredMessageId' in patch ? (patch.unblurredMessageId ?? null) : this.unblurredMessageId;
|
||||
clone.cached = patch.cached ?? this.cached;
|
||||
clone.error = patch.error ?? this.error;
|
||||
}
|
||||
|
||||
@@ -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