Add option to start private chat

By clicking on avatar. Issue #101.
This commit is contained in:
N-Pex 2021-05-10 16:11:03 +02:00
parent f3b37f7479
commit 91dfb0bc8e
6 changed files with 196 additions and 7 deletions

View file

@ -9,14 +9,14 @@
ref="chatContainer"
style="overflow-x: hidden; overflow-y: auto"
v-on:scroll="onScroll"
@click="closeContextMenuIfOpen"
@click="closeContextMenusIfOpen"
>
<div ref="messageOperationsStrut" class="message-operations-strut">
<message-operations
ref="messageOperations"
:style="opStyle"
:emojis="recentEmojis"
v-on:close="showContextMenu = false"
v-on:close="showContextMenu = false;showContextMenuAnchor = null;"
v-if="selectedEvent && showContextMenu"
v-on:addreaction="addReaction"
v-on:addquickreaction="addQuickReaction"
@ -29,6 +29,18 @@
/>
</div>
<div ref="avatarOperationsStrut" class="avatar-operations-strut">
<avatar-operations
ref="avatarOperations"
:style="avatarOpStyle"
v-on:close="showAvatarMenu = false;showAvatarMenuAnchor = null;"
v-on:start-private-chat="startPrivateChat($event)"
v-if="selectedEvent && showAvatarMenu"
:room="room"
:event="selectedEvent"
/>
</div>
<!-- Handle resizes, e.g. when soft keyboard is shown/hidden -->
<resize-observer
ref="chatContainerResizer"
@ -82,6 +94,7 @@
v-on:send-quick-reaction="sendQuickReaction"
v-on:context-menu="showContextMenuForEvent($event)"
v-on:own-avatar-clicked="viewProfile"
v-on:other-avatar-clicked="showAvatarMenuForEvent($event)"
v-on:download="download(event)"
/>
<!-- <div v-if="debugging" style="user-select:text">EventID: {{ event.getId() }}</div> -->
@ -355,6 +368,7 @@ import DebugEvent from "./messages/DebugEvent.vue";
import util from "../plugins/utils";
import MessageOperations from "./messages/MessageOperations.vue";
import MessageOperationsPicker from "./messages/MessageOperationsPicker.vue";
import AvatarOperations from "./messages/AvatarOperations.vue";
import ChatHeader from "./ChatHeader";
import VoiceRecorder from "./VoiceRecorder";
import RoomInfoBottomSheet from "./RoomInfoBottomSheet";
@ -430,6 +444,7 @@ export default {
MessageOperationsBottomSheet,
StickerPickerBottomSheet,
BottomSheet,
AvatarOperations,
},
data() {
@ -456,6 +471,8 @@ export default {
replyToEvent: null,
showContextMenu: false,
showContextMenuAnchor: null,
showAvatarMenu: false,
showAvatarMenuAnchor: null,
initialLoadDone: false,
loading: false, // Set this to true during long operations to show a "spinner" overlay
showRecorder: false,
@ -586,6 +603,25 @@ export default {
}
return "top:" + top + "px;left:" + left + "px";
},
avatarOpStyle() {
// Calculate where to show the context menu.
//
const ref = this.selectedEvent && this.$refs[this.selectedEvent.getId()];
var top = 0;
var left = 0;
if (ref && ref[0]) {
if (this.showAvatarMenuAnchor) {
var rectAnchor = this.showAvatarMenuAnchor.getBoundingClientRect();
var rectChat = this.$refs.avatarOperationsStrut.getBoundingClientRect();
top = rectAnchor.top - rectChat.top;
left = rectAnchor.left - rectChat.left;
// if (left + 250 > rectChat.right) {
// left = rectChat.right - 250; // Pretty ugly, but we want to make sure it does not escape the screen, and we don't have the exakt width of it (yet)!
// }
}
}
return "top:" + top + "px;left:" + left + "px";
},
canRecordAudio() {
return util.browserCanRecordAudio();
},
@ -1258,13 +1294,44 @@ export default {
this.showContextMenuAnchor = e.anchor;
},
showAvatarMenuForEvent(e) {
const event = e.event;
this.selectedEvent = event;
this.showAvatarMenu = true;
this.showAvatarMenuAnchor = e.anchor;
},
viewProfile() {
this.$navigation.push({ name: "Profile" }, 1);
},
closeContextMenuIfOpen(e) {
startPrivateChat(e) {
this.$matrix.getOrCreatePrivateChat(e.event.getSender())
.then(room => {
this.$nextTick(() => {
this.$navigation.push(
{
name: "Chat",
params: { roomId: util.sanitizeRoomId(room.getCanonicalAlias() || room.roomId) },
},
-1
);
});
})
.catch(err => {
console.error(err);
})
},
closeContextMenusIfOpen(e) {
if (this.showContextMenu) {
this.showContextMenu = false;
this.showContextMenuAnchor = null;
e.preventDefault();
}
if (this.showAvatarMenu) {
this.showAvatarMenu = false;
this.showAvatarMenuAnchor = null;
e.preventDefault();
}
},

View file

@ -0,0 +1,37 @@
<template>
<div
:class="{
'avatar-operations': true,
incoming: incoming,
outgoing: !incoming,
}"
>
<v-btn v-if="incoming" text @click.stop="startPrivateChat" class="ma-0 pa-0"
>Private chat with this user</v-btn
>
</div>
</template>
<script>
import messageMixin from "./messageMixin";
export default {
mixins: [messageMixin],
mounted() {
// Any items to show?
if (this.room && this.event && this.$matrix.isDirectRoomWith(this.room, this.event.getSender())) {
this.$emit("close");
}
},
methods: {
startPrivateChat() {
this.$emit("close");
this.$emit("start-private-chat", { event: this.event });
},
},
};
</script>
<style lang="scss">
@import "@/assets/css/chat.scss";
</style>

View file

@ -1,7 +1,7 @@
<template>
<!-- BASE CLASS FOR INCOMING MESSAGE -->
<div :class="messageClasses">
<v-avatar class="avatar" size="32" color="#ededed">
<v-avatar class="avatar" ref="avatar" size="32" color="#ededed" @click.stop="otherAvatarClicked($refs.avatar.$el)">
<img v-if="messageEventAvatar(event)" :src="messageEventAvatar(event)" />
<span v-else class="white--text headline">{{
messageEventDisplayName(event).substring(0, 1).toUpperCase()

View file

@ -156,6 +156,10 @@ export default {
this.$emit("own-avatar-clicked", {event: this.event});
},
otherAvatarClicked(avatarRef) {
this.$emit("other-avatar-clicked", {event: this.event, anchor: avatarRef});
},
showContextMenu(buttonRef) {
this.$emit("context-menu", {event: this.event,anchor: buttonRef});
},