UI updates

This commit is contained in:
N-Pex 2020-12-14 16:11:45 +01:00
parent 3dc1fa3567
commit 24b72cab1e
9 changed files with 193 additions and 58 deletions

View file

@ -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%;
} }
} }

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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});
} }
} }
}; };

View file

@ -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>

View file

@ -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.
*/ */