UI updates
This commit is contained in:
parent
3dc1fa3567
commit
24b72cab1e
9 changed files with 193 additions and 58 deletions
|
|
@ -120,6 +120,21 @@ $chat-text-size: 0.7pt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.op-button {
|
||||||
|
position:absolute;
|
||||||
|
right:-30px;
|
||||||
|
top:0;
|
||||||
|
.v-icon {
|
||||||
|
color: #cccccc;
|
||||||
|
&:hover {
|
||||||
|
color: #888888;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.messageOut .op-button {
|
||||||
|
right:70%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.messageJoin {
|
.messageJoin {
|
||||||
|
|
@ -139,6 +154,9 @@ $chat-text-size: 0.7pt;
|
||||||
border-radius: 10px 10px 0 10px;
|
border-radius: 10px 10px 0 10px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
|
.audio-bubble {
|
||||||
|
overflow: scroll;
|
||||||
|
}
|
||||||
.bubble.image-bubble {
|
.bubble.image-bubble {
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
@ -179,6 +197,7 @@ $chat-text-size: 0.7pt;
|
||||||
}
|
}
|
||||||
.audio-bubble {
|
.audio-bubble {
|
||||||
margin-left: 40px;
|
margin-left: 40px;
|
||||||
|
overflow: scroll;
|
||||||
}
|
}
|
||||||
.bubble.image-bubble {
|
.bubble.image-bubble {
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
|
|
@ -248,14 +267,21 @@ $chat-text-size: 0.7pt;
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.messageOperations {
|
.message-operations-strut {
|
||||||
|
position: relative;
|
||||||
|
height: 0px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-operations {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 10px;
|
width: auto;
|
||||||
|
background-color: #ffe2e2;
|
||||||
&.incoming {
|
&.incoming {
|
||||||
left: -20px;
|
right: 30%;
|
||||||
}
|
}
|
||||||
&.outgoing {
|
&.outgoing {
|
||||||
right: 20px;
|
left: 30%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,32 @@
|
||||||
ref="chatContainer"
|
ref="chatContainer"
|
||||||
style="overflow-x: hidden; overflow-y: auto"
|
style="overflow-x: hidden; overflow-y: auto"
|
||||||
v-on:scroll="onScroll"
|
v-on:scroll="onScroll"
|
||||||
|
@click.prevent="closeContextMenuIfOpen"
|
||||||
>
|
>
|
||||||
|
<div class="message-operations-strut">
|
||||||
|
<message-operations
|
||||||
|
:style="opStyle"
|
||||||
|
v-on:close="showContextMenu = false"
|
||||||
|
v-if="selectedEvent && showContextMenu"
|
||||||
|
v-on:addreaction="addReaction"
|
||||||
|
v-on:edit="edit(selectedEvent)"
|
||||||
|
:event="selectedEvent"
|
||||||
|
:incoming="selectedEvent.getSender() != $matrix.currentUserId"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Handle resizes, e.g. when soft keyboard is shown/hidden -->
|
<!-- Handle resizes, e.g. when soft keyboard is shown/hidden -->
|
||||||
<resize-observer
|
<resize-observer
|
||||||
ref="chatContainerResizer"
|
ref="chatContainerResizer"
|
||||||
@notify="handleChatContainerResize"
|
@notify="handleChatContainerResize"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div v-for="event in events" :key="event.getId()">
|
<div v-for="event in events" :key="event.getId()">
|
||||||
<div
|
<div
|
||||||
v-if="
|
v-if="
|
||||||
!event.isRelation() && !event.isRedacted() && !event.isRedaction()
|
!event.isRelation() && !event.isRedacted() && !event.isRedaction()
|
||||||
"
|
"
|
||||||
|
:ref="event.getId()"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style="position: relative; user-select: none"
|
style="position: relative; user-select: none"
|
||||||
|
|
@ -41,14 +56,15 @@
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
v-on:send-quick-reaction="sendQuickReaction"
|
v-on:send-quick-reaction="sendQuickReaction"
|
||||||
|
v-on:context-menu="showContextMenuForEvent($event)"
|
||||||
/>
|
/>
|
||||||
<message-operations
|
<!-- <message-operations
|
||||||
v-on:close="showContextMenu = false"
|
v-on:close="showContextMenu = false"
|
||||||
v-if="selectedEvent == event && showContextMenu"
|
v-if="selectedEvent == event && showContextMenu"
|
||||||
v-on:addreaction="addReaction"
|
v-on:addreaction="addReaction"
|
||||||
:event="event"
|
:event="event"
|
||||||
:incoming="event.getSender() != $matrix.currentUserId"
|
:incoming="event.getSender() != $matrix.currentUserId"
|
||||||
/>
|
/> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -239,6 +255,7 @@ export default {
|
||||||
currentSendError: null,
|
currentSendError: null,
|
||||||
showEmojiPicker: false,
|
showEmojiPicker: false,
|
||||||
selectedEvent: null,
|
selectedEvent: null,
|
||||||
|
editedEvent: null,
|
||||||
showContextMenu: false,
|
showContextMenu: false,
|
||||||
/**
|
/**
|
||||||
* Current chat container size. We need to keep track of this so that if and when
|
* Current chat container size. We need to keep track of this so that if and when
|
||||||
|
|
@ -287,7 +304,18 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
opStyle() {
|
||||||
|
// Calculate where to show the context menu.
|
||||||
|
//
|
||||||
|
const ref = this.selectedEvent && this.$refs[this.selectedEvent.getId()];
|
||||||
|
if (ref && ref[0]) {
|
||||||
|
const offset = ref[0].offsetTop - this.scrollPosition.node.offsetTop;
|
||||||
|
return "top:" + offset + "px";
|
||||||
|
}
|
||||||
|
return "top:0px";
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
|
|
@ -459,7 +487,7 @@ export default {
|
||||||
) {
|
) {
|
||||||
scrollToSeeNew = true;
|
scrollToSeeNew = true;
|
||||||
}
|
}
|
||||||
if (event.forwardLooking) {
|
if (event.forwardLooking && !event.isRelation()) {
|
||||||
this.handleScrolledToBottom(scrollToSeeNew);
|
this.handleScrolledToBottom(scrollToSeeNew);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -483,6 +511,13 @@ export default {
|
||||||
|
|
||||||
sendMessage() {
|
sendMessage() {
|
||||||
if (this.currentInput.length > 0) {
|
if (this.currentInput.length > 0) {
|
||||||
|
// Is this an edit?
|
||||||
|
if (this.editedEvent) {
|
||||||
|
console.log("Edit");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editedEvent = null; //TODO - Is this a good place to reset this?
|
||||||
|
|
||||||
util
|
util
|
||||||
.sendTextMessage(
|
.sendTextMessage(
|
||||||
this.$matrix.matrixClient,
|
this.$matrix.matrixClient,
|
||||||
|
|
@ -640,6 +675,11 @@ export default {
|
||||||
this.showEmojiPicker = true;
|
this.showEmojiPicker = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
edit(event) {
|
||||||
|
this.editedEvent = event;
|
||||||
|
this.currentInput = event.getContent().body;
|
||||||
|
},
|
||||||
|
|
||||||
emojiSelected(e) {
|
emojiSelected(e) {
|
||||||
this.showEmojiPicker = false;
|
this.showEmojiPicker = false;
|
||||||
if (this.selectedEvent) {
|
if (this.selectedEvent) {
|
||||||
|
|
@ -664,6 +704,22 @@ export default {
|
||||||
console.log("Failed to send quick reaction:", err);
|
console.log("Failed to send quick reaction:", err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
showContextMenuForEvent(event) {
|
||||||
|
const ref = this.$refs[event.getId()];
|
||||||
|
if (ref) {
|
||||||
|
console.log("Got the ref", ref);
|
||||||
|
}
|
||||||
|
this.selectedEvent = event;
|
||||||
|
this.showContextMenu = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
closeContextMenuIfOpen(e) {
|
||||||
|
if (this.showContextMenu) {
|
||||||
|
this.showContextMenu = false;
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,16 @@
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
|
<v-card class="account ma-3">
|
||||||
|
<v-card-title>Your account</v-card-title>
|
||||||
|
<v-card-text>
|
||||||
|
<div v-if="$matrix.currentUser.is_guest">
|
||||||
|
<div>You don't have a Keanu account, yet ;)</div>
|
||||||
|
<v-btn dark block @click.stop="upgradeAccount">Login</v-btn>
|
||||||
|
</div>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
|
||||||
<!-- EDIT dialog -->
|
<!-- EDIT dialog -->
|
||||||
<v-dialog v-model="showEditDialog" class="ma-0 pa-0" width="50%">
|
<v-dialog v-model="showEditDialog" class="ma-0 pa-0" width="50%">
|
||||||
<v-card>
|
<v-card>
|
||||||
|
|
@ -130,6 +140,16 @@ export default {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
upgradeAccount() {
|
||||||
|
this.$matrix.upgradeGuestAccount()
|
||||||
|
.then(() => {
|
||||||
|
console.log("Done");
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log("ERROR", err);
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="messageIn">
|
<div class="messageIn">
|
||||||
<div class="audio-bubble">
|
<div class="audio-bubble">
|
||||||
<audio controls :src="src">Audio file</audio>
|
<audio controls :src="src">Audio file</audio>
|
||||||
<QuickReactions :event="event" :reactions="reactions" />
|
<QuickReactions :event="event" :reactions="reactions" />
|
||||||
</div>
|
</div>
|
||||||
<v-avatar class="avatar" size="32" color="#ededed">
|
<v-btn icon class="op-button" @click.stop="showContextMenu"
|
||||||
<img
|
><v-icon>more_vert</v-icon></v-btn
|
||||||
v-if="messageEventAvatar(event)"
|
>
|
||||||
:src="messageEventAvatar(event)"
|
<v-avatar class="avatar" size="32" color="#ededed">
|
||||||
/>
|
<img v-if="messageEventAvatar(event)" :src="messageEventAvatar(event)" />
|
||||||
<span v-else class="white--text headline">{{
|
<span v-else class="white--text headline">{{
|
||||||
messageEventDisplayName(event).substring(0, 1).toUpperCase()
|
messageEventDisplayName(event).substring(0, 1).toUpperCase()
|
||||||
}}</span>
|
}}</span>
|
||||||
</v-avatar>
|
</v-avatar>
|
||||||
<div class="sender">{{ messageEventDisplayName(event) }}</div>
|
<div class="sender">{{ messageEventDisplayName(event) }}</div>
|
||||||
<div class="time">
|
<div class="time">
|
||||||
{{ formatTime(event.event.origin_server_ts) }}
|
{{ formatTime(event.event.origin_server_ts) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="messageIn">
|
<div class="messageIn">
|
||||||
<div class="bubble image-bubble">
|
<div class="bubble image-bubble">
|
||||||
<v-img :aspect-ratio="16 / 9" ref="image" :src="src" cover />
|
<v-img :aspect-ratio="16 / 9" ref="image" :src="src" cover />
|
||||||
<QuickReactions :event="event" :reactions="reactions" />
|
<QuickReactions :event="event" :reactions="reactions" />
|
||||||
</div>
|
</div>
|
||||||
<v-avatar class="avatar" size="40" color="grey">
|
<v-btn icon class="op-button" @click.stop="showContextMenu"
|
||||||
<img
|
><v-icon>more_vert</v-icon></v-btn
|
||||||
v-if="messageEventAvatar(event)"
|
>
|
||||||
:src="messageEventAvatar(event)"
|
<v-avatar class="avatar" size="32" color="#ededed">
|
||||||
/>
|
<img v-if="messageEventAvatar(event)" :src="messageEventAvatar(event)" />
|
||||||
<span v-else class="white--text headline">{{
|
<span v-else class="white--text headline">{{
|
||||||
messageEventDisplayName(event).substring(0, 1).toUpperCase()
|
messageEventDisplayName(event).substring(0, 1).toUpperCase()
|
||||||
}}</span>
|
}}</span>
|
||||||
</v-avatar>
|
</v-avatar>
|
||||||
<div class="sender">{{ messageEventDisplayName(event) }}</div>
|
<div class="sender">{{ messageEventDisplayName(event) }}</div>
|
||||||
<div class="time">
|
<div class="time">
|
||||||
{{ formatTime(event.event.origin_server_ts) }}
|
{{ formatTime(event.event.origin_server_ts) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,25 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="messageIn">
|
<div class="messageIn">
|
||||||
<v-avatar class="avatar" size="32" color="#ededed">
|
<v-avatar class="avatar" size="32" color="#ededed">
|
||||||
<img
|
<img v-if="messageEventAvatar(event)" :src="messageEventAvatar(event)" />
|
||||||
v-if="messageEventAvatar(event)"
|
<span v-else class="white--text headline">{{
|
||||||
:src="messageEventAvatar(event)"
|
messageEventDisplayName(event).substring(0, 1).toUpperCase()
|
||||||
/>
|
}}</span>
|
||||||
<span v-else class="white--text headline">{{
|
</v-avatar>
|
||||||
messageEventDisplayName(event).substring(0, 1).toUpperCase()
|
|
||||||
}}</span>
|
|
||||||
</v-avatar>
|
|
||||||
|
|
||||||
<div class="bubble">
|
<div class="bubble">
|
||||||
<div class="message">{{ event.getContent().body }}
|
<div class="message">
|
||||||
<span class="edit-marker" v-if="event.replacingEventId()">(edited)</span>
|
{{ event.getContent().body }}
|
||||||
</div>
|
<span class="edit-marker" v-if="event.replacingEventId()"
|
||||||
<QuickReactions :event="event" :reactions="reactions" />
|
>(edited)</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="sender">{{ messageEventDisplayName(event) }}</div>
|
<QuickReactions :event="event" :reactions="reactions" />
|
||||||
|
</div>
|
||||||
|
<v-btn icon class="op-button" @click.stop="showContextMenu"
|
||||||
|
><v-icon>more_vert</v-icon></v-btn
|
||||||
|
>
|
||||||
|
<div class="sender">{{ messageEventDisplayName(event) }}</div>
|
||||||
<div class="time">
|
<div class="time">
|
||||||
{{ formatTime(event.event.origin_server_ts) }}
|
{{ formatTime(event.event.origin_server_ts) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="{'messageOperations':true,'incoming':incoming,'outgoing':!incoming}">
|
<div :class="{'message-operations':true,'incoming':incoming,'outgoing':!incoming}">
|
||||||
<v-btn icon @click.stop="addReaction" class="ma-0 pa-0">
|
<v-btn icon @click.stop="addReaction" class="ma-0 pa-0">
|
||||||
<v-icon>mood</v-icon>
|
<v-icon>mood</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
<v-btn v-if="incoming" icon @click.stop="addReply" class="ma-0 pa-0">
|
||||||
|
<v-icon>reply</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-btn v-if="isEditable" icon @click.stop="edit" class="ma-0 pa-0">
|
||||||
|
<v-icon>edit</v-icon>
|
||||||
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -27,10 +33,24 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
isEditable() {
|
||||||
|
return !this.incoming && this.event.getContent().msgtype == "m.text";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
addReaction() {
|
addReaction() {
|
||||||
this.$emit("close");
|
this.$emit("close");
|
||||||
this.$emit("addreaction", {event:this.event});
|
this.$emit("addreaction", {event:this.event});
|
||||||
|
},
|
||||||
|
addReply() {
|
||||||
|
this.$emit("close");
|
||||||
|
this.$emit("addreply", {event:this.event});
|
||||||
|
},
|
||||||
|
edit() {
|
||||||
|
this.$emit("close");
|
||||||
|
this.$emit("edit", {event:this.event});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,22 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="messageOut">
|
<div class="messageOut">
|
||||||
<div class="bubble">
|
<div class="bubble">
|
||||||
<div class="message">{{ event.getContent().body }}
|
<div class="message">
|
||||||
<span class="edit-marker" v-if="event.replacingEventId()">(edited)</span>
|
{{ event.getContent().body }}
|
||||||
</div>
|
<span class="edit-marker" v-if="event.replacingEventId()"
|
||||||
<QuickReactions :event="event" :reactions="reactions" />
|
>(edited)</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="sender">{{ "You" }}</div> -->
|
<QuickReactions :event="event" :reactions="reactions" />
|
||||||
|
</div>
|
||||||
|
<v-btn icon class="op-button" @click.stop="showContextMenu"
|
||||||
|
><v-icon>more_vert</v-icon></v-btn
|
||||||
|
>
|
||||||
|
<!-- <div class="sender">{{ "You" }}</div> -->
|
||||||
<div class="time">
|
<div class="time">
|
||||||
{{ formatTime(event.event.origin_server_ts) }}
|
{{ formatTime(event.event.origin_server_ts) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="status">{{ event.status }}</div>
|
<div class="status">{{ event.status }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,10 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
showContextMenu() {
|
||||||
|
this.$emit("context-menu", this.event);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a display name given an event.
|
* Get a display name given an event.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue