diff --git a/src/lib/blah/crypto/signedPayload.ts b/src/lib/blah/crypto/signedPayload.ts
index 50d590c..808ac66 100644
--- a/src/lib/blah/crypto/signedPayload.ts
+++ b/src/lib/blah/crypto/signedPayload.ts
@@ -3,6 +3,7 @@ export type BlahPayloadSignee
= {
payload: P;
timestamp: number;
user: string;
+ act_key?: string;
};
export type BlahSignedPayload
= {
diff --git a/src/lib/blah/structures/roomInfo.ts b/src/lib/blah/structures/roomInfo.ts
index 9061585..573ac1c 100644
--- a/src/lib/blah/structures/roomInfo.ts
+++ b/src/lib/blah/structures/roomInfo.ts
@@ -2,7 +2,7 @@ import type { BlahSignedPayload } from '../crypto';
import type { BlahMessage } from './message';
export type BlahRoomInfo = {
- ruuid: string;
+ rid: string;
title: string;
last_chat?: BlahSignedPayload;
};
diff --git a/src/lib/chatList.ts b/src/lib/chatList.ts
index 3685c98..1eff0ef 100644
--- a/src/lib/chatList.ts
+++ b/src/lib/chatList.ts
@@ -13,8 +13,8 @@ export class ChatListManager {
private sortChats(chatList: Chat[]) {
chatList.sort(
(a, b) =>
- (b.lastMessage?.date ?? new Date(1970, 0, 1)).getTime() ??
- -(a.lastMessage?.date ?? new Date(1970, 0, 1)).getTime()
+ (b.lastMessage?.date ?? new Date(0)).getTime() ??
+ -(a.lastMessage?.date ?? new Date(0)).getTime()
);
}
@@ -23,7 +23,7 @@ export class ChatListManager {
for (const chat of chats) {
const newChat = chatFromBlah(chat, serverEndpoint);
- const existing = chatList.find((c) => c.id === chat.ruuid);
+ const existing = chatList.find((c) => c.id === newChat.id);
if (existing) {
existing.name = newChat.name;
existing.lastMessage = newChat.lastMessage ?? existing.lastMessage;
@@ -43,7 +43,7 @@ export class ChatListManager {
const chat = chatList.find((c) => c.id === message.signee.payload.room);
if (chat) {
const newChat = chatFromBlah(
- { ruuid: chat.id, title: chat.name, last_chat: message },
+ { rid: chat.id, title: chat.name, last_chat: message },
serverEndpoint
);
chat.lastMessage = newChat.lastMessage ?? chat.lastMessage;
diff --git a/src/lib/chatServers.ts b/src/lib/chatServers.ts
index e13b73c..1d56479 100644
--- a/src/lib/chatServers.ts
+++ b/src/lib/chatServers.ts
@@ -5,6 +5,7 @@ import { BlahKeyPair, type EncodedBlahKeyPair } from './blah/crypto';
import { currentKeyPair } from './keystore';
import { ChatListManager } from './chatList';
import { browser } from '$app/environment';
+import { GlobalSearchManager } from './globalSearch';
export const chatServers = persisted('weblah-chat-servers', ['https://blah.oxa.li/api']);
@@ -12,6 +13,7 @@ class ChatServerConnectionPool {
private connections: Map = new Map();
private keypair: BlahKeyPair | null = null;
chatList: ChatListManager = new ChatListManager();
+ searchManager: GlobalSearchManager = new GlobalSearchManager(this.connections);
constructor() {
if (browser) {
diff --git a/src/lib/components/InputFrame.svelte b/src/lib/components/InputFrame.svelte
index 9238959..ee07782 100644
--- a/src/lib/components/InputFrame.svelte
+++ b/src/lib/components/InputFrame.svelte
@@ -5,11 +5,11 @@
export { className as class };
-
-
+
diff --git a/src/lib/globalSearch.ts b/src/lib/globalSearch.ts
new file mode 100644
index 0000000..02fe468
--- /dev/null
+++ b/src/lib/globalSearch.ts
@@ -0,0 +1,56 @@
+import type { BlahChatServerConnection } from './blah/connection/chatServer';
+import { chatFromBlah, type Chat } from './types';
+
+export class GlobalSearchManager {
+ private connections: Map;
+
+ constructor(connections: Map) {
+ this.connections = connections;
+ }
+
+ public async searchChats(query: string): Promise<{ joined: Chat[]; public: Chat[] }> {
+ let jobs: Promise<['joined' | 'public', Chat[]]>[] = [];
+
+ for (const [endpoint, connection] of this.connections.entries()) {
+ const fetchInJoinedRooms = async (): Promise<['joined' | 'public', Chat[]]> => [
+ 'joined',
+ (await connection.fetchJoinedRooms()).map((r) => chatFromBlah(r, endpoint))
+ ];
+ const fetchInPublicRooms = async (): Promise<['joined' | 'public', Chat[]]> => [
+ 'public',
+ (await connection.discoverRooms()).map((r) => chatFromBlah(r, endpoint))
+ ];
+
+ jobs = jobs.concat([fetchInJoinedRooms(), fetchInPublicRooms()]);
+ }
+
+ const results = await Promise.allSettled(jobs);
+ console.log(results);
+
+ const chats: { joined: Chat[]; public: Chat[] } = { joined: [], public: [] };
+ for (const result of results) {
+ console.log(result);
+
+ if (result.status === 'rejected') continue;
+
+ const [type, chatList] = result.value;
+ for (const chat of chatList) {
+ if (!chat.name.includes(query)) continue; // TODO: Actual backend search
+ if (chats[type].find((c) => c.id === chat.id)) continue; // Dedupe in its own type
+ if (type !== 'joined' && chats.joined.find((c) => c.id === chat.id)) continue; // If already in joined, don't add to public
+
+ // Insert in last message date order
+ const date = chat.lastMessage?.date;
+ if (!date) {
+ chats[type].push(chat);
+ continue;
+ }
+ let idx = chats[type].findIndex((c) => (c.lastMessage ? c.lastMessage?.date < date : true));
+ if (idx === -1) idx = 0;
+ chats[type].splice(idx, 0, chat);
+ }
+ }
+
+ return chats;
+ }
+}
diff --git a/src/lib/types/chat.ts b/src/lib/types/chat.ts
index e5697c6..5b8537e 100644
--- a/src/lib/types/chat.ts
+++ b/src/lib/types/chat.ts
@@ -14,7 +14,7 @@ export type Chat = {
export function chatFromBlah(room: BlahRoomInfo, serverEndpoint: string): Chat {
return {
server: serverEndpoint,
- id: room.ruuid,
+ id: room.rid,
name: room.title,
type: 'group',
lastMessage: room.last_chat ? messageFromBlah(room.last_chat) : undefined
diff --git a/src/routes/(app)/ChatList.svelte b/src/routes/(app)/ChatList.svelte
index 452365b..a1e9a84 100644
--- a/src/routes/(app)/ChatList.svelte
+++ b/src/routes/(app)/ChatList.svelte
@@ -1,16 +1,21 @@
-
-
-
+
+
{#if $chatList}
{#each $chatList as chat}
@@ -18,5 +23,13 @@
{/each}
{/if}
+ {#if isSearchFocused}
+
+
+
+ {/if}
diff --git a/src/routes/(app)/ChatListHeader.svelte b/src/routes/(app)/ChatListHeader.svelte
index 882e41d..5a0d51b 100644
--- a/src/routes/(app)/ChatListHeader.svelte
+++ b/src/routes/(app)/ChatListHeader.svelte
@@ -1,45 +1,51 @@
diff --git a/src/routes/(app)/IdentityMenu.svelte b/src/routes/(app)/IdentityMenu.svelte
index 2ba3146..f68eb56 100644
--- a/src/routes/(app)/IdentityMenu.svelte
+++ b/src/routes/(app)/IdentityMenu.svelte
@@ -4,6 +4,9 @@
import { keyStore, currentKeyIndex, currentKeyPair } from '$lib/keystore';
import { BlahKeyPair, generateName } from '$lib/blah/crypto';
+ let className: string = '';
+ export { className as class };
+
let currentKeyId: string | undefined;
let currentKeyName: string | null;
$: {
@@ -24,10 +27,10 @@
-
+
{#if currentKeyId}
{#key currentKeyId}
-
+
{/key}
Using identity {currentKeyName}
{:else}
diff --git a/src/routes/(app)/SearchChatResultSection.svelte b/src/routes/(app)/SearchChatResultSection.svelte
new file mode 100644
index 0000000..7f2b49d
--- /dev/null
+++ b/src/routes/(app)/SearchChatResultSection.svelte
@@ -0,0 +1,21 @@
+
+
+
+
+ {name}
+
+
+ {#each results as chat}
+
+ {/each}
+
+
diff --git a/src/routes/(app)/SearchPanel.svelte b/src/routes/(app)/SearchPanel.svelte
new file mode 100644
index 0000000..7236cc9
--- /dev/null
+++ b/src/routes/(app)/SearchPanel.svelte
@@ -0,0 +1,34 @@
+
+
+{#await search(searchQuery)}
+
+
+
+{:then results}
+ {#if results.joined.length === 0 && results.public.length === 0}
+
+ {:else}
+
+ {#if results.joined.length > 0}
+
+ {/if}
+ {#if results.public.length > 0}
+
+ {/if}
+
+ {/if}
+{/await}