parent
e7cd5db831
commit
43e876ba80
6 changed files with 92 additions and 43 deletions
11
package-lock.json
generated
11
package-lock.json
generated
|
|
@ -10,6 +10,7 @@
|
||||||
"aes-js": "^3.1.2",
|
"aes-js": "^3.1.2",
|
||||||
"axios": "^0.21.0",
|
"axios": "^0.21.0",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
|
"intersection-observer": "^0.11.0",
|
||||||
"json-web-key": "^0.4.0",
|
"json-web-key": "^0.4.0",
|
||||||
"material-design-icons-iconfont": "^5.0.1",
|
"material-design-icons-iconfont": "^5.0.1",
|
||||||
"matrix-js-sdk": "^9.0.1",
|
"matrix-js-sdk": "^9.0.1",
|
||||||
|
|
@ -7410,6 +7411,11 @@
|
||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/intersection-observer": {
|
||||||
|
"version": "0.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.11.0.tgz",
|
||||||
|
"integrity": "sha512-KZArj2QVnmdud9zTpKf279m2bbGfG+4/kn16UU0NL3pTVl52ZHiJ9IRNSsnn6jaHrL9EGLFM5eWjTx2fz/+zoQ=="
|
||||||
|
},
|
||||||
"node_modules/ip": {
|
"node_modules/ip": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
|
||||||
|
|
@ -20706,6 +20712,11 @@
|
||||||
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
|
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"intersection-observer": {
|
||||||
|
"version": "0.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.11.0.tgz",
|
||||||
|
"integrity": "sha512-KZArj2QVnmdud9zTpKf279m2bbGfG+4/kn16UU0NL3pTVl52ZHiJ9IRNSsnn6jaHrL9EGLFM5eWjTx2fz/+zoQ=="
|
||||||
|
},
|
||||||
"ip": {
|
"ip": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
"aes-js": "^3.1.2",
|
"aes-js": "^3.1.2",
|
||||||
"axios": "^0.21.0",
|
"axios": "^0.21.0",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
|
"intersection-observer": "^0.11.0",
|
||||||
"json-web-key": "^0.4.0",
|
"json-web-key": "^0.4.0",
|
||||||
"material-design-icons-iconfont": "^5.0.1",
|
"material-design-icons-iconfont": "^5.0.1",
|
||||||
"matrix-js-sdk": "^9.0.1",
|
"matrix-js-sdk": "^9.0.1",
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,7 @@
|
||||||
v-on:scroll="onScroll"
|
v-on:scroll="onScroll"
|
||||||
>
|
>
|
||||||
<div v-for="event in events" :key="event.getId()">
|
<div v-for="event in events" :key="event.getId()">
|
||||||
<component
|
<component :is="componentForEvent(event)" :room="room" :event="event" />
|
||||||
:is="componentForEvent(event)"
|
|
||||||
:room="room"
|
|
||||||
:event="event" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -81,14 +78,14 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { TimelineWindow, EventTimeline } from "matrix-js-sdk";
|
import { TimelineWindow, EventTimeline } from "matrix-js-sdk";
|
||||||
import MessageIncomingText from './messages/MessageIncomingText';
|
import MessageIncomingText from "./messages/MessageIncomingText";
|
||||||
import MessageOutgoingText from './messages/MessageOutgoingText';
|
import MessageOutgoingText from "./messages/MessageOutgoingText";
|
||||||
import ContactJoin from './messages/ContactJoin.vue';
|
import ContactJoin from "./messages/ContactJoin.vue";
|
||||||
import ContactLeave from './messages/ContactLeave.vue';
|
import ContactLeave from "./messages/ContactLeave.vue";
|
||||||
import ContactInvited from './messages/ContactInvited.vue';
|
import ContactInvited from "./messages/ContactInvited.vue";
|
||||||
import RoomNameChanged from './messages/RoomNameChanged.vue';
|
import RoomNameChanged from "./messages/RoomNameChanged.vue";
|
||||||
import RoomTopicChanged from './messages/RoomTopicChanged.vue';
|
import RoomTopicChanged from "./messages/RoomTopicChanged.vue";
|
||||||
import RoomAvatarChanged from './messages/RoomAvatarChanged.vue';
|
import RoomAvatarChanged from "./messages/RoomAvatarChanged.vue";
|
||||||
import DebugEvent from "./messages/DebugEvent.vue";
|
import DebugEvent from "./messages/DebugEvent.vue";
|
||||||
import MessageOutgoingImage from "./messages/MessageOutgoingImage.vue";
|
import MessageOutgoingImage from "./messages/MessageOutgoingImage.vue";
|
||||||
import MessageIncomingImage from "./messages/MessageIncomingImage.vue";
|
import MessageIncomingImage from "./messages/MessageIncomingImage.vue";
|
||||||
|
|
@ -134,22 +131,25 @@ export default {
|
||||||
RoomAvatarChanged,
|
RoomAvatarChanged,
|
||||||
DebugEvent,
|
DebugEvent,
|
||||||
MessageOutgoingImage,
|
MessageOutgoingImage,
|
||||||
MessageIncomingImage
|
MessageIncomingImage,
|
||||||
},
|
},
|
||||||
|
|
||||||
data() { return {
|
data() {
|
||||||
room: null,
|
return {
|
||||||
events: [],
|
room: null,
|
||||||
currentInput: "",
|
events: [],
|
||||||
contactIsTyping: false,
|
currentInput: "",
|
||||||
timelineWindow: null,
|
contactIsTyping: false,
|
||||||
scrollPosition: null,
|
timelineWindow: null,
|
||||||
currentImageInput: null,
|
scrollPosition: null,
|
||||||
currentImageInputPath: null,
|
currentImageInput: null,
|
||||||
currentSendOperation: null,
|
currentImageInputPath: null,
|
||||||
currentSendProgress: null,
|
currentSendOperation: null,
|
||||||
currentSendError: null,
|
currentSendProgress: null,
|
||||||
}},
|
currentSendError: null,
|
||||||
|
joinRoom: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
const container = this.$refs.chatContainer;
|
const container = this.$refs.chatContainer;
|
||||||
|
|
@ -157,11 +157,21 @@ export default {
|
||||||
|
|
||||||
this.$matrix.on("Room.timeline", this.onEvent);
|
this.$matrix.on("Room.timeline", this.onEvent);
|
||||||
this.$matrix.on("RoomMember.typing", this.onUserTyping);
|
this.$matrix.on("RoomMember.typing", this.onUserTyping);
|
||||||
|
this.$matrix.on("Matrix.initialized", this.onInitialized);
|
||||||
|
|
||||||
|
if (this.$route.params && this.$route.params.joinRoom) {
|
||||||
|
this.joinRoom = this.$route.params.joinRoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.$matrix.matrixClientReady) {
|
||||||
|
this.onInitialized(this.$matrix.matrixClient);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.$matrix.off("Room.timeline", this.onEvent);
|
this.$matrix.off("Room.timeline", this.onEvent);
|
||||||
this.$matrix.off("RoomMember.typing", this.onUserTyping);
|
this.$matrix.off("RoomMember.typing", this.onUserTyping);
|
||||||
|
this.$matrix.off("Matrix.initialized", this.onInitialized);
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -207,40 +217,55 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
onInitialized(matrixClient) {
|
||||||
|
if (this.joinRoom) {
|
||||||
|
const roomId = this.joinRoom;
|
||||||
|
this.joinRoom = null;
|
||||||
|
matrixClient
|
||||||
|
.joinRoom(roomId)
|
||||||
|
.then((room) => {
|
||||||
|
this.$matrix.setCurrentRoomId(room.roomId);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
// TODO - handle error
|
||||||
|
console.log("Failed to join room", err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
componentForEvent(event) {
|
componentForEvent(event) {
|
||||||
switch (event.getType()) {
|
switch (event.getType()) {
|
||||||
case 'm.room.member':
|
case "m.room.member":
|
||||||
if (event.event.state_key != this.myUserId) {
|
if (event.event.state_key != this.myUserId) {
|
||||||
if (event.getContent().membership == 'join') {
|
if (event.getContent().membership == "join") {
|
||||||
return ContactJoin;
|
return ContactJoin;
|
||||||
} else if (event.getContent().membership == 'leave') {
|
} else if (event.getContent().membership == "leave") {
|
||||||
return ContactLeave;
|
return ContactLeave;
|
||||||
} else if (event.getContent().membership == 'invite') {
|
} else if (event.getContent().membership == "invite") {
|
||||||
return ContactInvited;
|
return ContactInvited;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'm.room.message':
|
case "m.room.message":
|
||||||
if (event.getSender() != this.myUserId) {
|
if (event.getSender() != this.myUserId) {
|
||||||
if (event.getContent().msgtype == 'm.image') {
|
if (event.getContent().msgtype == "m.image") {
|
||||||
return MessageIncomingImage;
|
return MessageIncomingImage;
|
||||||
}
|
}
|
||||||
return MessageIncomingText;
|
return MessageIncomingText;
|
||||||
} else {
|
} else {
|
||||||
if (event.getContent().msgtype == 'm.image') {
|
if (event.getContent().msgtype == "m.image") {
|
||||||
return MessageOutgoingImage;
|
return MessageOutgoingImage;
|
||||||
}
|
}
|
||||||
return MessageOutgoingText;
|
return MessageOutgoingText;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'm.room.name':
|
case "m.room.name":
|
||||||
return RoomNameChanged;
|
return RoomNameChanged;
|
||||||
|
|
||||||
case 'm.room.topic':
|
case "m.room.topic":
|
||||||
return RoomTopicChanged;
|
return RoomTopicChanged;
|
||||||
|
|
||||||
case 'm.room.avatar':
|
case "m.room.avatar":
|
||||||
return RoomAvatarChanged;
|
return RoomAvatarChanged;
|
||||||
}
|
}
|
||||||
return DebugEvent;
|
return DebugEvent;
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,7 @@ class Util {
|
||||||
.then(response => {
|
.then(response => {
|
||||||
return new Promise((resolve, ignoredReject) => {
|
return new Promise((resolve, ignoredReject) => {
|
||||||
var aesjs = require('aes-js');
|
var aesjs = require('aes-js');
|
||||||
//var JSONWebKey = require( 'json-web-key' );
|
|
||||||
var base64Url = require('json-web-key/lib/base64url');
|
var base64Url = require('json-web-key/lib/base64url');
|
||||||
//var tou8 = require('buffer-to-uint8array');
|
|
||||||
var key = base64Url.decode(file.key.k);
|
var key = base64Url.decode(file.key.k);
|
||||||
var iv = base64Url.decode(file.iv);
|
var iv = base64Url.decode(file.iv);
|
||||||
var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(iv));
|
var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(iv));
|
||||||
|
|
@ -52,7 +50,7 @@ class Util {
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(bytes => {
|
.then(bytes => {
|
||||||
resolve(URL.createObjectURL(new Blob([bytes.buffer], { type: 'image/png' })));
|
resolve(URL.createObjectURL(new Blob([bytes.buffer], { type: file.mimetype })));
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.log("Download error: ", err);
|
console.log("Download error: ", err);
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,16 @@ const routes = [
|
||||||
path: '/login',
|
path: '/login',
|
||||||
component: Login
|
component: Login
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/join/:room?',
|
||||||
|
redirect: from => {
|
||||||
|
const room = from.hash;
|
||||||
|
if (room) {
|
||||||
|
return { name: 'Chat', params: { joinRoom: room }};
|
||||||
|
}
|
||||||
|
return '/';
|
||||||
|
}
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const router = new VueRouter({
|
const router = new VueRouter({
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
matrixClient: null,
|
matrixClient: null,
|
||||||
|
matrixClientReady: false,
|
||||||
rooms: [],
|
rooms: [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -73,6 +74,7 @@ export default {
|
||||||
this.removeMatrixClientListeners(this.matrixClient);
|
this.removeMatrixClientListeners(this.matrixClient);
|
||||||
this.matrixClient.stopClient();
|
this.matrixClient.stopClient();
|
||||||
this.matrixClient = null;
|
this.matrixClient = null;
|
||||||
|
this.matrixClientReady = false;
|
||||||
localStorage.removeItem('user');
|
localStorage.removeItem('user');
|
||||||
}
|
}
|
||||||
this.$store.commit("setCurrentRoomId", null);
|
this.$store.commit("setCurrentRoomId", null);
|
||||||
|
|
@ -80,6 +82,8 @@ export default {
|
||||||
|
|
||||||
initClient() {
|
initClient() {
|
||||||
this.reloadRooms();
|
this.reloadRooms();
|
||||||
|
this.matrixClientReady = true;
|
||||||
|
this.matrixClient.emit('Matrix.initialized', this.matrixClient);
|
||||||
},
|
},
|
||||||
|
|
||||||
async getMatrixClient(user) {
|
async getMatrixClient(user) {
|
||||||
|
|
@ -179,10 +183,10 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
getRoom(roomId) {
|
getRoom(roomId) {
|
||||||
if (this.matrixClient) {
|
// if (this.matrixClient) {
|
||||||
return this.matrixClient.getRoom(roomId);
|
// return this.matrixClient.getRoom(roomId);
|
||||||
}
|
// }
|
||||||
return null;
|
return this.rooms.find(room => room.roomId == roomId);
|
||||||
},
|
},
|
||||||
|
|
||||||
on(event, handler) {
|
on(event, handler) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue