blowater/UI/conversation-list.ts

188 lines
6.6 KiB
TypeScript
Raw Normal View History

import { ConversationListRetriever, NewMessageChecker } from "./conversation-list.tsx";
2023-10-07 20:40:18 +00:00
import { PublicKey } from "../lib/nostr-ts/key.ts";
2023-08-28 17:58:05 +00:00
import { NostrAccountContext, NostrEvent, NostrKind } from "../lib/nostr-ts/nostr.ts";
import { getTags, Parsed_Event } from "../nostr.ts";
2023-12-22 12:20:34 +00:00
import { InvalidEvent } from "../features/dm.ts";
2023-06-30 14:05:57 +00:00
2023-09-23 21:54:13 +00:00
export interface ConversationSummary {
2023-06-30 14:05:57 +00:00
pubkey: PublicKey;
2023-10-15 22:39:21 +00:00
newestEventSendByMe?: NostrEvent;
newestEventReceivedByMe?: NostrEvent;
2023-06-30 14:05:57 +00:00
}
2023-10-15 22:39:21 +00:00
export class DM_List implements ConversationListRetriever, NewMessageChecker {
readonly convoSummaries = new Map<string, ConversationSummary>();
2023-12-22 12:20:34 +00:00
readonly newMessages = new Map<string, number>();
2023-09-23 21:54:13 +00:00
constructor(
public readonly ctx: NostrAccountContext,
) {}
2023-12-22 13:03:59 +00:00
newNessageCount(hex: string, isGourpChat: boolean): number {
return this.newMessages.get(hex) || 0;
}
markRead(hex: string, isGourpChat: boolean): void {
this.newMessages.set(hex, 0);
2023-10-07 20:40:18 +00:00
}
*getStrangers() {
2023-09-27 20:04:01 +00:00
for (const convoSummary of this.convoSummaries.values()) {
if (
2023-09-27 20:04:01 +00:00
(
convoSummary.newestEventReceivedByMe == undefined ||
convoSummary.newestEventSendByMe == undefined
) &&
!(
convoSummary.newestEventReceivedByMe == undefined &&
convoSummary.newestEventSendByMe == undefined
)
) {
2023-09-27 20:04:01 +00:00
yield convoSummary;
}
}
}
*getContacts() {
for (const userInfo of this.convoSummaries.values()) {
if (
userInfo.newestEventReceivedByMe != undefined &&
userInfo.newestEventSendByMe != undefined
) {
yield userInfo;
}
}
}
2023-10-04 21:34:43 +00:00
getConversationType(pubkey: PublicKey, isGroupChat: boolean) {
if (isGroupChat) {
return "Group";
}
const contact = this.convoSummaries.get(pubkey.hex);
if (contact == undefined) {
return "Strangers";
}
if (
contact.newestEventReceivedByMe == undefined || contact.newestEventSendByMe == undefined
) {
return "Strangers";
} else {
return "Contacts";
}
}
2023-10-04 15:07:40 +00:00
addEvents(
2023-12-17 20:41:49 +00:00
events: NostrEvent[],
2023-12-22 13:03:59 +00:00
newEvents: boolean,
2023-10-03 15:15:45 +00:00
) {
for (const event of events) {
2023-12-22 12:20:34 +00:00
if (event.kind != NostrKind.DIRECT_MESSAGE) {
continue;
}
2023-12-22 13:03:59 +00:00
const err = this.addEvent({
...event,
kind: event.kind,
}, newEvents);
if (err instanceof Error) {
return err;
}
}
}
2023-12-22 12:20:34 +00:00
2023-12-22 13:03:59 +00:00
private addEvent(event: NostrEvent<NostrKind.DIRECT_MESSAGE>, newEvent: boolean) {
let whoAm_I_TalkingTo = "";
if (event.pubkey == this.ctx.publicKey.hex) {
// I am the sender
whoAm_I_TalkingTo = getTags(event).p[0];
if (whoAm_I_TalkingTo == undefined) {
return new InvalidEvent(event, `event ${event.id} does not have p tags`);
2023-12-22 12:20:34 +00:00
}
2023-12-22 13:03:59 +00:00
} else if (getTags(event).p[0] == this.ctx.publicKey.hex) {
// I am the receiver
whoAm_I_TalkingTo = event.pubkey;
} else {
// I am neither. Possible because other user has used this device before
return;
}
2023-12-22 12:20:34 +00:00
2023-12-22 13:03:59 +00:00
if (newEvent && this.ctx.publicKey.hex != event.pubkey) {
this.newMessages.set(whoAm_I_TalkingTo, this.newNessageCount(whoAm_I_TalkingTo, false) + 1);
}
2023-12-22 12:20:34 +00:00
2023-12-22 13:03:59 +00:00
const userInfo = this.convoSummaries.get(whoAm_I_TalkingTo);
if (userInfo) {
if (whoAm_I_TalkingTo == this.ctx.publicKey.hex) {
// talking to myself
if (userInfo.newestEventSendByMe) {
if (event.created_at > userInfo.newestEventSendByMe?.created_at) {
2023-12-22 12:20:34 +00:00
userInfo.newestEventSendByMe = event;
userInfo.newestEventReceivedByMe = event;
}
} else {
2023-12-22 13:03:59 +00:00
userInfo.newestEventSendByMe = event;
userInfo.newestEventReceivedByMe = event;
}
} else {
if (this.ctx.publicKey.hex == event.pubkey) {
// I am the sender
if (userInfo.newestEventSendByMe) {
if (event.created_at > userInfo.newestEventSendByMe.created_at) {
2023-12-22 12:20:34 +00:00
userInfo.newestEventSendByMe = event;
2023-06-30 14:05:57 +00:00
}
2023-12-22 12:20:34 +00:00
} else {
2023-12-22 13:03:59 +00:00
userInfo.newestEventSendByMe = event;
}
} else {
// I am the receiver
if (userInfo.newestEventReceivedByMe) {
if (event.created_at > userInfo.newestEventReceivedByMe.created_at) {
2023-12-22 12:20:34 +00:00
userInfo.newestEventReceivedByMe = event;
2023-06-30 14:05:57 +00:00
}
2023-12-22 13:03:59 +00:00
} else {
userInfo.newestEventReceivedByMe = event;
2023-06-30 14:05:57 +00:00
}
2023-12-22 12:20:34 +00:00
}
2023-12-22 13:03:59 +00:00
}
} else {
const pubkey = PublicKey.FromHex(whoAm_I_TalkingTo);
if (pubkey instanceof Error) {
return new InvalidEvent(event, pubkey.message);
}
const newUserInfo: ConversationSummary = {
pubkey,
newestEventReceivedByMe: undefined,
newestEventSendByMe: undefined,
};
if (whoAm_I_TalkingTo == this.ctx.publicKey.hex) {
// talking to myself
newUserInfo.newestEventSendByMe = event;
newUserInfo.newestEventReceivedByMe = event;
2023-12-22 12:20:34 +00:00
} else {
2023-12-22 13:03:59 +00:00
if (this.ctx.publicKey.hex == event.pubkey) {
// I am the sender
2023-12-22 12:20:34 +00:00
newUserInfo.newestEventSendByMe = event;
} else {
2023-12-22 13:03:59 +00:00
// I am the receiver
newUserInfo.newestEventReceivedByMe = event;
2023-12-22 12:20:34 +00:00
}
2023-06-30 14:05:57 +00:00
}
2023-12-22 13:03:59 +00:00
this.convoSummaries.set(whoAm_I_TalkingTo, newUserInfo);
2023-06-30 14:05:57 +00:00
}
}
}
2023-09-23 21:54:13 +00:00
export const sortUserInfo = (a: ConversationSummary, b: ConversationSummary) => {
2023-06-30 14:05:57 +00:00
return sortScore(b) - sortScore(a);
};
2023-09-23 21:54:13 +00:00
function sortScore(contact: ConversationSummary) {
2023-06-30 14:05:57 +00:00
let score = 0;
if (contact.newestEventSendByMe !== undefined) {
score += contact.newestEventSendByMe.created_at;
}
if (contact.newestEventReceivedByMe !== undefined) {
score += contact.newestEventReceivedByMe.created_at;
}
return score;
}