From 1ab5e65191004f8cd131f7fda0d41552131f99e3 Mon Sep 17 00:00:00 2001 From: BlowaterNostr <127284497+BlowaterNostr@users.noreply.github.com> Date: Thu, 21 Mar 2024 14:04:32 +0800 Subject: [PATCH] render replies (#432) Co-authored-by: bob2402 --- app/UI/message-list.tsx | 247 ++++++++++++++++++++++++---------------- 1 file changed, 149 insertions(+), 98 deletions(-) diff --git a/app/UI/message-list.tsx b/app/UI/message-list.tsx index e32aa9d..9a95ec9 100644 --- a/app/UI/message-list.tsx +++ b/app/UI/message-list.tsx @@ -1,4 +1,11 @@ -import { Component, createRef, h } from "https://esm.sh/preact@10.17.1"; +import { + Component, + ComponentChildren, + createRef, + Fragment, + h, + RefObject, +} from "https://esm.sh/preact@10.17.1"; import { PublicKey } from "../../libs/nostr.ts/key.ts"; import { RelayRecordGetter } from "../database.ts"; import { emitFunc } from "../event-bus.ts"; @@ -25,7 +32,7 @@ import { Parsed_Event } from "../nostr.ts"; import { NoteID } from "../../libs/nostr.ts/nip19.ts"; import { robohash } from "./relay-detail.tsx"; -interface MessageListProps { +interface Props { myPublicKey: PublicKey; messages: ChatMessage[]; emit: emitFunc; @@ -42,7 +49,7 @@ interface MessageListState { const ItemsOfPerPage = 50; -export class MessageList extends Component { +export class MessageList extends Component { readonly messagesULElement = createRef(); state = { @@ -51,7 +58,7 @@ export class MessageList extends Component { jitter = new JitterPrevention(100); - async componentDidUpdate(previousProps: Readonly) { + async componentDidUpdate(previousProps: Readonly) { const newest = last(this.props.messages); const pre_newest = last(previousProps.messages); if ( @@ -74,12 +81,12 @@ export class MessageList extends Component { const sameAuthor = pre.event.pubkey == cur.event.pubkey; const _66sec = Math.abs(cur.created_at.getTime() - pre.created_at.getTime()) < 1000 * 60; - return sameAuthor && _66sec; + const is_not_reply = cur.event.parsedTags.e.length === 0; // todo: make a isReply(event) function + return sameAuthor && _66sec && is_not_reply; }); const messageBoxGroups = []; for (const messages of groups) { - const profileEvent = this.props.getters.profileGetter - .getProfilesByPublicKey(messages[0].author); + const profileEvent = this.props.getters.profileGetter.getProfilesByPublicKey(messages[0].author); messageBoxGroups.push( MessageBoxGroup({ messages: messages, @@ -92,35 +99,14 @@ export class MessageList extends Component { } return ( -
- + {MessageListView(this.goToButtom, this.messagesULElement, messageBoxGroups)} + -
    - - {messageBoxGroups} - -
); } @@ -170,7 +156,40 @@ export class MessageList extends Component { }; } -export class MessageList_V0 extends Component { +function MessageListView( + goToButtom: (smooth: boolean) => void, + messagesULElement: RefObject, + messageBoxGroups: ComponentChildren, +) { + return ( +
+ +
    + {messageBoxGroups} +
+
+ ); +} + +export class MessageList_V0 extends Component { readonly messagesULElement = createRef(); jitter = new JitterPrevention(100); @@ -179,7 +198,7 @@ export class MessageList_V0 extends Component { this.goToButtom(false); } - componentDidUpdate(previousProps: Readonly): void { + componentDidUpdate(previousProps: Readonly): void { // todo: this is not a correct check of if new message is received // a better check is to see if the // current newest message is newer than previous newest message @@ -190,7 +209,6 @@ export class MessageList_V0 extends Component { render() { const messages_to_render = this.sortAndSliceMessage(); - console.log(messages_to_render); const groups = groupContinuousMessages(messages_to_render, (pre, cur) => { const sameAuthor = pre.event.pubkey == cur.event.pubkey; const _66sec = Math.abs(cur.created_at.getTime() - pre.created_at.getTime()) < @@ -212,33 +230,7 @@ export class MessageList_V0 extends Component { ); } - return ( -
- -
    - {messageBoxGroups} -
-
- ); + return MessageListView(this.goToButtom, this.messagesULElement, messageBoxGroups); } sortAndSliceMessage = () => { @@ -292,46 +284,72 @@ function MessageBoxGroup(props: { }) { const first_message = props.messages[0]; const rows = []; + + // check if the first message is a reply message + function isReply(event: Parsed_Event) { + if (event.parsedTags.e.length == 0) { + return; + } + const reply_to_event = props.getters.getEventByID(event.parsedTags.e[0]); + if (!reply_to_event) { + return ; + } + let author = reply_to_event.publicKey.bech32(); + let picture = robohash(reply_to_event.publicKey.hex); + if (reply_to_event.pubkey) { + const profile = props.getters.profileGetter.getProfilesByPublicKey(reply_to_event.publicKey); + if (profile) { + author = profile.profile.name || profile.profile.display_name || + reply_to_event?.publicKey.bech32(); + picture = profile.profile.picture || robohash(reply_to_event.publicKey.hex); + } + } + return ; + } + rows.push(
  • {MessageActions(first_message, props.emit)} - { - props.emit({ - type: "ViewUserDetail", - pubkey: first_message.author, - }); - }} - /> + {isReply(first_message.event)} +
    + { + props.emit({ + type: "ViewUserDetail", + pubkey: first_message.author, + }); + }} + /> -
    - {NameAndTime( - first_message.author, - props.authorProfile, - props.myPublicKey, - first_message.created_at, - )} -
    -                    {ParseMessageContent(
    -                        first_message,
    -                        props.emit,
    -                        props.getters,
    -                        )}
    -                
    + {NameAndTime( + first_message.author, + props.authorProfile, + props.myPublicKey, + first_message.created_at, + )} +
    +                {ParseMessageContent(
    +                   first_message,
    +                    props.emit,
    +                    props.getters,
    +                    )}
    +                    
    +
  • , ); @@ -368,7 +386,6 @@ function MessageBoxGroup(props: { ); - // console.log("MessageBoxGroup", Date.now() - t); return vnode; } @@ -410,3 +427,37 @@ function last(array: Array): T | undefined { return array[array.length - 1]; } } + +function ReplyTo( + props: { unknown?: false; content: string; replyName: string; replayPic: string } | { + unknown: true; + noteId: NoteID; + }, +) { + return ( +
    +
    +
    +
    +
    + {props.unknown + ? ( +
    + {props.noteId.bech32()} +
    + ) + : ( + <> + +
    + @{props.replyName} +
    +
    + {props.content} +
    + + )} +
    +
    + ); +}