feat(chat): implement pull-to-refresh functionality and pagination for chat history

This commit is contained in:
2026-07-15 18:19:35 +08:00
parent 05ca15be48
commit c37a2f9040
21 changed files with 892 additions and 66 deletions
+77 -1
View File
@@ -21,12 +21,88 @@ export function applyNetworkHistoryLoadedOutput(
output: {
messages: UiMessage[];
localCount: number;
total: number;
limit: number;
},
): Pick<ChatState, "messages" | "historyLoaded"> {
): Pick<
ChatState,
| "messages"
| "historyLoaded"
| "historyTotal"
| "historyLimit"
| "nextHistoryOffset"
| "isLoadingMoreHistory"
> {
const localSnapshotSize = output.localCount === 0 ? 1 : output.localCount;
const optimisticTail = context.messages.slice(localSnapshotSize);
const historyLimit = normalizeHistoryLimit(output.limit);
return {
messages: [...output.messages, ...optimisticTail],
historyLoaded: true,
historyTotal: Math.max(0, output.total),
historyLimit,
nextHistoryOffset: historyLimit,
isLoadingMoreHistory: false,
};
}
export function applyOlderHistoryLoadedOutput(
context: ChatState,
output: {
messages: UiMessage[];
offset: number;
total: number;
limit: number;
},
): Pick<
ChatState,
| "messages"
| "historyTotal"
| "historyLimit"
| "nextHistoryOffset"
| "isLoadingMoreHistory"
> {
const historyLimit = normalizeHistoryLimit(
output.limit,
context.historyLimit,
);
return {
messages: prependUniqueHistoryMessages(context.messages, output.messages),
historyTotal: Math.max(0, output.total),
historyLimit,
nextHistoryOffset: output.offset + historyLimit,
isLoadingMoreHistory: false,
};
}
export function canLoadMoreHistory(context: ChatState): boolean {
return (
context.historyLoaded &&
!context.isLoadingMoreHistory &&
context.nextHistoryOffset < context.historyTotal
);
}
export function normalizeHistoryLimit(
limit: number,
fallback = CHAT_HISTORY_LIMIT,
): number {
return Number.isFinite(limit) && limit > 0 ? Math.floor(limit) : fallback;
}
export function prependUniqueHistoryMessages(
currentMessages: readonly UiMessage[],
olderMessages: readonly UiMessage[],
): UiMessage[] {
const existingIds = new Set(
currentMessages.flatMap((message) => (message.id ? [message.id] : [])),
);
const pageIds = new Set<string>();
const uniqueOlderMessages = olderMessages.filter((message) => {
if (!message.id) return true;
if (existingIds.has(message.id) || pageIds.has(message.id)) return false;
pageIds.add(message.id);
return true;
});
return [...uniqueOlderMessages, ...currentMessages];
}