]> Repos - mime-chat/commitdiff
implement message view render queue
authorriqo <hernandeze2@xavier.edu>
Tue, 16 Feb 2021 23:00:24 +0000 (17:00 -0600)
committerriqo <hernandeze2@xavier.edu>
Tue, 16 Feb 2021 23:08:25 +0000 (17:08 -0600)
src/background/run.ts
src/background/session.ts
src/components/messageView/index.vue
src/components/messageView/viewDetails/anime.ts
src/components/messageView/viewDetails/transitions.ts
src/components/taInput/inputController.ts
src/components/taInput/textDetails/textVisualizer.ts
src/modules/ipc.ts
src/modules/queue.ts [new file with mode: 0644]
src/views/home.vue
tests/mockMessages.ts [moved from src/views/mockMessages.ts with 100% similarity]

index dc3e15053fd6858119a2da7f2f3bb00691a87166..d3ab52106f686ed9d07c1e11080a63acf67e1164 100644 (file)
@@ -23,6 +23,6 @@ export async function main() {
     socket = true;
 
     // Begin audio stream.
-    // initRecorder();
+    initRecorder();
 
 }
index bb14979e47b491527c68e0310045e729f248cfa3..5959e2e06a5c70095ad7ac428c2bbb756ffa0b92 100644 (file)
@@ -81,7 +81,6 @@ const asyncSend = (_event?, payload: TextMessage | Buffer): Promise<RenderMessag
     return new Promise((resolve, reject) => {
 
         backgroundMitt.once('message-res', (res: RenderMessage) => {
-            console.log(res)
             if (res.content) {
                 resolve(res);
             } else {
index 9a31f278319902b88c82efc73b7ffd074d2c9b6e..d6938c78c59b9c53ff34ae2ad141b2924ebdc61d 100644 (file)
@@ -4,7 +4,6 @@
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink"
     :viewBox="scrollView"
-    id="test"
   >
     <g id="messageView" transform="translate(0, 20)">
       <g v-for="(item, index) in renderArr" :key="index" preserverAspectRatio="none">
 </template>
 
 <script lang="ts">
-import useTransitions from "./viewDetails/transitions";
-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 useTransitions from "./viewDetails/transitions";
+import useScrollView from "@/modules/scrollView";
 import useMitt from "@/modules/mitt";
 import { useIpc } from "@/modules/ipc";
+import { Queue } from '@/modules/queue';
+import { defineComponent, reactive, onMounted, onUnmounted, watch } from "vue";
 
 export default defineComponent({
   name: "MessageView",
   components: { TextBubble },
   setup() {
-    const renderArr: Message[] = reactive([]);
     const { emitter } = useMitt();
+    const renderArr: Message[] = reactive([]);
+    const renderQ = new Queue();
+
     const { data, invoke } = useIpc("message");
+    const { beforeEnter, enter, afterEnter, rendering } = useTransitions();
+    const { scrollView } = useScrollView({
+      targetId: "messageView",
+    });
+
+    const render = (m: Message) => {
+      if (rendering.value) {
+        renderQ.enqueue(m);
+      } else {
+        renderArr.push(m);
+      }
+    }
+
+    watch(rendering, (rendering, _prevRendering) => {
+      if (!rendering) {
+          const m = renderQ.dequeue() as Message | null;
+          if (m) renderArr.push(m);
+      }
+    })
 
     onMounted(() => {
       window.ipcRenderer.on("render-message", (event, payload) => {
-        const message = payload.message;
-        if (message.content) renderArr.push(message);
+        const m = payload.message;
+        if (m.content) render(m);
       });
 
-      emitter.on("animateSend", async (message) => {
+      emitter.on("user-message", async (message) => {
         try {
-          // renderArr.push(message)
           await invoke(message);
-          renderArr.push(data.value);
+          render(data.value)
         } catch (e) {
           console.log("No response. Do not render.");
         }
@@ -60,11 +80,6 @@ export default defineComponent({
       emitter.all.clear();
     });
 
-    const { beforeEnter, enter, afterEnter } = useTransitions();
-    const { scrollView } = useScrollView({
-      targetId: "messageView",
-    });
-
     return {
       renderArr,
       beforeEnter,
index 3b82d36d369c363340ef7fd2ff93202465d1dff6..0e56eb488223a2002d25a83488327e8bdf5087bb 100644 (file)
@@ -1,9 +1,8 @@
 import { inject } from "vue";
 import AnimeFunc from "@/types/animejs/index";
-import { MessageAnimeFunc } from '@/types/message/index';
 
 /**
- * anime js animations used by message renderer
+ * anime js animations used by message view transitions
  */
 export default function useMessageViewAnims() {
     // imports animejs safely
@@ -11,37 +10,47 @@ export default function useMessageViewAnims() {
     const animeInject: AnimeFunc | undefined = inject("animejs");
     if (animeInject) anime = animeInject;
 
-    // adds new message at the bottom of the list and shifts existing message list
-    const shiftAnimate = (el: Element, transform: string, view: SVGGElement, viewTransform: string) => {
+    // update message View bottom bound
+    const shiftView = (el: SVGGElement, transform: string) => {
         anime({
             targets: el,
             transform: transform,
             easing: "easeInOutQuad",
-            duration: 800,
-            begin: function() {
-                shiftView(view, viewTransform);
-            },
+            duration: 500,
         });
     }
 
     // stacks message from top to bottom
     const stackAnimate = (el: Element, transform: string) => {
-        anime({
-            targets: el,
-            transform: transform,
-            easing: "easeInOutQuad",
-            duration: 1000,
-        });
+        return new Promise((resolve, _reject) => {
+            anime({
+                targets: el,
+                transform: transform,
+                easing: "easeInOutQuad",
+                duration: 1000,
+                complete: function() {
+                    resolve();
+                }
+            });
+        })
     }
 
-    // update message View bottom bound
-    const shiftView = (el: SVGGElement, transform: string) => {
-        anime({
-            targets: el,
-            transform: transform,
-            easing: "easeInOutQuad",
-            duration: 500,
-        });
+    // adds new message at the bottom of the list and shifts existing message list
+    const shiftAnimate = (el: Element, transform: string, view: SVGGElement, viewTransform: string) => {
+        return new Promise((resolve, _reject) => {
+            anime({
+                targets: el,
+                transform: transform,
+                easing: "easeInOutQuad",
+                duration: 800,
+                begin: function() {
+                    shiftView(view, viewTransform);
+                },
+                complete: function() {
+                    resolve();
+                }
+            });
+        })
     }
 
     return {
index 2562dac5c7bc2d88f81b119a4e783ab4e5c396a8..8d85701800191c92440782b59f6cd2a3dbfa3797 100644 (file)
@@ -1,11 +1,18 @@
 /**
- * handles visualization of view messages through
- * vue transition callbacks and anime-js animations
+ * Do stuff before, on, and after message enters the view.
+ * Rendering Process consists of the execution of the above 
+ * mentioned callbacks followed by the shift or stack animation. 
+ * The animation called depends on the height of the message view 
+ * relative to the window height. Additionally, the animation will
+ * always be called on the after enter callback, after all the neccesary 
+ * calculations have been completed. While all of this is hapenning,
+ * the rendering state is updated throughout the process.
  */
 
 import { VueTransitionCallback } from '@/types/vue3/vueTransitionCallback/index';
 import useMessageViewAnims from "./anime";
 import useOffsetCalculator from './offsetCalculator';
+import { ref } from 'vue';
 
 const wH = 500; // window Height
 const vP = 10;  // view padding
@@ -22,21 +29,23 @@ let messageView: SVGGElement;
 export default function useTransitions() {
     const { calculateMessageOffsets } = useOffsetCalculator();
     const { shiftAnimate, stackAnimate } = useMessageViewAnims();
+    const rendering = ref(false);
 
-    const animateMessage = (el: SVGGElement): void => {
+    const animateMessage = async (el: SVGGElement) => {
 
         const elTransform = `translate(${messageOffset.x} ${messageOffset.y})`;
         const viewTransform = `translate(0 ${-vB})`;
 
         if (shift) {
-            shiftAnimate(el, elTransform, messageView, viewTransform);
+            await shiftAnimate(el, elTransform, messageView, viewTransform);
         } else {
-            stackAnimate(el, elTransform)
+            await stackAnimate(el, elTransform)
         }
-
+        rendering.value = false;
     }
 
     const beforeEnter: VueTransitionCallback = () => {
+        rendering.value = true;
         // query DOM for messageView element
         const messageViewQuery = document.querySelectorAll("#messageView");
         messageView = messageViewQuery[0] as SVGGElement;
@@ -52,7 +61,7 @@ export default function useTransitions() {
         }
     }
 
-    const afterEnter: VueTransitionCallback = async (el) => {
+    const afterEnter: VueTransitionCallback = (el) => {
 
         if (message) messageOffset = calculateMessageOffsets(message);
 
@@ -71,5 +80,6 @@ export default function useTransitions() {
         beforeEnter,
         enter,
         afterEnter,
+        rendering
     };
 }
index f3c4ca95f784fee7d0a6dd98de9c006d97a510f5..e7eda4c7a7b6c5900c184d1bfe211fc155245a7e 100644 (file)
@@ -29,7 +29,7 @@ export default function useInputController() {
             audio: 0,
             text: input
         };
-        emitter.emit("animateSend", message);
+        emitter.emit("user-message", message);
     }
 
     const { visualizeStreamAsPaths, expandBubble } = useAudioVisualizer(visualizeStream);
@@ -39,14 +39,8 @@ export default function useInputController() {
     // stops stream recording on space key up
     function keyupHandler(e: any) {
         if (e.key === " " && visualizeStream.value) {
-            console.log("stop recording");
 
             post(false);
-            // window.postMessage({
-            //     myTypeField: 'update-recorder',
-            //     record: false
-            // }, '*')
-
             visualizeStream.value = false;
             paths.value = []
             audioBubbleWidth.value = 10;
@@ -75,15 +69,8 @@ export default function useInputController() {
             return;
         }
         if (input === " " && visualizeStream.value === false) {
-            console.log("record MediaStream");
             visualizeStream.value = true;
-
             post(true);
-            // window.postMessage({
-            //     myTypeField: 'update-recorder',
-            //     record: true
-            // }, '*')
-
             expandBubble(audioBubbleWidth);
             visualizeStreamAsPaths(stream, paths, audioBubbleWidth);
             return;
index 8dbda23d657ee0704e9710eb37b81a33a07c8f88..86ed1ccebd5e1b5e934b088d0a6aa41a47bfe64c 100644 (file)
@@ -32,7 +32,7 @@ export default function useTextVisualizer(input: Ref<string>) {
         }
     }
 
-    emitter.on("animateSend", async (payload: any) => {
+    emitter.on("user-message", () => {
         const inputEl = document.getElementsByClassName("inputContainer");
         const foreignEl = inputEl[0] as HTMLElement;
         animateSend(foreignEl, inputHeight.value, input);
index 3018767b9a45fa25af5bddec92db884f2679b758..53c4288f771a54489bb078f4d2b98e29b9854c84 100644 (file)
@@ -20,13 +20,6 @@ export const useIpc = (endpoint: string) => {
             error.value = e;
             throw e;
         }
-
-        // return window.ipcRenderer.invoke(endpoint, payload).then(res => {
-        //     data.value = res;
-        // }).catch(e => {
-        //     error.value = e;
-        //     throw e;
-        // })
     }
 
     const post = (payload: any) => {
diff --git a/src/modules/queue.ts b/src/modules/queue.ts
new file mode 100644 (file)
index 0000000..8b734b9
--- /dev/null
@@ -0,0 +1,78 @@
+export interface DataNode<T> {
+    data: T;
+    next: DataNode<T> | null;
+}
+
+export interface QueueI<T> {
+  enqueue(data: T): void;
+  dequeue(): T | null;
+  peek(): T | null;
+  size(): number;
+}
+
+export class Queue<T> implements QueueI<T> {
+  private _size: number;
+  private head: DataNode<T> | null;
+  private tail: DataNode<T>  | null;
+  constructor() {
+     this._size = 0;
+     this.head = this.tail = null; 
+  }
+
+  enqueue(data: T) {
+
+      const node: DataNode<T> = {
+         data,
+         next: null 
+      }
+      if (this.head === null) {
+         this.head = this.tail = node; 
+      } else {
+        if (this.tail) {
+         this.tail.next = node; 
+         this.tail = this.tail.next;
+        }
+
+      }
+      ++this._size;
+  }
+
+  dequeue(): T | null {
+
+    let item: T | null = null; 
+
+    if (this._size === 0) {
+      return null;
+    }
+
+    if (this.head) {
+      item = this.head.data;
+      this.head = this.head.next;
+      --this._size;
+
+      if (!this._size) {
+       this.tail = null; 
+      }
+    }
+    return item;
+  }
+
+  peek(): T | null {
+
+    let item: T | null = null; 
+
+    if (this._size === 0) {
+     return null;
+    }
+
+    if (this.head) {
+       item = this.head.data; 
+    }
+    
+    return item;
+  }
+
+  size(): number {
+    return this._size;
+  }
+}
index c502e36c8d630a36f73b72eb1280df07925abc90..677474b9bd18ef16a258451ea7ea92335bae59ae 100644 (file)
 <script lang="ts">
 import MessageView from "@/components/messageView/index.vue";
 import TextAudioInput from "@/components/taInput/index.vue";
-import { defineComponent, ref } from "vue";
-import {Messages} from './mockMessages';
-import useMitt from "@/modules/mitt";
+import { defineComponent } from "vue";
 
 export default defineComponent({
   name: "Messenger",
   components: { MessageView, TextAudioInput },
-  setup() {
-     const { emitter } = useMitt();
-     const counter = ref(0);
-
-      const emittMessage = () => {
-            emitter.emit('animateSend', Messages[counter.value])
-            counter.value++;
-          }
-          return {
-                  emittMessage
-              }
-  }
 });
 </script>