* Fix duplicated private messages

* Fix minor message styling issues
This commit is contained in:
styppo 2023-01-26 18:02:13 +00:00
parent 0ef9c65bde
commit 080f50bf26
No known key found for this signature in database
GPG Key ID: 3AAA685C50724C28
4 changed files with 92 additions and 24 deletions

View File

@ -0,0 +1,51 @@
<template>
<q-chat-message
:sent="sent"
:bg-color="sent ? 'grey-2' : 'pink-2'"
:stamp="createdAt"
class="chat-message"
>
<EncryptedMessage :message="message" click-to-decrypt />
</q-chat-message>
</template>
<script>
import EncryptedMessage from 'components/Message/EncryptedMessage.vue'
import {useAppStore} from 'stores/App'
import DateUtils from 'src/utils/DateUtils'
export default {
name: 'ChatMessage',
components: {EncryptedMessage},
props: {
message: {
type: Object,
required: true,
}
},
setup() {
return {
app: useAppStore()
}
},
computed: {
sent() {
return this.message.author === this.app.myPubkey
},
createdAt() {
return DateUtils.formatFromNowLong(this.message.createdAt)
}
},
}
</script>
<style lang="scss">
.chat-message {
&.q-message-received .q-message-container {
padding-right: 10%;
}
&.q-message-sent .q-message-container {
padding-left: 10%;
}
}
</style>

View File

