Merge branch 'master' into matrix-chat-native
This commit is contained in:
commit
550d79af28
@ -1,36 +1,30 @@
|
||||
<template>
|
||||
<img v-if="mxcURL" :src="thumbnailUrl()" class="userThumbnail image"/>
|
||||
<img v-if="mxcURL" :src="getAvatarUrl(mxcURL)" class="userThumbnail image"/>
|
||||
<div v-else v-html="getJdenticon()" class="userThumbnail identicon"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import parseMXC from '@modular-matrix/parse-mxc';
|
||||
import {matrix} from "@/main";
|
||||
import {toSvg} from 'jdenticon';
|
||||
import {getAvatarUrl} from '@/lib/getMxc';
|
||||
|
||||
export default {
|
||||
name: "userThumbnail.vue",
|
||||
name: 'userThumbnail.vue',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
mxcURL: String,
|
||||
username: String,
|
||||
fallback: String,
|
||||
homeserver: String,
|
||||
size: Number
|
||||
},
|
||||
methods: {
|
||||
thumbnailUrl(){
|
||||
let mxc = parseMXC.parse(this.mxcURL);
|
||||
return `${this.homeserver||matrix.baseUrl}/_matrix/media/v1/thumbnail/${
|
||||
mxc.homeserver}/${mxc.id}?width=${this.imageSize}&height=${this.imageSize}&method=${this.resizeMethod}`;
|
||||
},
|
||||
getFontSize(){
|
||||
return window.getComputedStyle(document.body,null).fontSize.split("px", 1)||16;
|
||||
return window.getComputedStyle(document.body,null).fontSize.split('px', 1)||16;
|
||||
},
|
||||
getJdenticon(){
|
||||
return toSvg(this.fallback, this.getFontSize()*this.size);
|
||||
}
|
||||
},
|
||||
getAvatarUrl
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
|
@ -7,7 +7,7 @@
|
||||
<form v-on:submit.prevent="sendMessage()">
|
||||
<textarea
|
||||
@keyup.enter.exact="sendMessage()"
|
||||
@input="resizeMessageBanner()"
|
||||
@input="resizeMessageBanner(); sendTyping(2000);"
|
||||
v-model="event.content.body"
|
||||
ref="newMessageInput" class="newMessageInput"
|
||||
rows="1" placeholder="type a message ..."
|
||||
@ -50,6 +50,11 @@ export default {
|
||||
id.style.height = '1.25rem';
|
||||
this.onResize(id.parentElement.clientHeight);
|
||||
},
|
||||
sendTyping(timeout){
|
||||
if (this.waitForSendTyping) return;
|
||||
matrix.client.sendTyping(this.roomId, true, timeout+100);
|
||||
setTimeout(()=>this.waitForSendTyping=false, timeout);
|
||||
},
|
||||
resizeMessageBanner(){
|
||||
let id = this.$refs.newMessageInput;
|
||||
id.style.height = '1.25rem';
|
||||
@ -82,7 +87,8 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
showEmojiPicker: false
|
||||
showEmojiPicker: false,
|
||||
waitForSendTyping: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
28
src/lib/NotificationHandler.js
Normal file
28
src/lib/NotificationHandler.js
Normal file
@ -0,0 +1,28 @@
|
||||
import {getMxcFromUserId, getAvatarUrl} from '@/lib/getMxc';
|
||||
import {calcUserName} from '@/lib/matrixUtils';
|
||||
import {getRoom} from '@/lib/matrixUtils';
|
||||
import {router} from '@/router';
|
||||
|
||||
export class NotificationHandler{
|
||||
constructor() {
|
||||
this.activateNotification();
|
||||
}
|
||||
async activateNotification(){
|
||||
if (!window.Notification){
|
||||
console.log('notifications are unsupported')
|
||||
return false;
|
||||
}
|
||||
if (Notification.permission === 'granted') return true;
|
||||
return await Notification.requestPermission()
|
||||
.then(permission => {return permission === 'granted'});
|
||||
}
|
||||
showNotification(event){
|
||||
if (Notification.permission !== 'granted') return false;
|
||||
console.log(event);
|
||||
let mxc = getMxcFromUserId(event.sender);
|
||||
new Notification(`${calcUserName(event.sender)} in ${getRoom(event.room_id).name}`, {
|
||||
body: event.content.body,
|
||||
icon: mxc?getAvatarUrl(mxc):undefined
|
||||
}).onclick = ()=>router.push(`/rooms/${event.room_id}`);
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import sdk from 'matrix-js-sdk'
|
||||
import {matrix} from "@/main";
|
||||
import {matrix} from '@/main';
|
||||
import parseMXC from '@modular-matrix/parse-mxc';
|
||||
|
||||
export function getMxcFromUser(user){
|
||||
return user.avatarUrl;
|
||||
@ -10,10 +11,16 @@ export function getMxcFromUserId(userId){
|
||||
}
|
||||
|
||||
export function getMxcFromRoom(room){
|
||||
let avatarState = room.getLiveTimeline().getState(sdk.EventTimeline.FORWARDS).getStateEvents("m.room.avatar");
|
||||
let avatarState = room.getLiveTimeline().getState(sdk.EventTimeline.FORWARDS).getStateEvents('m.room.avatar');
|
||||
return avatarState.length>0?avatarState[avatarState.length-1].getContent().url:undefined;
|
||||
}
|
||||
|
||||
export function getMxcFromRoomId(roomId){
|
||||
return getMxcFromRoom(matrix.client.getRoom(roomId));
|
||||
}
|
||||
|
||||
export function getAvatarUrl(mxcUrl, size = 64, resizeMethod = 'crop'){
|
||||
let mxc = parseMXC.parse(mxcUrl);
|
||||
return `${matrix.baseUrl}/_matrix/media/v1/thumbnail/${
|
||||
mxc.homeserver}/${mxc.id}?width=${size}&height=${size}&method=${resizeMethod}`;
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import matrix from 'matrix-js-sdk';
|
||||
import {NotificationHandler} from "@/lib/NotificationHandler";
|
||||
|
||||
export class MatrixHandler {
|
||||
constructor(clientDisplayName = 'matrix-chat') {
|
||||
@ -9,6 +10,7 @@ export class MatrixHandler {
|
||||
this.loading = undefined;
|
||||
this.user = undefined;
|
||||
this.baseUrl = undefined;
|
||||
this.notify = new NotificationHandler();
|
||||
}
|
||||
login(user, password, baseUrl, onError, callback = ()=>{}){
|
||||
if (this.client){ console.log('there is already an active session'); return; }
|
||||
@ -57,15 +59,22 @@ export class MatrixHandler {
|
||||
await this.client.stopClient();
|
||||
this.client = undefined;
|
||||
}
|
||||
startSync(callback = ()=>{}){
|
||||
async startSync(callback = ()=>{}){
|
||||
this.loading = true;
|
||||
this.client.startClient();
|
||||
await this.client.startClient();
|
||||
this.client.once('sync', (state) => {
|
||||
console.log(state);
|
||||
this.rooms = this.client.getRooms();
|
||||
console.log(this.rooms)
|
||||
this.loading = false;
|
||||
callback();
|
||||
this.listenToPushEvents()
|
||||
});
|
||||
}
|
||||
listenToPushEvents(){
|
||||
this.client.on('event', event => {
|
||||
if (this.client.getPushActionsForEvent(event).notify){
|
||||
this.notify.showNotification(event.event);
|
||||
}
|
||||
});
|
||||
}
|
||||
async sendEvent({content, type}, roomId, replyTo = undefined){
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
import App from './App.vue'
|
||||
import {router} from './router.js'
|
||||
import {router} from '@/router'
|
||||
import {MatrixHandler} from './lib/matrixHandler.js'
|
||||
import {cookieHandler} from './lib/cookieHandler.js';
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
import VueRouter from 'vue-router';
|
||||
import login from '@/views/login';
|
||||
import chat from '@/views/chat';
|
||||
import rooms from '@/views/rooms';
|
||||
import admin from '@/views/admin';
|
||||
|
||||
export const router = new VueRouter({
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: login
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: login
|
||||
},
|
||||
{
|
||||
path: '/chat/*',
|
||||
name: 'chat',
|
||||
component: chat
|
||||
},
|
||||
{
|
||||
path: '/rooms/*',
|
||||
name: 'room',
|
||||
component: rooms
|
||||
},
|
||||
{
|
||||
path: '/rooms',
|
||||
name: 'rooms',
|
||||
component: rooms
|
||||
},
|
||||
{
|
||||
path: '/admin',
|
||||
name: 'admin',
|
||||
component: admin
|
||||
}
|
||||
]
|
||||
})
|
@ -0,0 +1,40 @@
|
||||
import VueRouter from 'vue-router';
|
||||
import login from '@/views/login';
|
||||
import chat from '@/views/chat';
|
||||
import rooms from '@/views/rooms';
|
||||
import admin from '@/views/admin';
|
||||
|
||||
export const router = new VueRouter({
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: login
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: login
|
||||
},
|
||||
{
|
||||
path: '/chat/*',
|
||||
name: 'chat',
|
||||
component: chat
|
||||
},
|
||||
{
|
||||
path: '/rooms/*',
|
||||
name: 'room',
|
||||
component: rooms
|
||||
},
|
||||
{
|
||||
path: '/rooms',
|
||||
name: 'rooms',
|
||||
component: rooms
|
||||
},
|
||||
{
|
||||
path: '/admin',
|
||||
name: 'admin',
|
||||
component: admin
|
||||
}
|
||||
]
|
||||
})
|
@ -45,8 +45,8 @@ export default {
|
||||
},
|
||||
methods:{
|
||||
onScroll(){
|
||||
if (this.$refs.timelineContainer.scrollTop === 0) this.loadEvents();
|
||||
this.showScrollBtn = this.scroll.getScrollBottom() > 400;
|
||||
if (this.$refs.timelineContainer.scrollTop < 400 && this.loadingStatus !== 'loading') this.loadEvents();
|
||||
this.showScrollBtn = this.scroll.getScrollBottom() > 500;
|
||||
},
|
||||
resize(height = this.$refs.newMessage.clientHeight){
|
||||
this.$refs.chatContainer.style.height = `calc(100% - ${height}px - 3.5rem)`;
|
||||
@ -56,10 +56,10 @@ export default {
|
||||
},
|
||||
async loadEvents(){
|
||||
let scrollBottom = this.scroll.getScrollBottom();
|
||||
this.loadingStatus = 'loading ...';
|
||||
await matrix.client.paginateEventTimeline(this.room.getLiveTimeline(), {backwards: true})
|
||||
.then(state => this.loadingStatus = state?'load more':false);
|
||||
if (this.loadingStatus) this.scroll.setScrollBottom(scrollBottom);
|
||||
this.loadingStatus = 'loading';
|
||||
await matrix.client.scrollback(this.room, 30);
|
||||
this.loadingStatus = 'load more';
|
||||
this.scroll.setScrollBottom(scrollBottom)
|
||||
},
|
||||
getUser(userId){
|
||||
return matrix.client.getUser(userId);
|
||||
@ -76,11 +76,12 @@ export default {
|
||||
}
|
||||
},
|
||||
updated(){
|
||||
if(this.scroll.getScrollBottom() < 350) this.scroll.scrollToBottom();
|
||||
if(this.scroll.getScrollBottom() < 400 && this.loadingStatus !== 'loading') this.scroll.scrollToBottom();
|
||||
},
|
||||
mounted(){
|
||||
this.scroll = new scrollHandler(this.$refs.timelineContainer);
|
||||
this.scroll.scrollToBottom();
|
||||
this.onScroll();
|
||||
},
|
||||
watch: {
|
||||
'$route'(){
|
||||
|
Loading…
Reference in New Issue
Block a user