fix ConversationList & simplify DirectMessageContainer (#359)

This commit is contained in:
BlowaterNostr 2023-12-22 18:20:37 +08:00 committed by GitHub
parent 3f1bebb790
commit e6a1819b72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 260 additions and 235 deletions

View File

@ -412,29 +412,23 @@ export function AppComponent(props: {
) { ) {
if (model.navigationModel.activeNav == "DM") { if (model.navigationModel.activeNav == "DM") {
dmVNode = ( dmVNode = (
<div <DirectMessageContainer
class={tw`flex-1 overflow-hidden`} {...model.dm}
> rightPanelModel={model.rightPanelModel}
{DirectMessageContainer({ bus={app.eventBus}
...model.dm, ctx={myAccountCtx}
rightPanelModel: model.rightPanelModel, profileGetter={app.database}
bus: app.eventBus, pool={props.pool}
ctx: myAccountCtx, conversationLists={app.conversationLists}
profileGetter: app.database, profilesSyncer={app.profileSyncer}
pool: props.pool, eventSyncer={app.eventSyncer}
conversationLists: app.conversationLists, pinListGetter={app.otherConfig}
profilesSyncer: app.profileSyncer, groupChatController={app.groupChatController}
eventSyncer: app.eventSyncer, newMessageChecker={app.conversationLists}
pinListGetter: app.otherConfig, messageGetter={model.dm.isGroupMessage ? app.groupChatController : app.dmController}
groupChatController: app.groupChatController, newMessageListener={model.dm.isGroupMessage ? app.groupChatController : app.dmController}
newMessageChecker: app.conversationLists, relayRecordGetter={app.database}
messageGetter: model.dm.isGroupMessage ? app.groupChatController : app.dmController, />
newMessageListener: model.dm.isGroupMessage
? app.groupChatController
: app.dmController,
relayRecordGetter: app.database,
})}
</div>
); );
} }
@ -446,7 +440,7 @@ export function AppComponent(props: {
console.debug("AppComponent:2", Date.now() - t); console.debug("AppComponent:2", Date.now() - t);
const final = ( const final = (
<div class={tw`h-screen fixed w-full flex-1 flex overflow-hidden`}> <div class={tw`h-screen w-full flex`}>
<nav.NavBar <nav.NavBar
publicKey={app.ctx.publicKey} publicKey={app.ctx.publicKey}
profileGetter={app.database} profileGetter={app.database}

View File

@ -6,7 +6,6 @@ import { Datebase_View } from "../database.ts";
import { PrivateKey } from "../lib/nostr-ts/key.ts"; import { PrivateKey } from "../lib/nostr-ts/key.ts";
import { InMemoryAccountContext, NostrEvent, NostrKind } from "../lib/nostr-ts/nostr.ts"; import { InMemoryAccountContext, NostrEvent, NostrKind } from "../lib/nostr-ts/nostr.ts";
import { testEventBus } from "./_setup.test.ts"; import { testEventBus } from "./_setup.test.ts";
import { initialModel } from "./app_model.ts";
import { DM_List } from "./conversation-list.ts"; import { DM_List } from "./conversation-list.ts";
import { NewIndexedDB } from "./dexie-db.ts"; import { NewIndexedDB } from "./dexie-db.ts";
import { ProfileSyncer } from "../features/profile.ts"; import { ProfileSyncer } from "../features/profile.ts";
@ -16,7 +15,6 @@ import { GroupChatSyncer, GroupMessageController } from "../features/gm.ts";
import { Channel } from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts"; import { Channel } from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
import { LamportTime } from "../time.ts"; import { LamportTime } from "../time.ts";
import { prepareEncryptedNostrEvent } from "../lib/nostr-ts/event.ts"; import { prepareEncryptedNostrEvent } from "../lib/nostr-ts/event.ts";
import { PublicKey } from "../lib/nostr-ts/nodejs/index.mjs";
const ctx = InMemoryAccountContext.Generate(); const ctx = InMemoryAccountContext.Generate();
const db = NewIndexedDB(); const db = NewIndexedDB();

View File

@ -107,12 +107,15 @@ export class ConversationList extends Component<Props, State> {
return ( return (
<div <div
class={tw`h-screen flex flex-col mobile:w-full desktop:w-64 bg-[${SecondaryBackgroundColor}]`} // https://tailwindcss.com/docs/hover-focus-and-other-states#quick-reference
class={`
h-screen w-80 max-sm:w-full
flex flex-col bg-[${SecondaryBackgroundColor}]`}
> >
<div <div
class={tw`flex items-center gap-2 px-4 h-20 border-b border-[#36393F]`} class={`gap-2 py-2.5 px-4 border-b border-[#36393F]`}
> >
<div class={`flex-1 ${LinearGradientsClass}} items-center`}> <div class={`${LinearGradientsClass} flex items-center justify-center rounded-lg`}>
<button <button
onClick={async () => { onClick={async () => {
props.emit({ props.emit({

View File

@ -69,7 +69,5 @@
} }
</style> </style>
</head> </head>
<body> <body></body>
</body>
</html> </html>

View File

@ -76,7 +76,5 @@
} }
</style> </style>
</head> </head>
<body> <body></body>
</body>
</html> </html>

View File

@ -69,8 +69,7 @@ pool.addRelayURL(relays[0]);
const gmControl = new GroupMessageController(ctx, { add: (_) => {} }, { add: (_) => {} }); const gmControl = new GroupMessageController(ctx, { add: (_) => {} }, { add: (_) => {} });
const dmControl = new DirectedMessageController(ctx); const dmControl = new DirectedMessageController(ctx);
const view = () => { render(
return (
<DirectMessageContainer <DirectMessageContainer
conversationLists={dm_list} conversationLists={dm_list}
eventSyncer={new EventSyncer(pool, database)} eventSyncer={new EventSyncer(pool, database)}
@ -91,11 +90,9 @@ const view = () => {
newMessageChecker={dm_list} newMessageChecker={dm_list}
newMessageListener={dmControl} newMessageListener={dmControl}
relayRecordGetter={database} relayRecordGetter={database}
/> />,
); document.body,
}; );
render(view(), document.body);
(async () => { (async () => {
for await (const event of database.subscribe()) { for await (const event of database.subscribe()) {
@ -105,25 +102,3 @@ render(view(), document.body);
dm_list.addEvents([event]); dm_list.addEvents([event]);
} }
})(); })();
for await (const e of testEventBus.onChange()) {
console.log(e);
if (e.type == "SendMessage") {
const err = await handle_SendMessage(
e,
ctx,
lamport,
pool,
model.dmEditors,
model.gmEditors,
database,
gmControl,
);
if (err instanceof Error) {
console.error("update:SendMessage", err);
continue; // todo: global error toast
}
}
render(view(), document.body);
}

143
UI/dm.tsx
View File

@ -1,5 +1,5 @@
/** @jsx h */ /** @jsx h */
import { h } from "https://esm.sh/preact@10.17.1"; import { Component, h, VNode } from "https://esm.sh/preact@10.17.1";
import * as cl from "./conversation-list.tsx"; import * as cl from "./conversation-list.tsx";
import { MessagePanel, NewMessageListener } from "./message-panel.tsx"; import { MessagePanel, NewMessageListener } from "./message-panel.tsx";
import { EventBus } from "../event-bus.ts"; import { EventBus } from "../event-bus.ts";
@ -22,6 +22,7 @@ import { UserIcon } from "./icons/user-icon.tsx";
import { LeftArrowIcon } from "./icons/left-arrow-icon.tsx"; import { LeftArrowIcon } from "./icons/left-arrow-icon.tsx";
import { RelayRecordGetter } from "../database.ts"; import { RelayRecordGetter } from "../database.ts";
import { RightPanelModel } from "./right-panel.tsx"; import { RightPanelModel } from "./right-panel.tsx";
import { Channel, PopChannel } from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
export type DM_Model = { export type DM_Model = {
currentEditor: EditorModel | undefined; currentEditor: EditorModel | undefined;
@ -52,7 +53,44 @@ export type StartInvite = {
publicKey: PublicKey; publicKey: PublicKey;
}; };
export function DirectMessageContainer(props: DirectMessageContainerProps) { type State = {
currentEditor: EditorModel | undefined;
};
export class DirectMessageContainer extends Component<DirectMessageContainerProps, State> {
changes?: PopChannel<UI_Interaction_Event>;
state: State = {
currentEditor: undefined,
};
componentWillUpdate(nextProps: Readonly<DirectMessageContainerProps>): void {
this.setState({
currentEditor: nextProps.currentEditor,
});
}
async componentDidMount() {
this.setState({
currentEditor: this.props.currentEditor,
});
const changes = this.props.bus.onChange();
this.changes = changes;
for await (const change of changes) {
if (change.type == "SelectConversation") {
// todo
}
}
}
componentWillUnmount(): void {
if (this.changes) {
this.changes.close();
}
}
render(props: DirectMessageContainerProps) {
const t = Date.now(); const t = Date.now();
const currentEditor = props.currentEditor; const currentEditor = props.currentEditor;
@ -112,7 +150,11 @@ export function DirectMessageContainer(props: DirectMessageContainerProps) {
<div <div
class={`h-full w-full flex bg-[#36393F] overflow-hidden`} class={`h-full w-full flex bg-[#36393F] overflow-hidden`}
> >
<div class={`${props.currentEditor ? "mobile:hidden" : "mobile:w-full"}`}> <div
class={`w-fit
max-sm:w-full
${props.currentEditor ? "max-sm:hidden" : ""}`}
>
<cl.ConversationList <cl.ConversationList
eventBus={props.bus} eventBus={props.bus}
emit={props.bus.emit} emit={props.bus.emit}
@ -122,13 +164,57 @@ export function DirectMessageContainer(props: DirectMessageContainerProps) {
{...props} {...props}
/> />
</div> </div>
{props.currentEditor
{this.state.currentEditor
? ( ? (
<div class={`h-screen flex-1 overflow-hidden flex-col flex`}> <div class={`flex flex-col flex-1 overflow-hidden`}>
<TopBar
bus={this.props.bus}
buttons={buttons}
currentEditor={this.state.currentEditor}
profileGetter={this.props.profileGetter}
showRightPanel={this.props.rightPanelModel.show}
/>
<div class={`flex-1 overflow-auto`}>
<MessagePanel
myPublicKey={props.ctx.publicKey}
rightPanelModel={props.rightPanelModel}
emit={props.bus.emit}
newMessageListener={props.newMessageListener}
focusedContent={getFocusedContent(
props.focusedContent.get(this.state.currentEditor.pubkey.hex),
props.profileGetter,
)}
profilesSyncer={props.profilesSyncer}
eventSyncer={props.eventSyncer}
isGroupMessage={props.isGroupMessage}
profileGetter={props.profileGetter}
editorModel={this.state.currentEditor}
messageGetter={props.messageGetter}
relayRecordGetter={props.relayRecordGetter}
/>
</div>
</div>
)
: undefined}
</div>
);
console.debug("DirectMessageContainer:end", Date.now() - t);
return vDom;
}
}
function TopBar(props: {
bus: EventBus<UI_Interaction_Event>;
currentEditor: EditorModel;
profileGetter: ProfileGetter;
showRightPanel: boolean;
buttons: VNode[];
}) {
return (
<div <div
class={`h-14 mobile:h-12 class={`h-14 border-l border-b border-[#36393F] flex
border-l border-b border-[#36393F] flex items-center justify-between bg-[#2F3136]`}
items-center justify-between px- mobile:px-2 bg-[#2F3136]`}
> >
<div class={`flex items-center overflow-hidden`}> <div class={`flex items-center overflow-hidden`}>
<button <button
@ -162,24 +248,26 @@ export function DirectMessageContainer(props: DirectMessageContainerProps) {
}); });
}} }}
> >
{props.profileGetter.getProfilesByPublicKey(props.currentEditor.pubkey) {props.profileGetter.getProfilesByPublicKey(
props.currentEditor.pubkey,
)
?.profile.name || ?.profile.name ||
props.currentEditor.pubkey.bech32()} props.currentEditor.pubkey.bech32()}
</span> </span>
</div> </div>
<div> <div>
{buttons} {props.buttons}
{!props.rightPanelModel.show {!props.showRightPanel
? ( ? (
<button <button
class={`absolute z-10 w-6 h-6 transition-transform duration-100 ease-in-out right-4 mobile:right-0 top-4${ class={`absolute z-10 w-6 h-6 transition-transform duration-100 ease-in-out right-4 mobile:right-0 top-4${
props.rightPanelModel.show ? " rotate-180" : "" props.showRightPanel ? " rotate-180" : ""
} ${IconButtonClass}`} } ${IconButtonClass}`}
onClick={() => { onClick={() => {
props.bus.emit({ props.bus.emit({
type: "ToggleRightPanel", type: "ToggleRightPanel",
show: !props.rightPanelModel.show, show: !props.showRightPanel,
}); });
}} }}
> >
@ -194,34 +282,5 @@ export function DirectMessageContainer(props: DirectMessageContainerProps) {
: undefined} : undefined}
</div> </div>
</div> </div>
<div class={`flex-1 overflow-x-auto`}>
{props.currentEditor
? (
<MessagePanel
myPublicKey={props.ctx.publicKey}
rightPanelModel={props.rightPanelModel}
emit={props.bus.emit}
newMessageListener={props.newMessageListener}
focusedContent={getFocusedContent(
props.focusedContent.get(props.currentEditor.pubkey.hex),
props.profileGetter,
)}
profilesSyncer={props.profilesSyncer}
eventSyncer={props.eventSyncer}
isGroupMessage={props.isGroupMessage}
profileGetter={props.profileGetter}
editorModel={props.currentEditor}
messageGetter={props.messageGetter}
relayRecordGetter={props.relayRecordGetter}
/>
)
: undefined}
</div>
</div>
)
: undefined}
</div>
); );
console.debug("DirectMessageContainer:end", Date.now() - t);
return vDom;
} }