@ -1,6 +1,6 @@
<template> <template>
<PostRenderer v-if="note?.content" :note="note" /> <PostRenderer v-if="note" :note="note" />
<span v-else-if="!decryptFailed" class="click-to-decrypt" @click="decrypt">Click to decrypt</span> <span v-else-if="!decryptFailed" class="click-to-decrypt" @click="clickToDecrypt && decrypt()">Click to decrypt</span>
<span v-else class="decrypt-failed" @click="decrypt">Decryption failed</span> <span v-else class="decrypt-failed" @click="decrypt">Decryption failed</span>
</template> </template>
@ -17,6 +17,10 @@ export default {
type: Object, type: Object,
required: true, required: true,
}, },
clickToDecrypt: {
type: Boolean,
default: false,
}
}, },
setup() { setup() {
return { return {
@ -25,26 +29,30 @@ export default {
}, },
data() { data() {
return { return {
plaintext: null,
decryptFailed: false, decryptFailed: false,
} }
}, },
computed: { computed: {
note() { note() {
if (!this.message) return if (!this.message?.plaintext) return
const note = new Note(this.message.id, this.message) const note = new Note(this.message.id, this.message)
note.content = this.message.plaintext || this.plaintext note.content = this.message.plaintext
return note return note
} }
}, },
methods: { methods: {
async decrypt() { async decrypt() {
if (this.message.plaintext) return
try { try {
const messageId = this.message.id
const counterparty = this.message.author === this.app.myPubkey const counterparty = this.message.author === this.app.myPubkey
? this.message.recipient ? this.message.recipient
: this.message.author : this.message.author
this.plaintext = await this.app.decryptMessage(counterparty, this.message.content) const plaintext = await this.app.decryptMessage(counterparty, this.message.content)
this.message.cachePlaintext(this.plaintext) // The message can change while we are decrypting it, so we need to make sure not to cache the wrong message.
if (this.message.id === messageId) {
this.message.cachePlaintext(plaintext)
}
} catch (e) { } catch (e) {
console.error('Failed to decrypt message', e) console.error('Failed to decrypt message', e)
this.decryptFailed = true this.decryptFailed = true
@ -52,9 +60,16 @@ export default {
} }
}, },
async mounted() { async mounted() {
if (!this.message.plaintext && this.app.activeAccount.canDecrypt()) { if (this.app.activeAccount.canDecrypt()) {
await this.decrypt() await this.decrypt()
} }
},
watch: {
async message() {
if (this.app.activeAccount.canDecrypt()) {
await this.decrypt()
}
}
} }
} }
</script> </script>

View File

@ -5,15 +5,11 @@
<div class="conversation"> <div class="conversation">
<div class="pusher"></div> <div class="pusher"></div>
<q-chat-message <ChatMessage
v-for="message in conversation" v-for="message in conversation"
:key="message.id" :key="message.id"
:sent="message.author === app.myPubkey" :message="message"
:bg-color="message.author === app.myPubkey ? 'grey-2' : 'pink-2'" />
:stamp="formatMessageDate(message.createdAt)"
>
<EncryptedMessage :message="message" />
</q-chat-message>
<p v-if="!conversation?.length" class="placeholder"> <p v-if="!conversation?.length" class="placeholder">
<template v-if="counterparty !== app.myPubkey"> <template v-if="counterparty !== app.myPubkey">
This is the beginning of your message history with <UserName :pubkey="counterparty" clickable />. This is the beginning of your message history with <UserName :pubkey="counterparty" clickable />.
@ -32,17 +28,16 @@
<script> <script>
import PageHeader from 'components/PageHeader.vue' import PageHeader from 'components/PageHeader.vue'
import UserCard from 'components/User/UserCard.vue' import UserCard from 'components/User/UserCard.vue'
import EncryptedMessage from 'components/Message/EncryptedMessage.vue'
import MessageEditor from 'components/Message/MessageEditor.vue' import MessageEditor from 'components/Message/MessageEditor.vue'
import UserName from 'components/User/UserName.vue'
import ChatMessage from 'components/Message/ChatMessage.vue'
import {useMessageStore} from 'src/nostr/store/MessageStore' import {useMessageStore} from 'src/nostr/store/MessageStore'
import {useAppStore} from 'stores/App' import {useAppStore} from 'stores/App'
import DateUtils from 'src/utils/DateUtils'
import {bech32ToHex} from 'src/utils/utils' import {bech32ToHex} from 'src/utils/utils'
import UserName from 'components/User/UserName.vue'
export default { export default {
name: 'Conversation', name: 'Conversation',
components: {UserName, MessageEditor, EncryptedMessage, PageHeader, UserCard}, components: {ChatMessage, UserName, MessageEditor, PageHeader, UserCard},
setup() { setup() {
return { return {
app: useAppStore(), app: useAppStore(),
@ -65,21 +60,22 @@ export default {
}, },
}, },
methods: { methods: {
formatMessageDate(timestamp) {
return DateUtils.formatFromNowLong(timestamp)
},
onPublish() { onPublish() {
this.markAsRead() this.markAsRead()
this.$nextTick(() => window.scrollTo(0, document.body.scrollHeight)) this.scrollToBottom()
}, },
markAsRead() { markAsRead() {
if (this.app.isSignedIn && this.counterparty) { if (this.app.isSignedIn && this.counterparty) {
this.messages.markAsRead(this.app.myPubkey, this.counterparty) this.messages.markAsRead(this.app.myPubkey, this.counterparty)
} }
}, },
scrollToBottom() {
this.$nextTick(() => window.scrollTo(0, document.body.scrollHeight))
},
}, },
mounted() { mounted() {
this.markAsRead() this.markAsRead()
setTimeout(() => this.scrollToBottom(), 100)
} }
} }
</script> </script>
@ -116,6 +112,9 @@ export default {
} }
@media screen and (max-width: $tablet) { @media screen and (max-width: $tablet) {
.conversation {
padding-bottom: 76px;
}
.conversation-reply { .conversation-reply {
padding-bottom: 22px; padding-bottom: 22px;
} }
@ -128,6 +127,9 @@ export default {
} }
@media screen and (max-width: $phone) { @media screen and (max-width: $phone) {
.conversation {
padding-bottom: 48px;
}
.conversation-reply { .conversation-reply {
width: 100%; width: 100%;
padding-bottom: 1rem; padding-bottom: 1rem;

View File

@ -1,7 +1,7 @@
<template> <template>
<PageHeader back-button> <PageHeader back-button>
<template #addon> <template #addon>
<q-btn icon="more_vert" size="md" round> <q-btn icon="more_vert" size="md" round flat>
<q-menu anchor="bottom right" self="top right" :offset="[0, 6]" class="options-popup"> <q-menu anchor="bottom right" self="top right" :offset="[0, 6]" class="options-popup">
<a @click="markAllAsRead" v-close-popup>Mark all as read</a> <a @click="markAllAsRead" v-close-popup>Mark all as read</a>
</q-menu> </q-menu>