mirror of
https://github.com/nextcloud/spreed.git
synced 2025-12-17 21:12:20 +01:00
Merge pull request #16515 from nextcloud/fix/noid/toaster
This commit is contained in:
commit
fdd705c4a7
2 changed files with 60 additions and 63 deletions
|
|
@ -4,11 +4,7 @@
|
|||
-->
|
||||
|
||||
<template>
|
||||
<TransitionWrapper
|
||||
class="toaster"
|
||||
name="toast"
|
||||
tag="ul"
|
||||
group>
|
||||
<ul class="toaster">
|
||||
<li
|
||||
v-for="toast in toasts"
|
||||
:key="toast.seed"
|
||||
|
|
@ -28,7 +24,7 @@
|
|||
{{ toast.name }}
|
||||
</span>
|
||||
</li>
|
||||
</TransitionWrapper>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
@ -38,7 +34,6 @@ import { imagePath } from '@nextcloud/router'
|
|||
import { usernameToColor } from '@nextcloud/vue/functions/usernameToColor'
|
||||
import Hex from 'crypto-js/enc-hex.js'
|
||||
import SHA1 from 'crypto-js/sha1.js'
|
||||
import TransitionWrapper from '../../UIShared/TransitionWrapper.vue'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
import { useGuestNameStore } from '../../../stores/guestName.ts'
|
||||
|
||||
|
|
@ -57,13 +52,14 @@ const reactions = {
|
|||
'😥': 'Concerned.gif',
|
||||
}
|
||||
|
||||
const ANIMATION_LENGTH = 2_000
|
||||
const TOAST_INTERVAL = 500
|
||||
// Timestamp of when the next reaction should be shown in UI
|
||||
let nextProcessedTimestamp = 0
|
||||
|
||||
export default {
|
||||
name: 'ReactionToaster',
|
||||
|
||||
components: {
|
||||
TransitionWrapper,
|
||||
},
|
||||
|
||||
props: {
|
||||
/**
|
||||
* The conversation token
|
||||
|
|
@ -101,7 +97,6 @@ export default {
|
|||
registeredModels: {},
|
||||
reactionsQueue: [],
|
||||
intervalId: null,
|
||||
animationLength: 2000,
|
||||
toasts: [],
|
||||
}
|
||||
},
|
||||
|
|
@ -113,25 +108,29 @@ export default {
|
|||
},
|
||||
|
||||
watch: {
|
||||
callParticipantModels(models) {
|
||||
// subscribe connected models for reaction signals
|
||||
const addedModels = models.filter((model) => !this.registeredModels[model.attributes.peerId])
|
||||
addedModels.forEach((addedModel) => {
|
||||
this.registeredModels[addedModel.attributes.peerId] = addedModel
|
||||
this.registeredModels[addedModel.attributes.peerId].on('reaction', this.handleReaction)
|
||||
})
|
||||
callParticipantModels: {
|
||||
handler(models) {
|
||||
// subscribe connected models for reaction signals
|
||||
const addedModels = models.filter((model) => !this.registeredModels[model.attributes.peerId])
|
||||
addedModels.forEach((addedModel) => {
|
||||
this.registeredModels[addedModel.attributes.peerId] = addedModel
|
||||
this.registeredModels[addedModel.attributes.peerId].on('reaction', this.handleReaction)
|
||||
})
|
||||
|
||||
// unsubscribe disconnected models
|
||||
const removedModelIds = Object.keys(this.registeredModels).filter((registeredModelId) => !models.find((model) => model.attributes.peerId === registeredModelId))
|
||||
removedModelIds.forEach((removedModelId) => {
|
||||
this.registeredModels[removedModelId].off('reaction', this.handleReaction)
|
||||
delete this.registeredModels[removedModelId]
|
||||
})
|
||||
// unsubscribe disconnected models
|
||||
const removedModelIds = Object.keys(this.registeredModels).filter((registeredModelId) => !models.find((model) => model.attributes.peerId === registeredModelId))
|
||||
removedModelIds.forEach((removedModelId) => {
|
||||
this.registeredModels[removedModelId].off('reaction', this.handleReaction)
|
||||
delete this.registeredModels[removedModelId]
|
||||
})
|
||||
},
|
||||
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.intervalId = setInterval(this.processReactionsQueue, this.animationLength / 4)
|
||||
this.intervalId = setInterval(this.processReactionsQueue, TOAST_INTERVAL)
|
||||
subscribe('send-reaction', this.handleOwnReaction)
|
||||
},
|
||||
|
||||
|
|
@ -151,8 +150,8 @@ export default {
|
|||
},
|
||||
|
||||
handleReaction(model, reaction, isLocalModel = false) {
|
||||
// prevent spamming to queue from a single account
|
||||
if (this.reactionsQueue.some((item) => item.id === model.attributes.peerId)) {
|
||||
// prevent spamming to queue from a single account (unless in debug mode)
|
||||
if (!OC.debug && this.reactionsQueue.some((item) => item.id === model.attributes.peerId)) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -169,19 +168,39 @@ export default {
|
|||
? this.actorStore.displayName || t('spreed', 'Guest')
|
||||
: this.getParticipantName(model),
|
||||
seed: Math.random(),
|
||||
timestamp: Date.now(),
|
||||
})
|
||||
},
|
||||
|
||||
processReactionsQueue() {
|
||||
if (this.reactionsQueue.length > 0) {
|
||||
// Move reactions from queue to visible array
|
||||
this.toasts.push(this.reactionsQueue.shift())
|
||||
|
||||
// Delete reactions from array after animation ends
|
||||
setTimeout(() => {
|
||||
this.toasts.shift()
|
||||
}, this.animationLength)
|
||||
if (this.reactionsQueue.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
// Prevent spamming with reactions, if tab was suspended
|
||||
const now = Date.now()
|
||||
if (now < nextProcessedTimestamp) {
|
||||
return
|
||||
}
|
||||
|
||||
// Discard reactions, that should have been fired long ago
|
||||
if (this.reactionsQueue.at(0).timestamp < now - 30_000) {
|
||||
this.reactionsQueue = this.reactionsQueue.filter((reaction) => reaction.timestamp >= now - 30_000)
|
||||
|
||||
if (this.reactionsQueue.length === 0) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
nextProcessedTimestamp = now + TOAST_INTERVAL
|
||||
|
||||
// Move reactions from queue to visible array
|
||||
this.toasts.push(this.reactionsQueue.shift())
|
||||
|
||||
// Delete reactions from array after animation ends
|
||||
setTimeout(() => {
|
||||
this.toasts.shift()
|
||||
}, ANIMATION_LENGTH)
|
||||
},
|
||||
|
||||
getParticipantName(model) {
|
||||
|
|
@ -209,7 +228,7 @@ export default {
|
|||
|
||||
return {
|
||||
'--background-color': `rgb(${color.r}, ${color.g}, ${color.b})`,
|
||||
'--animation-length': `${this.animationLength + 300}ms`,
|
||||
'--animation-length': `${ANIMATION_LENGTH + 300}ms`,
|
||||
'--horizontal-offset': `${10 + 20 * seed}%`,
|
||||
'--vertical-offset': 30 + 5 * seed,
|
||||
}
|
||||
|
|
@ -268,6 +287,10 @@ export default {
|
|||
@keyframes toast-floating {
|
||||
0% {
|
||||
transform: translateY(0);
|
||||
opacity: 0;
|
||||
}
|
||||
5% {
|
||||
transform: translateY(calc(-0.05 * var(--vertical-offset) * 1vh));
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ export default {
|
|||
'slide-up',
|
||||
'slide-right',
|
||||
'slide-down',
|
||||
'toast',
|
||||
'zoom',
|
||||
].includes(value)
|
||||
},
|
||||
|
|
@ -153,23 +152,6 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
@mixin toast-rules {
|
||||
&-enter,
|
||||
&-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
&-enter-to,
|
||||
&-leave {
|
||||
opacity: 1;
|
||||
}
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: $transition-slow;
|
||||
transition-property: opacity;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin zoom-rules {
|
||||
&-enter,
|
||||
&-leave-to {
|
||||
|
|
@ -207,10 +189,6 @@ export default {
|
|||
@include slide-down-rules;
|
||||
}
|
||||
|
||||
.toast {
|
||||
@include toast-rules;
|
||||
}
|
||||
|
||||
.zoom {
|
||||
@include zoom-rules;
|
||||
}
|
||||
|
|
@ -240,10 +218,6 @@ export default {
|
|||
@include group-rules;
|
||||
@include slide-down-rules;
|
||||
}
|
||||
&.toast {
|
||||
@include group-rules;
|
||||
@include toast-rules;
|
||||
}
|
||||
&.zoom {
|
||||
@include group-rules;
|
||||
@include zoom-rules;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue