diff --git a/package-lock.json b/package-lock.json index fddbd70..c18ceb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2086,6 +2086,12 @@ "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", "dev": true }, + "@types/matrix-js-sdk": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@types/matrix-js-sdk/-/matrix-js-sdk-9.2.1.tgz", + "integrity": "sha512-RgNJ5ffGdt0bXyxQpbDXtuyAp/kH205Pgv/RZCoI29jbQXOScY6HlKxi6HJAlW5vexaYlCzGu+70tYqK0sxraQ==", + "dev": true + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", diff --git a/package.json b/package.json index b770f68..4c848df 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "@angular/compiler-cli": "~11.2.6", "@types/jasmine": "~3.5.0", "@types/jasminewd2": "~2.0.3", + "@types/matrix-js-sdk": "^9.2.1", "@types/node": "^12.20.6", "codelyzer": "^6.0.0", "jasmine-core": "~3.6.0", diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 3d252b9..df278b0 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -7,6 +7,10 @@ import { NgxMatDatetimePickerModule } from '@angular-material-components/datetim import { AppComponent } from './app.component'; import { MaterialModule } from './material/material.module'; +import { MatGridListModule } from '@angular/material/grid-list'; +import { MatDatepickerModule } from '@angular/material/datepicker'; +import {MatListModule} from '@angular/material/list'; +import { NgxMatMomentModule } from '@angular-material-components/moment-adapter'; import { HomeComponent } from './pages/home/home.component'; import { TravelComponent } from './pages/travel/travel.component'; @@ -16,11 +20,10 @@ import { HeaderComponent } from './views/header/header.component'; import { ListComponent } from './views/list/list.component'; import { TravelFormComponent } from './views/travel-form/travel-form.component'; import { NewTravelComponent } from './pages/new-travel/new-travel.component'; -import { MatDatepickerModule } from '@angular/material/datepicker'; -import { NgxMatMomentModule } from '@angular-material-components/moment-adapter'; import { AppRouterModule } from './router.module'; import { AvailablePlacesPipe } from './pipes/available-places.pipe'; import { AuthConfigModule } from './auth/auth-config.module'; +import { ChatComponent } from './views/chat/chat.component'; @NgModule({ imports: [ @@ -31,6 +34,8 @@ import { AuthConfigModule } from './auth/auth-config.module'; BrowserAnimationsModule, AppRouterModule, MaterialModule, + MatListModule, + MatGridListModule, MatDatepickerModule, NgxMatDatetimePickerModule, NgxMatMomentModule, @@ -45,7 +50,8 @@ import { AuthConfigModule } from './auth/auth-config.module'; ListComponent, TravelFormComponent, NewTravelComponent, - AvailablePlacesPipe + AvailablePlacesPipe, + ChatComponent ], providers: [ // (useHash) ? { provide: LocationStrategy, useClass: HashLocationStrategy } : [], diff --git a/src/app/entities/matrix-login-dto.ts b/src/app/entities/matrix-login-dto.ts new file mode 100644 index 0000000..28d9ccd --- /dev/null +++ b/src/app/entities/matrix-login-dto.ts @@ -0,0 +1,4 @@ +export interface MatrixLoginDto { + access_token: string; + user_id: string; +} diff --git a/src/app/pages/travel/travel.component.html b/src/app/pages/travel/travel.component.html index 01c4ced..b62d506 100644 --- a/src/app/pages/travel/travel.component.html +++ b/src/app/pages/travel/travel.component.html @@ -16,6 +16,13 @@ + + Chat + + + + + Back Join Leave diff --git a/src/app/pages/travel/travel.component.ts b/src/app/pages/travel/travel.component.ts index d18cecb..5f72cd9 100644 --- a/src/app/pages/travel/travel.component.ts +++ b/src/app/pages/travel/travel.component.ts @@ -82,16 +82,6 @@ export class TravelComponent implements OnInit { .subscribe(res => { if (res.success) { this.travel = Object.assign( new Travel(), res.data ); - console.log({travel: this.travel}); - - this.chatService.getRoomMessages(this.travel.matrixRoomId); - - this.chatService.listemRoomMessages(this.travel.matrixRoomId, (event: any) => { - console.log( - // the room name will update with m.room.name events automatically - "%s: %s", event.getSender(), event.getContent().body - ); - }); } else { console.error('Error getting travel ' + this.travelId + ': ' + res.error); diff --git a/src/app/services/chat.service.ts b/src/app/services/chat.service.ts index 1a38d2a..021a75c 100644 --- a/src/app/services/chat.service.ts +++ b/src/app/services/chat.service.ts @@ -3,6 +3,11 @@ import { Injectable } from '@angular/core'; import * as olm from 'olm'; global.Olm = olm; import * as matrix from 'matrix-js-sdk'; +import { RoomMember } from 'matrix-js-sdk/src/models/room'; +import { Room } from 'matrix-js-sdk/src/models/room'; +import { EventTimeline } from 'matrix-js-sdk/src/models/event-timeline'; +import { MatrixLoginDto } from '../entities/matrix-login-dto'; +import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; @Injectable({ providedIn: 'root' @@ -19,7 +24,7 @@ export class ChatService { } async login(loginToken: string): Promise { - const res = await this.http.post( + const matrixLogin = await this.http.post( 'http://synapse:8008/_matrix/client/r0/login', { initial_device_display_name: 'Okupa mi coche', @@ -28,42 +33,39 @@ export class ChatService { } ).toPromise(); console.log('LOGGED TO CHAT'); - console.log(res); + console.log(matrixLogin); this.client = matrix.createClient({ baseUrl: 'http://localhost:8008', - accessToken: res['access_token'], - userId: res['user_id'] + accessToken: matrixLogin.access_token, + userId: matrixLogin.user_id }); - await this.client.startClient({ initialSyncLimit: 10 }); + await this.client.startClient({ initialSyncLimit: 100 }); - this.client.once('sync', function (state, prevState, res) { + this.client.once('sync', (state: string, prevState: string, _: any) => { if (state === 'PREPARED') { - console.log("CHAT SYNC FINISHED"); + console.log('CHAT SYNC FINISHED'); } else { console.log(state); } }); - - // this.client.publicRooms((err: any, data: any) => { - // console.log('Public Rooms: %s', JSON.stringify(data)); - // }); } - getRoomMessages(roomId: string): void { - const room = this.client?.getRoom(roomId); - const members = room?.getJoinedMembers(); - members?.forEach(member => { - console.log(member); - }); - - room?.timeline.forEach(t => { - console.log(JSON.stringify(t.event)); - }); + getRoomMessages(roomId: string): MatrixEvent[] { + console.log('roomId=' + roomId); + const room: Room = this.client?.getRoom(roomId) as Room; + console.log({room}); + return room?.timeline + .filter((t: MatrixEvent) => (t.getType() === 'm.room.message')); } - listemRoomMessages(roomId: string, handle: (event: any) => void): void { - this.client?.on('Room.timeline', function (event, room, toStartOfTimeline) { + getRoomMembers(roomId: string): RoomMember[] { + const room: Room = this.client?.getRoom(roomId) as Room; + return room?.getJoinedMembers(); + } + + listemRoomMessages(roomId: string, handle: (event: EventTimeline) => void): void { + this.client?.on('Room.timeline', (event: EventTimeline, room: Room, toStartOfTimeline: boolean) => { if (room.roomId !== roomId) { return; // only listen to specified room } diff --git a/src/app/views/chat/chat.component.css b/src/app/views/chat/chat.component.css new file mode 100644 index 0000000..5e48686 --- /dev/null +++ b/src/app/views/chat/chat.component.css @@ -0,0 +1,5 @@ +.chat-messages { + width: 100%; + height: 100%; + overflow-y: scroll; +} diff --git a/src/app/views/chat/chat.component.html b/src/app/views/chat/chat.component.html new file mode 100644 index 0000000..1d1667b --- /dev/null +++ b/src/app/views/chat/chat.component.html @@ -0,0 +1,18 @@ + + + + + {{message.getSender()}} + + {{message.getContent().body}} + + + + + + + + Miembros + + + \ No newline at end of file diff --git a/src/app/views/chat/chat.component.spec.ts b/src/app/views/chat/chat.component.spec.ts new file mode 100644 index 0000000..7d7548c --- /dev/null +++ b/src/app/views/chat/chat.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ChatComponent } from './chat.component'; + +describe('ChatComponent', () => { + let component: ChatComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ChatComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ChatComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/views/chat/chat.component.ts b/src/app/views/chat/chat.component.ts new file mode 100644 index 0000000..5e157e3 --- /dev/null +++ b/src/app/views/chat/chat.component.ts @@ -0,0 +1,41 @@ +import { Component, Input, OnInit, AfterViewInit, ElementRef, ViewChildren } from '@angular/core'; +import { ChatService } from 'src/app/services/chat.service'; + +import { RoomMember } from 'matrix-js-sdk/src/models/room'; +import { Room } from 'matrix-js-sdk/src/models/room'; +import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; +import { QueryList } from '@angular/core'; + +@Component({ + selector: 'app-chat', + templateUrl: './chat.component.html', + styleUrls: ['./chat.component.css'] +}) +export class ChatComponent implements OnInit, AfterViewInit { + @Input() roomId: string; + @ViewChildren('messageItem', { read: ElementRef }) messageItems: QueryList; + messages: MatrixEvent[]; + + constructor(private chatService: ChatService) { } + + ngOnInit(): void { + this.messages = this.chatService.getRoomMessages(this.roomId); + + this.chatService.listemRoomMessages(this.roomId, (event: any) => { + console.log( + // the room name will update with m.room.name events automatically + '%s: %s', event.getSender(), event.getContent().body + ); + }); + } + + ngAfterViewInit(): void { + // Always scroll to last chat message. + this.messageItems?.last.nativeElement?.scrollIntoView(false); + this.messageItems.changes.subscribe((c) => { + console.log({ c }); + this.messageItems?.last.nativeElement?.scrollIntoView(false); + }); + } + +}
+ {{message.getContent().body}} +