From cf6fe3a4c8776d92b5d01c6eac3753d6a2e0456f Mon Sep 17 00:00:00 2001 From: Peter Maquiran Date: Wed, 17 Jul 2024 16:39:18 +0100 Subject: [PATCH] receive user typing --- src/app/app.module.ts | 5 +- src/app/module/chat/chat-service.service.ts | 4 +- .../async/socket/message-async.service.ts | 1 - .../data/async/socket/room-async.service.ts | 36 ++++++++++ .../async/socket/user-typing-async.service.ts | 53 ++++++++++++++ .../room/rooom-local-data-source.service.ts | 26 +++++++ .../user-typing-live-data-source.service.ts | 18 +++++ .../user-typing-local-data-source.service.ts | 63 +++++++++++++++++ .../user-typing-memory-data-source.service.ts | 70 +++++++++++++++++++ .../repository/message-respository.service.ts | 7 ++ .../repository/room-repository.service.ts | 21 +----- .../user-typing-repository.service.ts | 28 ++++++++ .../chat/infra/socket/signal-r.service.ts | 14 +++- src/app/module/chat/infra/socket/signalR.ts | 46 +++++++++++- .../decorators/validate-schema.decorator.ts | 5 ++ .../shared/chat/messages/messages.page.html | 29 ++++++++ src/app/shared/chat/messages/messages.page.ts | 31 ++++++-- 17 files changed, 424 insertions(+), 33 deletions(-) create mode 100644 src/app/module/chat/data/async/socket/room-async.service.ts create mode 100644 src/app/module/chat/data/async/socket/user-typing-async.service.ts create mode 100644 src/app/module/chat/data/data-source/userTyping/user-typing-live-data-source.service.ts create mode 100644 src/app/module/chat/data/data-source/userTyping/user-typing-local-data-source.service.ts create mode 100644 src/app/module/chat/data/data-source/userTyping/user-typing-memory-data-source.service.ts create mode 100644 src/app/module/chat/data/repository/user-typing-repository.service.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4f5f11b2f..2eddd8002 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -96,6 +96,7 @@ import { DeplomaOptionsPageModule } from './shared/popover/deploma-options/deplo import { DiplomaOptionsPage } from './shared/popover/deploma-options/deploma-options.page'; import { ImageCropperModule } from 'ngx-image-cropper'; import { createAction, createReducer, on, StoreModule } from '@ngrx/store'; +import { typingReducer } from './module/chat/data/data-source/userTyping/user-typing-memory-data-source.service'; // import { ServiceWorkerModule } from '@angular/service-worker'; // import { AngularFireModule } from '@angular/fire'; // import { AngularFireMessagingModule } from '@angular/fire/messaging'; @@ -143,7 +144,9 @@ export function counterReducer(state, action) { @NgModule({ declarations: [AppComponent, PopupQuestionPipe, InputFilterDirective], - imports: [BrowserModule, + imports: [ + StoreModule.forRoot({ userTyping: typingReducer }), + BrowserModule, CommonModule, FormsModule, CalendarModule.forRoot({ diff --git a/src/app/module/chat/chat-service.service.ts b/src/app/module/chat/chat-service.service.ts index 0b6320988..60c87b303 100644 --- a/src/app/module/chat/chat-service.service.ts +++ b/src/app/module/chat/chat-service.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; import { MessageAsyncService } from 'src/app/module/chat/data/async/socket/message-async.service' +import { UserTypingAsyncService } from 'src/app/module/chat/data/async/socket/user-typing-async.service' @Injectable({ providedIn: 'root' @@ -7,6 +8,7 @@ import { MessageAsyncService } from 'src/app/module/chat/data/async/socket/messa export class ChatServiceService { constructor( - private MessageAsyncService: MessageAsyncService + private MessageAsyncService: MessageAsyncService, + private UserTypingAsyncService: UserTypingAsyncService ) { } } diff --git a/src/app/module/chat/data/async/socket/message-async.service.ts b/src/app/module/chat/data/async/socket/message-async.service.ts index 9beafcc35..e4f980bff 100644 --- a/src/app/module/chat/data/async/socket/message-async.service.ts +++ b/src/app/module/chat/data/async/socket/message-async.service.ts @@ -5,7 +5,6 @@ import { MessageRemoteDataSourceService } from '../../data-source/message/messag import { SignalRService } from '../../../infra/socket/signal-r.service'; import { filter } from 'rxjs/operators'; import { InstanceId } from '../../repository/message-respository.service'; -import { SocketStreamReturn } from 'src/app/services/decorators/socket-validate-schema.decorator'; import { SafeValidateSchema } from 'src/app/services/decorators/validate-schema.decorator'; @Injectable({ diff --git a/src/app/module/chat/data/async/socket/room-async.service.ts b/src/app/module/chat/data/async/socket/room-async.service.ts new file mode 100644 index 000000000..ce637ff6e --- /dev/null +++ b/src/app/module/chat/data/async/socket/room-async.service.ts @@ -0,0 +1,36 @@ +import { Injectable } from '@angular/core'; +import { MessageLiveDataSourceService } from '../../data-source/message/message-live-data-source.service'; +import { RoomLiveDataSourceService } from '../../data-source/room/room-live-data-source.service'; +import { RoomRemoteDataSourceService } from '../../data-source/room/room-remote-data-source.service'; +import { roomDataSource, RoomLocalDataSourceService } from '../../data-source/room/rooom-local-data-source.service'; + +@Injectable({ + providedIn: 'root' +}) +export class RoomAsyncService { + + constructor( + private roomRemoteDataSourceService: RoomRemoteDataSourceService, + // private roomMemoryDataSourceService: Store, + private roomLocalDataSourceService: RoomLocalDataSourceService, + private roomLiveDataSourceService: RoomLiveDataSourceService, + private messageLiveDataSourceService: MessageLiveDataSourceService, + ) { + + + roomDataSource.typing.hook('creating', (primKey, obj, trans) => { + setTimeout(() => { + + }, 1000); + }) + } + + + incomingTyping() { + + } + + async removeUserTyping() { + const result = await this.roomLocalDataSourceService.removeUserTyping() + } +} diff --git a/src/app/module/chat/data/async/socket/user-typing-async.service.ts b/src/app/module/chat/data/async/socket/user-typing-async.service.ts new file mode 100644 index 000000000..e8ea6889d --- /dev/null +++ b/src/app/module/chat/data/async/socket/user-typing-async.service.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@angular/core'; +import { UserTypingLiveDataSourceService } from '../../data-source/userTyping/user-typing-live-data-source.service'; +import { UserTypingLocalDataSourceService } from '../../data-source/userTyping/user-typing-local-data-source.service'; +import { SignalRService } from '../../../infra/socket/signal-r.service'; +import { interval, Subject, timer } from 'rxjs'; +import { switchMap } from 'rxjs/operators'; +import { addUserTyping, removeUserTyping, TypingState } from '../../data-source/userTyping/user-typing-memory-data-source.service'; +import { Store } from '@ngrx/store'; + +@Injectable({ + providedIn: 'root' +}) +export class UserTypingAsyncService { + + typingCallback: {[key: string]: Subject } = {} + + constructor( + private localDataSource: UserTypingLocalDataSourceService, + private liveDataSource: UserTypingLiveDataSourceService, + private memoryDataSource: Store, + private signalR: SignalRService, + ) { + + this.signalR.getTyping().subscribe(async (e:any) => { + if(e?.chatRoomId) { + + console.log('e', e) + + this.memoryDataSource.dispatch(removeUserTyping({data: {...e} as any})) + this.memoryDataSource.dispatch(addUserTyping({data: {...e} as any})) + // + const value = await this.localDataSource.addUserTyping(e); + + const id = e.chatRoomId + '@' + e.userName + if(!this.typingCallback[id]) { + this.typingCallback[id] = new Subject() + this.typingCallback[id].pipe( + switchMap(() => timer(2000)), + ).subscribe(() => { + console.log('111111==============') + this.memoryDataSource.dispatch(removeUserTyping({data: {...e} as any})) + this.localDataSource.removeUserTyping(e) + }) + } else { + this.typingCallback[id].next() + } + + } else { + console.log('e--', e) + } + }) + } +} diff --git a/src/app/module/chat/data/data-source/room/rooom-local-data-source.service.ts b/src/app/module/chat/data/data-source/room/rooom-local-data-source.service.ts index 3909582de..b0db889f5 100644 --- a/src/app/module/chat/data/data-source/room/rooom-local-data-source.service.ts +++ b/src/app/module/chat/data/data-source/room/rooom-local-data-source.service.ts @@ -40,18 +40,30 @@ const TableMemberListSchema = z.object({ joinAt: z.string() }) + +export const TypingSchema = z.object({ + id: z.string().optional(), + userId: z.string(), + roomId: z.string(), + entryDate: z.string() +}) + + export type TableRoom = z.infer export type TableMemberList = z.infer +export type TypingList = z.infer // Database declaration (move this to its own module also) export const roomDataSource = new Dexie('FriendDatabase') as Dexie & { room: EntityTable; memberList: EntityTable; + typing: EntityTable; }; roomDataSource.version(1).stores({ room: 'id, createdBy, roomName, roomType, expirationDate, lastMessage', memberList: '$roomIdUserId, id, user, joinAt, roomId', + TypingList: '++id, userId, roomId, entryDate' }); @Injectable({ @@ -63,6 +75,20 @@ export class RoomLocalDataSourceService { constructor() {} + @ValidateSchema(TypingSchema) + async addUserTyping(data: any) { + try { + const result = await roomDataSource.typing.add(data) + return ok(result) + } catch (e) { + return err(false) + } + } + + async removeUserTyping() { + + } + @ValidateSchema(tableSchema) async createRoom(data: TableRoom) { try { diff --git a/src/app/module/chat/data/data-source/userTyping/user-typing-live-data-source.service.ts b/src/app/module/chat/data/data-source/userTyping/user-typing-live-data-source.service.ts new file mode 100644 index 000000000..cd4686f48 --- /dev/null +++ b/src/app/module/chat/data/data-source/userTyping/user-typing-live-data-source.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@angular/core'; +import { SignalRService } from '../../../infra/socket/signal-r.service'; +import { SessionStore } from 'src/app/store/session.service'; + +@Injectable({ + providedIn: 'root' +}) +export class UserTypingLiveDataSourceService { + + constructor( + private SignalRLiveDataSourceService: SignalRService + ) { } + + sendTyping(ChatRoomId) { + return this.SignalRLiveDataSourceService.sendTyping({ChatRoomId, UserName:SessionStore.user.FullName}) + } + +} diff --git a/src/app/module/chat/data/data-source/userTyping/user-typing-local-data-source.service.ts b/src/app/module/chat/data/data-source/userTyping/user-typing-local-data-source.service.ts new file mode 100644 index 000000000..05429dcae --- /dev/null +++ b/src/app/module/chat/data/data-source/userTyping/user-typing-local-data-source.service.ts @@ -0,0 +1,63 @@ +import { Injectable } from '@angular/core'; +import { z } from 'zod'; +import { Dexie, EntityTable, liveQuery, Observable } from 'Dexie'; +import { err, ok } from 'neverthrow'; + +export const TypingSchema = z.object({ + id: z.string().optional(), + userId: z.string().optional(), + userName: z.string(), + chatRoomId: z.string(), + entryDate: z.string() +}) + +export type TypingList = z.infer + +export type UserTypingList = z.infer + + +// Database declaration (move this to its own module also) +export const TypingDataSource = new Dexie('UserTyping') as Dexie & { + TypingList: EntityTable; +} + + +TypingDataSource.version(1).stores({ + TypingList: 'id, userId, userName, chatRoomId, entryDate' +}); + +@Injectable({ + providedIn: 'root' +}) +export class UserTypingLocalDataSourceService { + + constructor() { } + + + async addUserTyping(data: TypingList) { + data.id = data.chatRoomId + '@' + data.userName + try { + const result = await TypingDataSource.TypingList.add(data) + return ok(result) + } catch (e) { + return err(false) + } + } + + async removeUserTyping(data: TypingList) { + + const id = data.chatRoomId + '@' + data.userName + try { + const result = await TypingDataSource.TypingList.delete(id) + return ok(result) + } catch (e) { + return err(false) + } + } + + + getUserTypingLive() { + return liveQuery(() => TypingDataSource.TypingList.toArray()); + } + +} diff --git a/src/app/module/chat/data/data-source/userTyping/user-typing-memory-data-source.service.ts b/src/app/module/chat/data/data-source/userTyping/user-typing-memory-data-source.service.ts new file mode 100644 index 000000000..d3a1ca867 --- /dev/null +++ b/src/app/module/chat/data/data-source/userTyping/user-typing-memory-data-source.service.ts @@ -0,0 +1,70 @@ +import { createAction, createFeatureSelector, createReducer, createSelector, on, props } from '@ngrx/store'; +import { TypingList } from './user-typing-local-data-source.service'; + + +export const addUserTyping = createAction( + '[Typing] Add User Typing', + props<{ data: TypingList }>() +); + +export const removeUserTyping = createAction( + '[Typing] Remove User Typing', + props<{ data: TypingList }>() +); + +export const loadUserTyping = createAction('[Typing] Load User Typing'); + +export const loadUserTypingSuccess = createAction( + '[Typing] Load User Typing Success', + props<{ data: TypingList[] }>() +); + +export const loadUserTypingFailure = createAction( + '[Typing] Load User Typing Failure', + props<{ error: any }>() +); + + +export interface TypingState { + typingList: TypingList[]; + error: any; +} + +export const initialState: TypingState = { + typingList: [], + error: null +}; + +export const typingReducer = createReducer( + initialState, + on(loadUserTypingSuccess, (state, { data }) => ({ + ...state, + typingList: data + })), + on(loadUserTypingFailure, (state, { error }) => ({ + ...state, + error + })), + on(addUserTyping, (state, { data }) => ({ + ...state, + typingList: [...state.typingList, data] + })), + on(removeUserTyping, (state, { data }) => ({ + ...state, + typingList: state.typingList.filter( + typing => typing.chatRoomId !== data.chatRoomId || typing.userName !== data.userName + ) + })) +); + +export const selectCalendarState = createFeatureSelector('userTyping'); + +export const selectAllUserSource = createSelector( + selectCalendarState, + (state: TypingState) => state.typingList +); + +export const selectUserTypingList = () => createSelector( + selectAllUserSource, + (typingList) => typingList +); diff --git a/src/app/module/chat/data/repository/message-respository.service.ts b/src/app/module/chat/data/repository/message-respository.service.ts index 22d76c5f5..e4839d169 100644 --- a/src/app/module/chat/data/repository/message-respository.service.ts +++ b/src/app/module/chat/data/repository/message-respository.service.ts @@ -50,6 +50,9 @@ export class MessageRepositoryService { if(localActionResult.isOk()) { + (await this.sendTyping(data.roomId)).map((e) => { + console.log('map', e) + }) const sendMessageResult = await this.messageLiveSignalRDataSourceService.sendMessage(data) @@ -101,4 +104,8 @@ export class MessageRepositoryService { subscribeToNewMessages(roomId: any) { return this.messageLocalDataSourceService.subscribeToNewMessage(roomId) } + + sendTyping(ChatRoomId) { + return this.messageLiveSignalRDataSourceService.sendTyping({ChatRoomId, UserName:SessionStore.user.FullName}) + } } diff --git a/src/app/module/chat/data/repository/room-repository.service.ts b/src/app/module/chat/data/repository/room-repository.service.ts index ba603b391..891cbdf5e 100644 --- a/src/app/module/chat/data/repository/room-repository.service.ts +++ b/src/app/module/chat/data/repository/room-repository.service.ts @@ -42,26 +42,7 @@ export class RoomRepositoryService { private roomLocalDataSourceService: RoomLocalDataSourceService, private roomLiveDataSourceService: RoomLiveDataSourceService, private messageLiveDataSourceService: MessageLiveDataSourceService, - ) { - - // this.messageLiveDataSourceService.socket.messages$.subscribe(({payload, requestId, type}) => { - // if(payload.sender == null) { - // delete payload.sender - // } - - // if(type == 'sendMessage') { - // let clone: TableMessage = { - // ...payload, - // messageId: payload.id, - // } - - // this.roomLocalDataSourceService.updateRoom({lastMessage: clone}) - - // } - - // }) - - } + ) {} @captureAndReraiseAsync('RoomRepositoryService/list') async list() { diff --git a/src/app/module/chat/data/repository/user-typing-repository.service.ts b/src/app/module/chat/data/repository/user-typing-repository.service.ts new file mode 100644 index 000000000..f31378900 --- /dev/null +++ b/src/app/module/chat/data/repository/user-typing-repository.service.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@angular/core'; +import { TypingList, UserTypingLocalDataSourceService } from '../data-source/userTyping/user-typing-local-data-source.service'; +import { UserTypingLiveDataSourceService } from '../data-source/userTyping/user-typing-live-data-source.service'; +import { SessionStore } from 'src/app/store/session.service'; + +@Injectable({ + providedIn: 'root' +}) +export class UserTypingServiceRepository { + + constructor( + private localDataSource: UserTypingLocalDataSourceService, + private liveDataSource: UserTypingLiveDataSourceService + ) { } + + async addUserTyping(ChatRoomId: any) { + return await this.liveDataSource.sendTyping(ChatRoomId) + } + + async removeUserTyping(data: TypingList) { + return await this.localDataSource.removeUserTyping(data) + } + + + getUserTypingLive() { + return this.localDataSource.getUserTypingLive() + } +} diff --git a/src/app/module/chat/infra/socket/signal-r.service.ts b/src/app/module/chat/infra/socket/signal-r.service.ts index 39d6964bd..260a8ef20 100644 --- a/src/app/module/chat/infra/socket/signal-r.service.ts +++ b/src/app/module/chat/infra/socket/signal-r.service.ts @@ -13,10 +13,11 @@ const { App } = Plugins; export class SignalRService { private connection: SignalRConnection; private messageSubject: BehaviorSubject = new BehaviorSubject(null); + private typingSubject: BehaviorSubject = new BehaviorSubject(null); private connectingSubject: BehaviorSubject = new BehaviorSubject(null); constructor( - private platform: Platform,) { + private platform: Platform) { // this.startConnection(); // this.addMessageListener(); @@ -58,6 +59,9 @@ export class SignalRService { this.connection.getMessages().subscribe((data) => { this.messageSubject.next(data) }) + this.connection.getTyping().subscribe((data) => { + this.typingSubject.next(data) + }) } } @@ -68,6 +72,10 @@ export class SignalRService { } + getTyping() { + return this.typingSubject.asObservable() + } + async sendMessage(data: Object) { return await this.connection.sendMessage(data as any) } @@ -75,4 +83,8 @@ export class SignalRService { newConnection() { this.establishConnection() } + + async sendTyping({ChatRoomId, UserName}) { + return await this.connection.typing({ ChatRoomId, UserName}) + } } diff --git a/src/app/module/chat/infra/socket/signalR.ts b/src/app/module/chat/infra/socket/signalR.ts index 51ae59344..697596992 100644 --- a/src/app/module/chat/infra/socket/signalR.ts +++ b/src/app/module/chat/infra/socket/signalR.ts @@ -3,11 +3,12 @@ import { BehaviorSubject, Observable } from 'rxjs'; import { ok, Result, err } from 'neverthrow'; import { SessionStore } from 'src/app/store/session.service'; import { filter, first } from 'rxjs/operators'; - +import { v4 as uuidv4 } from 'uuid' export class SignalRConnection { private hubConnection: signalR.HubConnection; private messageSubject: BehaviorSubject = new BehaviorSubject(null); + private typingSubject: BehaviorSubject = new BehaviorSubject(null); private connectionStateSubject: BehaviorSubject = new BehaviorSubject(false); private disconnectSubject: BehaviorSubject = new BehaviorSubject(false); private reconnectSubject: BehaviorSubject = new BehaviorSubject(false); @@ -27,7 +28,6 @@ export class SignalRConnection { .build(); this.hubConnection = hubConnection - this.join() hubConnection .start() @@ -70,7 +70,9 @@ export class SignalRConnection { public join() { if(this.connectionStateSubject.value == true) { console.log('join=============') - this.hubConnection.invoke("Join", 105, "UserFirefox"); + + this.hubConnection.invoke("Join", SessionStore.user.UserId, SessionStore.user.FullName); + //this.hubConnection.invoke("Join", 105, "UserFirefox"); } else { this.sendLaterSubject.next({method: 'SendMessage', args:["Join", 312, "Daniel"]}) } @@ -101,17 +103,55 @@ export class SignalRConnection { }) } + public async typing(data: Object & { ChatRoomId, UserName}):Promise> { + return new Promise((resolve, reject) => { + + const requestId = uuidv4() + if(this.connectionStateSubject.value == true) { + + try { + this.hubConnection.invoke("Typing", {UserName: data.UserName, ChatRoomId: data.ChatRoomId, requestId} as any) + + } catch (error) {} + + this.typingSubject.pipe( + filter((message: any) => { + return requestId == message?.requestId + }), + first() + ).subscribe(value => { + resolve(ok(value)); + }); + + } else { + this.sendLaterSubject.next({method: 'SendMessage', args: data}) + return reject(err(false)) + } + + + }) + } + private addMessageListener(): void { this.hubConnection.on('ReceiveMessage', (message) => { console.log('ReceiveMessage', message) this.messageSubject.next(message); }); + + this.hubConnection.on('Typing', (_message) => { + console.log('_message', _message) + this.typingSubject.next(_message); + }); } public getMessages(): Observable { return this.messageSubject.asObservable() } + public getTyping(): Observable { + return this.typingSubject.asObservable() + } + public getConnectionState(): Observable { return this.connectionStateSubject.asObservable(); } diff --git a/src/app/services/decorators/validate-schema.decorator.ts b/src/app/services/decorators/validate-schema.decorator.ts index b53f760e4..65cd3c12f 100644 --- a/src/app/services/decorators/validate-schema.decorator.ts +++ b/src/app/services/decorators/validate-schema.decorator.ts @@ -28,6 +28,11 @@ export function ValidateSchema(schema: Schema) { }; } +/** + * + * @param schema Zod Schema + * @param context + */ export function SafeValidateSchema(schema: Schema, context: string) { return ( target: unknown, diff --git a/src/app/shared/chat/messages/messages.page.html b/src/app/shared/chat/messages/messages.page.html index c5f8ac3d9..bd47c37b3 100644 --- a/src/app/shared/chat/messages/messages.page.html +++ b/src/app/shared/chat/messages/messages.page.html @@ -28,6 +28,7 @@ + @@ -56,6 +57,34 @@ + + + + +
+ +
+
+ + + + + + diff --git a/src/app/shared/chat/messages/messages.page.ts b/src/app/shared/chat/messages/messages.page.ts index 74aa78ba4..54736a8e1 100644 --- a/src/app/shared/chat/messages/messages.page.ts +++ b/src/app/shared/chat/messages/messages.page.ts @@ -1,6 +1,5 @@ import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core'; import { AnimationController, GestureController, IonRange, ModalController, PopoverController } from '@ionic/angular'; -import { ChatService } from 'src/app/services/chat.service'; import { ToastService } from 'src/app/services/toast.service'; import { ChatOptionsPopoverPage } from 'src/app/shared/popover/chat-options-popover/chat-options-popover.page'; import { MessagesOptionsPage } from 'src/app/shared/popover/messages-options/messages-options.page'; @@ -16,7 +15,6 @@ import { ViewEventPage } from 'src/app/modals/view-event/view-event.page'; import { Storage } from '@ionic/storage'; import { RochetChatConnectorService } from 'src/app/services/chat/rochet-chat-connector.service' import { MessageService } from 'src/app/services/chat/message.service'; -import { CameraService } from 'src/app/services/camera.service'; import { FileType } from 'src/app/models/fileType'; import { SearchPage } from 'src/app/pages/search/search.page'; import { Camera, CameraResultType, CameraSource } from '@capacitor/camera'; @@ -42,6 +40,8 @@ import { TableMessage } from 'src/app/module/chat/data/data-source/message/messa import { TableMemberList } from 'src/app/module/chat/data/data-source/room/rooom-local-data-source.service'; import { MessageInputDTO } from 'src/app/module/chat/data/dto/message/messageInputDtO'; import { RoomListItemOutPutDTO } from 'src/app/module/chat/data/dto/room/roomListOutputDTO'; +import { UserTypingServiceRepository } from 'src/app/module/chat/data/repository/user-typing-repository.service'; +import { UserTypingList } from 'src/app/module/chat/data/data-source/userTyping/user-typing-local-data-source.service'; const IMAGE_DIR = 'stored-images'; @@ -109,6 +109,8 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy audioDuration = 0; audioTimer: any; @ViewChild('range', { static: false }) range: IonRange; + @ViewChild('array') myInputRef!: ElementRef; + userName = ""; room: any = new Array(); roomName: any; @@ -120,7 +122,8 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy roomData$: DexieObservable roomMessage$: DexieObservable roomMembers$: DexieObservable - + //userTyping$: DexieObservable + userTyping$: UserTypingList[] | undefined newMessagesStream!: Subscription constructor( @@ -135,7 +138,6 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy public ThemeService: ThemeService, private storage: Storage, public RochetChatConnectorService: RochetChatConnectorService, - private CameraService: CameraService, private sanitiser: DomSanitizer, private file: File, private platform: Platform, @@ -143,7 +145,8 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy public p: PermissionService, private FileValidatorService: FileValidatorService, private roomRepositoryService: RoomRepositoryService, - private messageRepositoryService: MessageRepositoryService + private messageRepositoryService: MessageRepositoryService, + private userTypingServiceRepository: UserTypingServiceRepository, ) { // update this.checkAudioPermission() @@ -156,6 +159,15 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy this.roomRepositoryService.getRoomById(this.roomId) this.messageRepositoryService.listAllMessagesByRoomId(this.roomId) + this.userTypingServiceRepository.getUserTypingLive().subscribe((e) => { + const arrayNames = e.map(e => e.userName) + this.userTyping$ = e as any + + const uniqueArray = [...new Set(arrayNames)]; + + (this.myInputRef.nativeElement as HTMLDivElement).innerHTML = '::'+ uniqueArray + this.scrollToBottomClicked() + }) this.newMessagesStream?.unsubscribe() this.newMessagesStream = this.messageRepositoryService.subscribeToNewMessages(this.roomId).subscribe((e) => { @@ -169,9 +181,16 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy }) + //this.userTyping$ = this.userTypingMemoryDataSource.select(state => state) as any + + // let a = this.userTypingMemoryDataSource.select(state => state).subscribe((e) => { + // this.userTyping$ = e as any + // }) } - sendTyping() {} + sendTyping() { + this.userTypingServiceRepository.addUserTyping(this.roomId) + } async ChatMessageDebuggingPage() {