Add very basic chat display

This commit is contained in:
SondreB 2023-05-28 21:44:32 +02:00
parent f3e7422c1a
commit c88de0d3e3
No known key found for this signature in database
GPG Key ID: D6CC44C75005FDBF
15 changed files with 159 additions and 136 deletions

View File

@ -1,53 +1,9 @@
<mat-nav-list>
<div class="search">
<mat-form-field appearance="fill" class="input-full-width">
<input matInput type="text" placeholder="Search..." />
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
</div>
<ng-container *ngFor="let chat of ui.chats$ | async; let lastItem = last">
<mat-list-item>
<img alt="" matListItemAvatar [src]="chat.picture" />
<span matListItemTitle>{{ chat.name }}</span>
<span matListItemLine class="last-message">{{ chat.about }}</span>
<span matListItemLine><app-profile-name [pubkey]="chat.pubkey"></app-profile-name></span>
<!-- <span *ngIf="chat.lastMessageLength" [matBadge]="chat.lastMessageLength" matBadgeOverlap="false" matBadgePosition="above before" matBadgeColor="warn"></span> -->
</mat-list-item>
<!-- <app-chat-item [routerLink]="['/m', chat.id]" [chat]="chat"></app-chat-item> -->
<mat-divider *ngIf="!lastItem"></mat-divider>
</ng-container>
<!-- <ng-container *ngFor="let event of chatService.chats2$ | async; let lastItem = last">
<app-chat-item [routerLink]="['/m', '5f432a9f39b58ff132fc0a4c8af10d42efd917d8076f68bb7f2f91ed7d4f6a41']" [event]="event"></app-chat-item>
<mat-divider *ngIf="!lastItem"></mat-divider>
</ng-container> -->
</mat-nav-list>
<!-- <div *ngFor="let chat of chatService.chats3">{{ chat.pubkey }} : {{ chat.content }}</div> -->
<!-- <div *ngIf="chatService.uniqueChats$ | async as chats">
<div *ngFor="let chat of chats">{{ chat.pubkey }} : {{ chat.content }}</div>
</div> -->
<!-- <div *ngIf="chats$ | async as chats">
<div *ngFor="let chat of chats">{{ chat.id }} : {{ chat.name }}</div>
</div> -->
<!-- <button (click)="add()">Add</button>
<button (click)="reset()">Reset</button>
<button (click)="chatService.download()">Download</button> -->
<!-- <app-chat-list (openChatSidebar)="open.chatSideBar($event)"></app-chat-list> -->
<!-- <mat-sidenav-container class="drawer-container" autosize>
<mat-sidenav-container class="drawer-container" autosize>
<mat-tab-group mat-align-tabs="center">
<mat-tab label="Messages">
<mat-tab label="Subscribed">
<app-chat-list (openChatSidebar)="open.chatSideBar($event)"></app-chat-list>
</mat-tab>
<mat-tab label="Users">
<mat-tab label="Public">
<app-user-list (openUserSidebar)="open.userSideBar($event)"></app-user-list>
</mat-tab>
</mat-tab-group>
@ -69,4 +25,4 @@
</mat-toolbar>
<app-user-profile (openChatWindow)="open.chatSideBar($event)"></app-user-profile>
</mat-sidenav>
</mat-sidenav-container> -->
</mat-sidenav-container>

View File

@ -29,35 +29,3 @@
.spacer {
flex: 1;
}
.form {
padding: 16px 16px 0 16px;
}
.input-full-width {
position: relative;
margin: auto;
}
.search {
position: sticky;
top: 0;
padding: 10px;
z-index: 999;
}
.last-message {
text-overflow: ellipsis;
overflow: hidden;
width: 90%;
white-space: nowrap;
}
.user-avatar{
height: 50px;
width: 50px;
}
mat-list-item{
height: 90px !important;
}

View File

@ -1,10 +1,9 @@
import { Component, ChangeDetectorRef, ViewChild, ViewEncapsulation } from '@angular/core';
import { MatSidenav } from '@angular/material/sidenav';
import { ApplicationState } from '../services/applicationstate';
import { ChatService } from '../services/chat.service';
import { UIService } from '../services/ui';
import { RelayService } from '../services/relay';
import { Kind } from 'nostr-tools';
import { UIService } from '../services/ui';
@Component({
selector: 'app-chat',
templateUrl: './chat.html',
@ -14,10 +13,9 @@ import { UIService } from '../services/ui';
export class ChatComponent {
@ViewChild('chatSidebar', { static: false }) chatSidebar!: MatSidenav;
@ViewChild('userSidebar', { static: false }) userSidebar!: MatSidenav;
subscription?: string;
subscription: any;
constructor(private appState: ApplicationState, private chatService: ChatService, private relayService: RelayService, public ui: UIService) {}
constructor(private appState: ApplicationState, private relayService: RelayService, public ui: UIService) {}
sidebarTitles = {
user: '',
chat: '',
@ -29,6 +27,7 @@ export class ChatComponent {
this.me.sidebarTitles.user = title;
},
chatSideBar: function (title: string = '') {
debugger;
this.me.chatSidebar.open();
this.me.userSidebar.close();
this.me.sidebarTitles.chat = title;
@ -37,12 +36,15 @@ export class ChatComponent {
async ngOnInit() {
this.ui.clearChats();
this.subscription = this.relayService.subscribe([{ kinds: [Kind.ChannelCreation, Kind.ChannelMetadata], limit: 10 }]).id;
this.appState.updateTitle('Chat');
this.appState.goBack = true;
this.appState.actions = [];
}
this.subscription = this.relayService.subscribe([{ kinds: [Kind.ChannelCreation, Kind.ChannelMetadata], limit: 10 }]).id;
// this.chatService.downloadChatRooms();
ngOnDestroy() {
// this.relayService.unsubscribe(this.subscription!);
// this.ui.clearChats();
}
}

View File

@ -32,7 +32,7 @@ export class MessageComponent {
};
async ngOnInit() {
this.appState.updateTitle('@Milad');
this.appState.updateTitle('');
this.appState.goBack = true;
this.appState.showBackButton = true;
this.appState.actions = [];

View File

@ -319,11 +319,11 @@ export interface UserModel {
bio: string;
}
export interface MessageModel {
id: number;
cover: string;
message: string;
}
// export interface MessageModel {
// id: number;
// cover: string;
// message: string;
// }
export interface CustomObjectModel {
tmpl: string;
@ -344,7 +344,7 @@ export class ChatModel {
'cover': string;
'lastMessage': string;
'lastMessageLength': string | number;
'chat': Array<MessageModel>;
// 'chat': Array<MessageModel>;
}
export interface LabelModel {

View File

@ -435,6 +435,10 @@ export class RelayService {
this.ui.putChatMetadata(event);
}
if (event.kind == Kind.ChannelMessage) {
this.ui.putChatMessage(event);
}
if (response.subscription) {
const sub = this.subs.get(response.subscription);
if (sub) {

View File

@ -27,6 +27,7 @@ export class UIService {
replyEventsView: [] as NostrEventDocument[],
reactions: new Map<string, ThreadEntry>(),
chats: [] as NostrEventChat[],
chatMessages: [] as NostrEventChat[],
};
viewCounts = {
@ -165,6 +166,14 @@ export class UIService {
return this.#chatsChanged.asObservable();
}
chatMessage: NostrEvent[] = [];
#chatMessageChanged: BehaviorSubject<NostrEvent[]> = new BehaviorSubject<NostrEvent[]>(this.chatMessage);
get chatMessage$(): Observable<NostrEvent[]> {
return this.#chatMessageChanged.asObservable();
}
#loadMore: BehaviorSubject<LoadMoreOptions | undefined> = new BehaviorSubject<LoadMoreOptions | undefined>(undefined);
get loadMore$(): Observable<LoadMoreOptions | undefined> {
@ -362,6 +371,34 @@ export class UIService {
// this.triggerUnreadNotifications();
}
putChatMessage(event: NostrEvent) {
const index = this.chatMessage.findIndex((n) => n.id == event.id);
if (index == -1) {
const chat = event as NostrEvent;
try {
this.chatMessage.push(chat);
this.#chatMessageChanged.next(this.chatMessage);
} catch (err) {
console.debug('Failed to parse: ', chat.content);
}
}
// if (index == -1) {
// this.#notifications.unshift(notification);
// this.#notifications = this.#notifications.sort((a, b) => {
// return a.created < b.created ? 1 : -1;
// });
// } else {
// this.#notifications[index] = notification;
// }
// this.#activityFeed = this.#notifications.slice(0, 5);
// this.triggerUnreadNotifications();
}
viewEventsStart = 0;
viewEventsCount = 5;
@ -787,6 +824,7 @@ export class UIService {
this.#lists.reactions = new Map<string, ThreadEntry>();
this.#lists.chats = [];
this.#lists.chatMessages = [];
this.#notifications = [];
this.#activityFeed = [];
@ -846,6 +884,14 @@ export class UIService {
clearChats() {
this.#lists.chats = [];
this.chats = [];
this.#chatsChanged.next(this.chats);
}
clearChatMessages() {
this.#lists.chatMessages = [];
this.chatMessage = [];
this.#chatMessageChanged.next(this.chatMessage);
}
// #parentEventId: string | undefined = undefined;

View File

@ -1,5 +1,3 @@
<mat-drawer-container class="chat-detail-container" autosize>
<mat-drawer #drawer class="chat-detail-sidenav list-hide-small" opened mode="side">
<app-chat-list></app-chat-list>
@ -8,8 +6,9 @@
<div class="chat-detail-sidenav-content">
<div class="messages-list-container">
<div #scrollable class="scrollable">
<ng-container *ngIf="chat">
<ng-container *ngFor="let message of chat.chat">
<ng-container>
<ng-container *ngFor="let message of ui.chatMessage$ | async">
<!-- {{ message | json }} -->
<app-message-bubble [message]="message"></app-message-bubble>
</ng-container>
</ng-container>
@ -17,10 +16,9 @@
</div>
<div class="message-send">
<emoji-mart class="emoji-picker" *ngIf="isEmojiPickerVisible" emoji="point_up" [isNative]="true" [showPreview]="false"
(emojiSelect)="addEmoji($event)" title="Choose your emoji"></emoji-mart>
<emoji-mart class="emoji-picker" *ngIf="isEmojiPickerVisible" emoji="point_up" [isNative]="true" [showPreview]="false" (emojiSelect)="addEmoji($event)" title="Choose your emoji"></emoji-mart>
<button type="button" class="list-hide-small" style="margin: 5px;" mat-icon-button (click)="toggle()">
<button type="button" class="list-hide-small" style="margin: 5px" mat-icon-button (click)="toggle()">
<mat-icon *ngIf="displayList">chevron_left</mat-icon>
<mat-icon *ngIf="!displayList">chevron_right</mat-icon>
</button>
@ -41,11 +39,9 @@
<span>Document</span>
</button>
</mat-menu>
<input type="text" matInput placeholder="Write a message" [(ngModel)]="message"
(keypress)="saveMessage($event)">
<input type="text" matInput placeholder="Write a message" [(ngModel)]="message" (keypress)="saveMessage($event)" />
<mat-hint align="end" class="hint">Length : {{ message?.length }}</mat-hint>
<mat-icon class="toolbar-icon" matSuffix (click)="isEmojiPickerVisible = !isEmojiPickerVisible;"
matTooltip="Insert emoji">sentiment_satisfied</mat-icon>
<mat-icon class="toolbar-icon" matSuffix (click)="isEmojiPickerVisible = !isEmojiPickerVisible" matTooltip="Insert emoji">sentiment_satisfied</mat-icon>
<mat-icon class="toolbar-icon" matSuffix>mic</mat-icon>
<mat-icon class="toolbar-icon" (click)="send(message)" matSuffix>send</mat-icon>
@ -53,10 +49,4 @@
</div>
</div>
</div>
</mat-drawer-container>

View File

@ -1,10 +1,15 @@
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { MatSidenav } from '@angular/material/sidenav';
import { ActivatedRoute } from '@angular/router';
import { Kind } from 'nostr-tools';
import { Subscription } from 'rxjs';
import { ApplicationState } from 'src/app/services/applicationstate';
import { ChatService } from 'src/app/services/chat.service';
import { ChatModel } from 'src/app/services/interfaces';
import { MessageControlService } from 'src/app/services/message-control.service';
import { RelayService } from 'src/app/services/relay';
import { UIService } from 'src/app/services/ui';
import { Utilities } from 'src/app/services/utilities';
@Component({
selector: 'app-chat-detail',
@ -16,16 +21,45 @@ export class ChatDetailComponent implements OnInit, OnDestroy {
@ViewChild('picker') picker: unknown;
isEmojiPickerVisible: boolean | undefined;
subscription!: Subscription;
chat!: ChatModel;
sending: boolean = false;
message: any;
displayList = true;
constructor(private service: ChatService, private control: MessageControlService, private appState: ApplicationState) { }
constructor(private relayService: RelayService, public ui: UIService, private service: ChatService, private activatedRoute: ActivatedRoute, private utilities: Utilities, private control: MessageControlService, private appState: ApplicationState) {}
@ViewChild('drawer') drawer!: MatSidenav;
subscription?: string;
subscriptions: Subscription[] = [];
ngOnInit() {
this.subscriptions.push(
this.activatedRoute.paramMap.subscribe(async (params) => {
const id: any = params.get('id');
this.ui.clearChatMessages();
this.relayService.unsubscribe(this.subscription!);
this.subscription = this.relayService.subscribe([{ kinds: [Kind.ChannelMessage, Kind.ChannelMuteUser, Kind.ChannelHideMessage], ['#e']: [id], limit: 500 }]).id;
// this.ui.clearFeed();
// if (circle != null) {
// this.circle = Number(circle);
// this.ui.setFeedCircle(this.circle);
// } else {
// this.circle = -1;
// this.ui.setFeedCircle(this.circle);
// }
// this.subscriptions.push(
// this.navigation.showMore$.subscribe(() => {
// this.showMore();
// })
// );
})
);
// debugger;
// this.subscription = this.relayService.subscribe([{ kinds: [Kind.ChannelMessage, Kind.ChannelMuteUser, Kind.ChannelHideMessage], ['#e']: [this.pubkey], limit: 500 }]).id;
// this.subscription = this.service.chat.subscribe((messages) => {
// this.chat = messages;
@ -72,6 +106,7 @@ export class ChatDetailComponent implements OnInit, OnDestroy {
}
ngOnDestroy(): void {
this.subscription?.unsubscribe();
this.relayService.unsubscribe(this.subscription!);
this.utilities.unsubscribe(this.subscriptions);
}
}

View File

@ -1,6 +1,11 @@
<mat-list-item (click)="showMessageDetail()">
<img alt="" matListItemAvatar [src]="chat.cover" />
<img alt="" matListItemAvatar [src]="chat.picture" />
<span matListItemTitle>{{ chat.name }}</span>
<span matListItemLine class="last-message">{{ chat.about }}</span>
<span matListItemLine><app-profile-name [pubkey]="chat.pubkey"></app-profile-name></span>
<!-- <img alt="" matListItemAvatar [src]="chat.cover" />
<h4 mat-line>{{ chat.username }}</h4>
<p mat-line class="last-message">{{ chat.lastMessage }}</p>
<span *ngIf="chat.lastMessageLength" [matBadge]="chat.lastMessageLength" matBadgeOverlap="false" matBadgePosition="above before" matBadgeColor="warn"></span>
<p mat-line class="last-message">{{ chat.lastMessage }}</p> -->
<!-- <span *ngIf="chat.lastMessageLength" [matBadge]="chat.lastMessageLength" matBadgeOverlap="false" matBadgePosition="above before" matBadgeColor="warn"></span> -->
</mat-list-item>

View File

@ -15,7 +15,7 @@ export class ChatItemComponent {
constructor(private service: ChatService) {}
showMessageDetail() {
this.openChatSidebar.emit(this.chat.username);
this.openChatSidebar.emit(this.chat.id);
// this.service.chat.next(this.chat);
}
}

View File

@ -7,7 +7,7 @@
</mat-form-field>
</div>
<ng-container *ngFor="let chat of chatService.chats$ | async; let lastItem = last">
<ng-container *ngFor="let chat of ui.chats$ | async; let lastItem = last">
<app-chat-item [routerLink]="['/m', chat.id]" [chat]="chat"></app-chat-item>
<mat-divider *ngIf="!lastItem"></mat-divider>
</ng-container>
@ -18,7 +18,7 @@
</ng-container> -->
</mat-nav-list>
<div *ngFor="let chat of chatService.chats3">{{ chat.pubkey }} : {{ chat.content }}</div>
<!-- <div *ngFor="let chat of chatService.chats3">{{ chat.pubkey }} : {{ chat.content }}</div> -->
<!-- <div *ngIf="chatService.uniqueChats$ | async as chats">
<div *ngFor="let chat of chats">{{ chat.pubkey }} : {{ chat.content }}</div>
@ -28,8 +28,8 @@
<div *ngFor="let chat of chats">{{ chat.id }} : {{ chat.name }}</div>
</div> -->
<button (click)="add()">Add</button>
<!-- <button (click)="add()">Add</button>
<button (click)="reset()">Reset</button>
<button (click)="chatService.download()">Download</button>
<button (click)="chatService.download()">Download</button> -->

View File

@ -1,6 +1,9 @@
import { Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core';
import { Kind } from 'nostr-tools';
import { from, Observable, of } from 'rxjs';
import { ChatService } from 'src/app/services/chat.service';
import { RelayService } from 'src/app/services/relay';
import { UIService } from 'src/app/services/ui';
interface ChatModel {
id: string;
@ -15,15 +18,21 @@ interface ChatModel {
export class ChatListComponent implements OnInit {
@Output() openChatSidebar: EventEmitter<string> = new EventEmitter();
constructor(public chatService: ChatService) {}
constructor(public chatService: ChatService, public ui: UIService, private relayService: RelayService) {}
ngOnInit() {
// this.chatService.download();
// this.chatService.uniqueChats$.subscribe((data) => {
// console.log('YEEH!', data);
// });
}
ngOnDestroy() {
}
add() {
// this.#chats.unshift({ id: '123', name: 'Yes!' });
}

View File

@ -1,10 +1,11 @@
<div class="bubble" [class.me]="message.id==0">
<div class="bubble" [class.me]="message.pubkey == me">
<div class="bubble cover">
<img class="bubble picture" [src]="message.cover" alt="">
<!-- <img class="bubble picture" [src]="message.cover" alt="" /> -->
<app-profile-image class="bubble picture" [publicKey]="message.pubkey"></app-profile-image>
</div>
<div class="bubble container">
<mat-card class="bubble card">
{{message.message}}
{{ message.content }}
</mat-card>
</div>
</div>

View File

@ -1,13 +1,20 @@
import { Component, Input } from '@angular/core';
import { MessageModel } from 'src/app/services/interfaces';
import { ApplicationState } from 'src/app/services/applicationstate';
import { NostrEvent } from 'src/app/services/interfaces';
@Component({
selector: 'app-message-bubble',
templateUrl: './message-bubble.component.html',
styleUrls: ['./message-bubble.component.scss']
styleUrls: ['./message-bubble.component.scss'],
})
export class MessageBubbleComponent {
@Input() message!: MessageModel;
@Input() message!: NostrEvent;
@Input() cover!: string;
me?: string;
constructor(private appState: ApplicationState) {}
ngOnInit() {
this.me = this.appState.getPublicKey();
}
}