(feat): add theming for testers #20

Merged
raketentriebwerksventil merged 14 commits from dev into main 2026-06-16 12:50:47 +03:00
2 changed files with 76 additions and 33 deletions
Showing only changes of commit 4a0f9e3b58 - Show all commits

(fix): chat issues when sending messages
All checks were successful
/ build-web (push) Successful in 1m23s
/ build-desktop (linux) (push) Successful in 6m29s
/ build-mobile (push) Successful in 15m9s
/ release (push) Successful in 31s

Alois 2026-06-14 01:45:20 +02:00

View file

@ -266,7 +266,11 @@ export default function Provider(props: { children: ReactNode }) {
return updated ? next : prev; return updated ? next : prev;
}); });
const queryKey = ["chat-messages", String(userIdValue)] as const; const queryKey = [
"chat-messages",
String(userIdValue),
currentSharedSecret.length > 0,
] as const;
queryClient.setQueryData<InfiniteData<RawMessages>>( queryClient.setQueryData<InfiniteData<RawMessages>>(
queryKey, queryKey,
(current) => { (current) => {
@ -301,7 +305,7 @@ export default function Provider(props: { children: ReactNode }) {
}, },
); );
}); });
}, [subscribePush, userIdValue]); }, [currentSharedSecret, subscribePush, userIdValue]);
return ( return (
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>

View file

@ -12,8 +12,16 @@ import {
PAGE_SIZE, PAGE_SIZE,
FALLBACK_MESSAGE_HEIGHT, FALLBACK_MESSAGE_HEIGHT,
MESSAGES_PER_VIRTUAL_ROW, MESSAGES_PER_VIRTUAL_ROW,
type LiveMessage,
type RawMessage,
} from "./values"; } from "./values";
type MessageChunk = {
key: string;
messages: Array<RawMessage | LiveMessage>;
startIndex: number;
};
function getEstimatedMessageHeight(message: { height?: number }) { function getEstimatedMessageHeight(message: { height?: number }) {
return typeof message.height === "number" && Number.isFinite(message.height) return typeof message.height === "number" && Number.isFinite(message.height)
? Math.max(1, Math.ceil(message.height)) ? Math.max(1, Math.ceil(message.height))
@ -39,6 +47,34 @@ function shouldFetchPreviousPage({
].every(Boolean); ].every(Boolean);
} }
function getMessageRenderKey(message: RawMessage | LiveMessage) {
return "localId" in message ? message.localId : String(message.send_time);
}
function buildMessageChunks(
messages: Array<RawMessage | LiveMessage>,
keyPrefix: string,
startOffset = 0,
) {
const chunks: MessageChunk[] = [];
for (let end = messages.length; end > 0; end -= MESSAGES_PER_VIRTUAL_ROW) {
const start = Math.max(0, end - MESSAGES_PER_VIRTUAL_ROW);
const chunkMessages = messages.slice(start, end);
const firstMessage = chunkMessages[0];
if (firstMessage) {
chunks.push({
key: `${keyPrefix}-${getMessageRenderKey(firstMessage)}`,
messages: chunkMessages,
startIndex: startOffset + start,
});
}
}
return chunks;
}
/** /**
* Renders the chat screen with virtualized history and live message updates. * Renders the chat screen with virtualized history and live message updates.
* @returns Chat screen JSX. * @returns Chat screen JSX.
@ -148,49 +184,52 @@ export default function Screen() {
const historicalMessages = React.useMemo(() => { const historicalMessages = React.useMemo(() => {
const pages = messagesQuery.data?.pages ?? []; const pages = messagesQuery.data?.pages ?? [];
return [...pages].reverse().flat(); const seenSendTimes = new Set<number>();
const dedupedMessages: RawMessage[] = [];
for (const message of [...pages].reverse().flat()) {
if (seenSendTimes.has(message.send_time)) {
continue;
}
seenSendTimes.add(message.send_time);
dedupedMessages.push(message);
}
return dedupedMessages;
}, [messagesQuery.data]); }, [messagesQuery.data]);
const liveMessagesSnapshot = liveMessages(); const liveMessagesSnapshot = liveMessages();
const messages = React.useMemo(() => { const liveWithoutDuplicates = React.useMemo(() => {
if (historicalMessages.length === 0) {
return liveMessagesSnapshot;
}
const historicalSendTimes = new Set( const historicalSendTimes = new Set(
historicalMessages.map((message) => message.send_time), historicalMessages.map((message) => message.send_time),
); );
const liveWithoutDuplicates = liveMessagesSnapshot.filter(
return liveMessagesSnapshot.filter(
(message) => !historicalSendTimes.has(message.send_time), (message) => !historicalSendTimes.has(message.send_time),
); );
return [...historicalMessages, ...liveWithoutDuplicates];
}, [historicalMessages, liveMessagesSnapshot]); }, [historicalMessages, liveMessagesSnapshot]);
const messages = React.useMemo(() => {
return [...historicalMessages, ...liveWithoutDuplicates];
}, [historicalMessages, liveWithoutDuplicates]);
const historicalMessageChunks = React.useMemo(() => {
return buildMessageChunks(historicalMessages, "history");
}, [historicalMessages]);
const liveMessageChunks = React.useMemo(() => {
return buildMessageChunks(
liveWithoutDuplicates,
"live",
historicalMessages.length,
);
}, [historicalMessages.length, liveWithoutDuplicates]);
const messageChunks = React.useMemo(() => { const messageChunks = React.useMemo(() => {
const chunks: Array<{ return [...liveMessageChunks, ...historicalMessageChunks];
key: number; }, [historicalMessageChunks, liveMessageChunks]);
messages: typeof messages;
startIndex: number;
}> = [];
for (let end = messages.length; end > 0; end -= MESSAGES_PER_VIRTUAL_ROW) {
const start = Math.max(0, end - MESSAGES_PER_VIRTUAL_ROW);
const chunkMessages = messages.slice(start, end);
const firstMessage = chunkMessages[0];
if (firstMessage) {
chunks.push({
key: firstMessage.send_time,
messages: chunkMessages,
startIndex: start,
});
}
}
return chunks;
}, [messages]);
const shouldShowConversationStart = const shouldShowConversationStart =
!!messagesQuery.data && !messagesQuery.hasNextPage; !!messagesQuery.data && !messagesQuery.hasNextPage;
@ -530,7 +569,7 @@ export default function Screen() {
return ( return (
<Message <Message
key={message.send_time} key={getMessageRenderKey(message)}
grouped={isGrouped} grouped={isGrouped}
message={message} message={message}
user={ user={