remove old message event listeners

This commit is contained in:
Enrique Hernandez 2021-02-14 15:46:48 -06:00
commit 3cf22d61ac
13 changed files with 142 additions and 219 deletions

View file

@ -0,0 +1,91 @@
<template>
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
:viewBox="scrollView"
>
<g id="messageView" transform="translate(0, 5)">
<g
v-for="(item, index) in renderArr"
:key="index"
class="messageList"
transform="translate(0, 25)"
preserverAspectRatio="none"
>
<transition
appear
v-on:before-appear="beforeEnter"
v-on:appear="enter"
v-on:after-enter="afterEnter"
>
<TextBubble :item="item" :key="index" />
</transition>
</g>
</g>
</svg>
</template>
<script lang="ts">
import useMessageView from "./viewDetails/visualizer";
import useScrollView from "@/modules/scrollView";
import TextBubble from "@/components/textBubble/index.vue";
import { Message } from "@/types/message/index";
import { defineComponent, reactive, onMounted, onUnmounted } from "vue";
import useMitt from "@/modules/mitt";
import { useIpc } from "@/modules/ipc";
export default defineComponent({
name: "MessageView",
components: { TextBubble },
setup() {
const renderArr: Message[] = reactive([]);
const { emitter } = useMitt();
const { data, invoke } = useIpc("async-message");
onMounted(() => {
window.ipcRenderer.on("render-message", (event, payload) => {
const message = payload.message;
if (message) renderArr.push(message);
});
emitter.on("animateSend", async (message) => {
try {
await invoke(message);
renderArr.push(data.value);
} catch (e) {
console.log("No response. Do not render.");
}
});
});
onUnmounted(() => {
window.ipcRenderer.removeAllListeners("render-message");
emitter.all.clear();
});
const { beforeEnter, enter, afterEnter } = useMessageView();
const { scrollView } = useScrollView({
targetId: "messageView",
});
return {
renderArr,
beforeEnter,
enter,
afterEnter,
scrollView,
};
},
});
</script>
<style lang="scss" scoped>
svg {
height: 1%;
overflow: hidden;
}
#messageRenderer {
margin: 0;
}
</style>

View file

@ -0,0 +1,80 @@
import { inject } from "vue";
import AnimeFunc from "@/types/animejs/index";
import { MessageAnimeFunc } from '@/types/message/index';
/**
* anime js animations used by message renderer
*/
export default function useMessageViewAnims(): {
shiftAnimate: MessageAnimeFunc;
stackAnimate: MessageAnimeFunc;
} {
// imports animejs safely
let anime: AnimeFunc;
const animeInject: AnimeFunc | undefined = inject("animejs");
if (animeInject) anime = animeInject;
// shifts message list by a given value
function shiftList({ targetList, sv }: { targetList: NodeList | undefined; sv: number | undefined }) {
if (targetList) {
for (const element of targetList) {
const el = element.parentNode as HTMLElement;
anime({
targets: el,
transform: `translate(0 ${sv})`,
easing: "easeInOutQuad",
duration: 500,
});
}
}
}
// adds new message at the bottom of the list and shifts existing message list
const shiftAnimate: MessageAnimeFunc = (el, transform, shiftValue, targetList) => {
anime({
targets: el,
transform: transform.initialTranslate,
easing: "easeInOutQuad",
duration: 500,
begin: function() {
shiftList({
targetList,
sv: shiftValue
});
},
complete: function() {
anime({
targets: el,
transform: transform.finalTranslate,
easing: "easeInOutQuad",
duration: 500,
offset: 1000
});
}
});
}
// stacks message from top to bottom
const stackAnimate: MessageAnimeFunc = (el, transform) => {
anime({
targets: el,
transform: transform.initialTranslate,
easing: "easeInOutQuad",
duration: 1000,
complete: function() {
anime({
targets: el,
transform: transform.finalTranslate,
easing: "easeInOutQuad",
duration: 500,
offset: 1000
});
}
});
}
return {
shiftAnimate,
stackAnimate
};
}

View file

@ -0,0 +1,41 @@
import { ref } from "vue";
/**
* Calculates vertical and horizontal message offsets
*/
export default function useOffsetCalculator() {
const xOffset = ref(0);
const yOffset = ref(0);
const firstChildMarginTop = 0;
let previousMessageHeight = 0;
const messagePadding = 15;
function calculateX(message: HTMLElement): void {
const computedQuery = window.getComputedStyle(message);
const matrix = new WebKitCSSMatrix(computedQuery.webkitTransform);
xOffset.value = matrix.m41;
}
function calculateY(messageHeight: number): void {
if (previousMessageHeight === 0) {
yOffset.value = firstChildMarginTop;
} else {
yOffset.value += previousMessageHeight + messagePadding;
}
previousMessageHeight = messageHeight;
}
const calculateMessageOffsets = (msg: HTMLElement): { x: number; y: number } => {
const msgRect = msg.getBoundingClientRect();
calculateX(msg);
calculateY(msgRect.height);
const offsets = {
x: xOffset.value as number,
y: yOffset.value as number
};
return offsets;
}
return {
calculateMessageOffsets,
}
}

View file

@ -0,0 +1,73 @@
import { VueTransitionCallback } from '@/types/vue3/vueTransitionCallback/index';
import useMessageViewAnims from "./anime";
import useOffsetCalculator from './offsetCalculator';
/**
* handles visualization of view messages through
* vue transition callbacks and anime-js animations
*/
export default function useMessageView(): {
beforeEnter: VueTransitionCallback;
enter: VueTransitionCallback;
afterEnter: VueTransitionCallback;
} {
// uses offsetCalculator logic and renderer animations
const { calculateMessageOffsets } = useOffsetCalculator();
const { shiftAnimate, stackAnimate } = useMessageViewAnims();
const messagePadding = 15;
let messageList: NodeList;
let message: HTMLElement | null;
let messageOffset = { x: 0, y: 0 };
let shift = false;
let shiftOffset = 0;
// animates message item to 'enter' renderView
const animateMessage = (el: SVGGElement): void => {
const transform = {
initialTranslate: `translate(${messageOffset.x} ${messageOffset.y})`,
finalTranslate: `translate(${messageOffset.x} ${messageOffset.y})`
}
shift ? shiftAnimate(el, transform, shiftOffset, messageList) : stackAnimate(el, transform);
}
const beforeEnter: VueTransitionCallback = () => {
const queryResult = document.querySelectorAll(".messageList");
console.log(queryResult)
if (queryResult.length) messageList = queryResult;
}
const enter: VueTransitionCallback = (el) => {
// query DOM for latest message as soon as it enters
if (el) {
message = document.getElementById(el.id);
}
}
const afterEnter: VueTransitionCallback = (el) => {
// get message positioning & shift state before animating
if (message) {
messageOffset = calculateMessageOffsets(message);
shift = messageOffset.y > 400 ? true : false;
}
if (el) {
if (shift) {
console.log(messageOffset.y)
if (messageOffset.y < 445 && messageOffset.y < 500) {
shiftOffset -= 15;
} else {
shiftOffset -= el.getBBox().height + messagePadding;
}
}
animateMessage(el);
}
}
return {
beforeEnter,
enter,
afterEnter
};
}