]> Repos - mime-chat/commitdiff
add core directory
authorriqo <hernandeze2@xavier.edu>
Sun, 13 Dec 2020 21:07:06 +0000 (15:07 -0600)
committerriqo <hernandeze2@xavier.edu>
Tue, 15 Dec 2020 21:45:02 +0000 (15:45 -0600)
25 files changed:
src/components/UI/UIDetails/messageItem.vue
src/components/UI/UIDetails/messageRenderer.vue
src/components/input/inputItem.vue
src/composables/audioRenderer/useAudioRenderer.ts [deleted file]
src/composables/inputItem/useInputRenderer.ts [deleted file]
src/composables/messageItem/useMessageItemAnims.ts [deleted file]
src/composables/messageItem/useMessageItemComp.ts [deleted file]
src/composables/messageRenderer/useMessageRenderer.ts [deleted file]
src/core/UI/input/audio/useStreamRecord.ts [new file with mode: 0644]
src/core/UI/input/audio/useStreamRender.ts [moved from src/composables/streamRecorder/useStreamRecorder.ts with 75% similarity]
src/core/UI/input/text/textDetails/useAnimations.ts [moved from src/composables/inputItem/useInputAnims.ts with 92% similarity]
src/core/UI/input/text/useTextRender.ts [moved from src/composables/inputItem/useTextInput.ts with 78% similarity]
src/core/UI/input/useInputController.ts [new file with mode: 0644]
src/core/UI/scrollView/useScrollView.ts [moved from src/composables/scrollView/useScrollView.ts with 99% similarity]
src/core/messenger/message/messageDetails/useAnimations.ts [new file with mode: 0644]
src/core/messenger/message/messageDetails/useComputed.ts [new file with mode: 0644]
src/core/messenger/renderView/renderDetails/useAnimations.ts [moved from src/composables/messageRenderer/useRendererAnims.ts with 84% similarity]
src/core/messenger/renderView/renderDetails/useOffsetCalculator.ts [moved from src/composables/messageRenderer/useOffsetCalculator.ts with 68% similarity]
src/core/messenger/renderView/useRenderView.ts [new file with mode: 0644]
src/types/vue3/vueTransitionCallback/index.ts [new file with mode: 0644]
src/utils/keyDownHandler/keyBoardMaps/keyboardCharMap.ts [moved from src/composables/keyDownHandler/keyboardMaps/keyboardCharMap.ts with 100% similarity]
src/utils/keyDownHandler/keyBoardMaps/keyboardNameMap.ts [moved from src/composables/keyDownHandler/keyboardMaps/keyboardNameMap.ts with 100% similarity]
src/utils/keyDownHandler/useKeyDownHandler.ts [moved from src/composables/keyDownHandler/useKeyDownHandler.ts with 93% similarity]
src/utils/mediaStream/useMediaStream.ts [moved from src/composables/mediaStream/useMediaStream.ts with 80% similarity]
src/utils/textWrap/useTextWrap.ts [moved from src/composables/textWrap/useTextWrap.ts with 100% similarity]

index 95049f8f806dd6a40ed24e0cdb49fa95bd5eaad8..21e93f927b36a6d2e5dd76006eecb51e1c92b00e 100644 (file)
@@ -28,9 +28,9 @@
 
 <script lang="ts">
 import { defineComponent, onMounted, ref, reactive } from "vue";
-import useMessageItemComp from "@/composables/messageItem/useMessageItemComp";
-import useMessageItemAnims from "@/composables/messageItem/useMessageItemAnims";
-import useTextWrap from "@/composables/textWrap/useTextWrap";
+import useMessageItemComp from "@/core/messenger/message/messageDetails/useComputed";
+import useMessageItemAnims from "@/core/messenger/message/messageDetails/useAnimations";
+import useTextWrap from "@/utils/textWrap/useTextWrap";
 export default defineComponent({
   name: "MessageItem",
   props: {
index 2068c80e44405d52791a316783de800396d04ba7..02a14e87fd0f8639c1eecb26363eeebdf38b7a96 100644 (file)
@@ -28,8 +28,8 @@
 </template>
 
 <script lang="ts">
-import useMessageRenderer from "@/composables/messageRenderer/useMessageRenderer";
-import useScrollView from "@/composables/scrollView/useScrollView";
+import useRenderView from '@/core/messenger/renderView/useRenderView';
+import useScrollView from "@/core/UI/scrollView/useScrollView";
 import {
   defineComponent,
   reactive,
@@ -54,8 +54,10 @@ export default defineComponent({
       });
     }
 
-    const { beforeEnter, enter, afterEnter } = useMessageRenderer();
-    const {scrollView} = useScrollView({ targetId: "messageRenderer"});
+    const { beforeEnter, enter, afterEnter } = useRenderView();
+    const { scrollView } = useScrollView({ 
+      targetId: "messageRenderer"
+    });
 
     return {
       renderArr,
index c85a9cd70a2c03588da92d8fa0685db1f9b6f7c0..4e4cf01678df21ec00bc43f99e4222e995e9df60 100644 (file)
 </template>
 
 <script lang="ts">
-import {defineComponent} from 'vue'
+import { defineComponent } from 'vue'
 import TextInput from './inputDetails/textInput.vue';
 import AudioInput from './inputDetails/audioInput.vue';
-import useInputRenderer from "@/composables/inputItem/useInputRenderer";
+import useInputController from "@/core/UI/input/useInputController";
 export default defineComponent({
   name: "InputItem",
   components: {TextInput, AudioInput},
@@ -26,7 +26,7 @@ export default defineComponent({
       renderAudio, 
       reactiveWidth, 
       textInputXoffset,
-      paths } = useInputRenderer();
+      paths } = useInputController();
 
     return {
       input,
diff --git a/src/composables/audioRenderer/useAudioRenderer.ts b/src/composables/audioRenderer/useAudioRenderer.ts
deleted file mode 100644 (file)
index bf44178..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-export default function useAudioRenderer(stream: MediaStream) {
-    const audioCtx = new (window.AudioContext)();
-    const analyzer = audioCtx.createAnalyser();
-    const source = audioCtx.createMediaStreamSource(stream);
-    source.connect(analyzer);
-
-    analyzer.fftSize = 2048;
-    const xInitial = 24;
-    const xFinal = 640;
-    analyzer.minDecibels = -90;
-    analyzer.smoothingTimeConstant = 0.85;
-    const dataArray = new Uint8Array(analyzer.frequencyBinCount);
-    // const sampleRate = 16000;
-
-    const renderAudio = (audio: Float32Array, sampleRate: number) => {
-
-        // step 2: source audio frequency {ffft} data
-        const buffer = audioCtx.createBuffer(1, audio.length, sampleRate);
-        buffer.copyToChannel(audio, 0, 0);
-        const source = audioCtx.createBufferSource();
-        source.buffer = buffer;
-        source.connect(analyzer);
-        source.start();
-        analyzer.getByteFrequencyData(dataArray);
-
-        // step 3: process audio frequency data
-        const dataView = dataArray.slice(xInitial, xFinal);
-        const sum = dataView.reduce((a, b) => a + b);
-        const average = sum / dataView.length;
-        const scaled = average / 255;
-        const zeroed = scaled - 0.6;
-        return average;
-    }
-
-    return {
-        renderAudio
-    }
-}
diff --git a/src/composables/inputItem/useInputRenderer.ts b/src/composables/inputItem/useInputRenderer.ts
deleted file mode 100644 (file)
index a6968db..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-import {ref, watch, onUnmounted, onMounted } from "vue";
-import useKeyDownHandler from "@/composables/keyDownHandler/useKeyDownHandler";
-import useMediaStream from "@/composables/mediaStream/useMediaStream";
-import useStreamRecorder from "@/composables/streamRecorder/useStreamRecorder";
-import useTextInput from '@/composables/inputItem/useTextInput';
-/* 
-* Renders input to the user
-*/
-export default function useInputRenderer() {
-  // program ref varaiables
-  const renderAudio = ref(false);
-  const reactiveWidth = ref(10);
-  const pathOffset = ref(10);
-  const paths = ref([]);
-  
-  // get input feedback & handler function
-  const { keyDownHandler, input } = useKeyDownHandler();
-  // get text Offset and & textRender function
-  const { textInputXoffset, renderTextInput } = useTextInput(input, renderAudio);
-
-  // why do we have audio stuff here ?
-  let stream: MediaStream;
-  const {renderStream} = useStreamRecorder(renderAudio)
-  onMounted(async () => {
-    const streamRes = await useMediaStream()
-    stream = streamRes.stream;
-  })
-
-  // stop stream recording on space keyup event
-  function keyupHandler(e: any) {
-    if (e.key === " " && renderAudio.value) {
-      console.log("stop recording");
-      renderAudio.value = false;
-      input.value = "";
-      reactiveWidth.value = 10;
-      pathOffset.value = 10;
-    }
-  }
-
-  // add window event listener
-  window.addEventListener("keydown", keyDownHandler);
-  window.addEventListener('keyup', keyupHandler);
-
-  // remove Event Listeners on component unMount
-  onUnmounted(() => {
-    window.removeEventListener("keydown", keyDownHandler);
-    window.removeEventListener("keyup", keyupHandler);
-  });
-
-  // determine whether to render text or audio based one the keyboard input
-  watch(input, async (input, prevInput) => {
-    if (prevInput !== "" || prevInput.length > 0) {
-      if (!renderAudio.value) {
-        renderTextInput();
-      }
-      return;
-    }
-    if (input === " " && renderAudio.value === false) {
-      console.log("record");
-      renderAudio.value = true;
-      renderStream(stream, reactiveWidth, pathOffset, paths);
-      return;
-    }           
-    renderTextInput();
-  });
-
-  return {
-    input,
-    renderAudio,
-    reactiveWidth,
-    textInputXoffset,
-    paths
-  }
-
-}
\ No newline at end of file
diff --git a/src/composables/messageItem/useMessageItemAnims.ts b/src/composables/messageItem/useMessageItemAnims.ts
deleted file mode 100644 (file)
index 3e2875d..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-import { ref, onMounted } from "vue";
-import {Ref} from "@/types/vueRef/index";
-export default function useMessageItemAnims({
-  mr,
-  tr,
-}: {
-  mr: Ref<string>;
-  tr: Ref<string>;
-}) {
-  const signatureTranslate = ref("");
-  let messageRect: SVGSVGElement & SVGRectElement;
-  let messageText: SVGSVGElement & SVGTextElement;
-
-  onMounted(async () => {
-    messageRect = (mr.value as unknown) as SVGSVGElement & SVGRectElement;
-    messageText = (tr.value as unknown) as SVGSVGElement & SVGTextElement;
-  });
-
-  function adjustMessageRect(): void {
-    // must get dimensions of text box to fit bubble around
-    const padding = 12.5;
-    const textBox = messageText.getBBox();
-    messageRect.setAttribute("x", String(textBox.x - padding));
-    messageRect.setAttribute("y", String(textBox.y - padding));
-    messageRect.setAttribute("width", String(textBox.width + 2 * padding));
-    messageRect.setAttribute("height", String(textBox.height + 2 * padding));
-  }
-
-  function translateMsgSignature(): void {
-    if (messageRect.getAttribute("height") !== null) {
-      const height = Number(messageRect.getAttribute("height"));
-      signatureTranslate.value = `translate(-10 ${height})`;
-    }
-  }
-
-  async function drawMessage() {
-    // ignore lint error: await needed for proper render
-    await adjustMessageRect();
-    translateMsgSignature();
-  }
-
-  return {
-    drawMessage,
-    signatureTranslate,
-  };
-}
diff --git a/src/composables/messageItem/useMessageItemComp.ts b/src/composables/messageItem/useMessageItemComp.ts
deleted file mode 100644 (file)
index 564736f..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-import { computed, onMounted, ref } from "vue";
-export default function useMessageItemComp(m: string, id: string) {
-  const x = ref(0)
-  const paddingLeft = 30;
-  const winW = 350;
-  const messageWidth = ref(0);
-  const messageMarginTop = 75;
-  const test = ref("");
-
-  const textFill = computed(() => {
-    switch (m) {
-      case "sf":
-        return "#fff";
-      default:
-        return "#000";
-    }
-  });
-
-  const bubbleFill = computed(() => {
-    switch (m) {
-      case "sf":
-        return "#61b4f4";
-      default: 
-        return "#fff";
-    }
-  });
-
-  const setMessageWidthRef = async () => {
-      const msg = await document.getElementById(id);
-      if (msg) {
-        messageWidth.value = msg.getBoundingClientRect().width;
-      }
-  }
-
-  const selfMessageMarginRight = 2.5;
-  const calculateXoffset = async () => {
-    switch (m) {
-        case "sf":
-            x.value = winW - messageWidth.value - selfMessageMarginRight;
-            break;
-        default:
-            x.value = paddingLeft;
-            // to center a message
-            // x = messageMargin + (winW -messageWidth) / 2;
-    }
-  }
-
-  const startingOffset = computed(() => {
-    const messageRenderer = document.getElementById('messageRenderer');
-    if (messageRenderer) {
-      const rect = messageRenderer.getBoundingClientRect();
-      let Y = 600;
-      if (rect.height > 500) {
-        Y = rect.height + messageMarginTop;
-      }
-      return `translate(${x.value} ${Y})`;
-    }
-  });
-
-  onMounted(async () => {
-    // to calculate X offset:
-    // First: set message width ref
-    await setMessageWidthRef();
-    // Then: calculate message X offset
-    calculateXoffset();
-  })
-
-  return {
-    textFill,
-    bubbleFill,
-    startingOffset
-  };
-}
diff --git a/src/composables/messageRenderer/useMessageRenderer.ts b/src/composables/messageRenderer/useMessageRenderer.ts
deleted file mode 100644 (file)
index a916f5c..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-import useRendererAnims from "./useRendererAnims";
-import useOffsetCalculator from './useOffsetCalculator';
-export default function useMessageRenderer() {
-
-    const { calculateMessageOffsets } = useOffsetCalculator();
-    const { shiftAnimate, stackAnimate } = useRendererAnims();
-
-    let messageList: NodeList;
-    let message: HTMLElement | null;
-    let messageOffset = { x: 0, y: 0 };
-    let shift = false;
-    let shiftValue = 0;
-
-    function animateMessage(el: SVGGElement): void {
-        const transform = {
-            initialTranslate: `translate(${messageOffset.x} ${messageOffset.y})`,
-            finalTranslate: `translate(${messageOffset.x} ${messageOffset.y})`
-        }
-        shift ? shiftAnimate(el, transform, shiftValue, messageList) : stackAnimate(el, transform);
-    }
-
-    function beforeEnter(el: SVGGElement): void {
-        const queryResult = document.querySelectorAll(".messageList");
-        if (queryResult.length) messageList = queryResult;
-    }
-
-    function enter(el: SVGGElement): void {
-        message = document.getElementById(el.id);
-    }
-
-    function afterEnter(el: SVGGElement) {
-        const messagePadding = 15;
-
-        if (message) {
-            messageOffset = calculateMessageOffsets(message);
-            shift = messageOffset.y > 445 ? true : false;
-        }
-        if (shift) {
-            shiftValue -= el.getBBox().height + messagePadding;
-        }
-        animateMessage(el);
-    }
-
-    return {
-        beforeEnter,
-        enter,
-        afterEnter
-    };
-}
diff --git a/src/core/UI/input/audio/useStreamRecord.ts b/src/core/UI/input/audio/useStreamRecord.ts
new file mode 100644 (file)
index 0000000..bef12f5
--- /dev/null
@@ -0,0 +1,20 @@
+export default function useStreamRecord(): {
+    initRecorder: (stream: MediaStream) => MediaRecorder;
+} {
+    let streamRecorder: MediaRecorder;
+    const chunks: Blob[] = [];
+
+    const initRecorder = (stream: MediaStream) => {
+        streamRecorder = new MediaRecorder(stream);
+        streamRecorder.ondataavailable = (e: any) => { chunks.push(e.data) }
+        streamRecorder.onstop = (e: any) => {
+            // send audio to BE
+            const audioBlob = new Blob(chunks, { 'type': 'audio/ogg; codecs=opus' });
+        }
+        return streamRecorder
+    }
+
+    return {
+        initRecorder,
+    }
+}
similarity index 75%
rename from src/composables/streamRecorder/useStreamRecorder.ts
rename to src/core/UI/input/audio/useStreamRender.ts
index 1f625ede8cf60e7035e0977c93b58f32ef7abb71..1c2450aff05ff4b30c0150d70830e4a5755a5f29 100644 (file)
@@ -1,28 +1,14 @@
 import {Ref} from '@/types/vueRef/index';
-import { ref } from 'vue';
-export default function useStreamRecorder(render: Ref<boolean>) {
-    let streamRecorder: MediaRecorder;
-    const chunks: Blob[] = [];
+export default function useStreamRender(render: Ref<boolean>) {
 
     // window.AudioContext = window.AudioContext;
     const audioContext = new AudioContext();
     const analyzer = audioContext.createAnalyser();
     analyzer.fftSize = 2048;
+    const xInitial = 24;
+    const xFinal = 640;
     const dataArray = new Uint8Array(analyzer.frequencyBinCount);
 
-    const initRecorder = async () => {
-        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
-        streamRecorder = new MediaRecorder(stream);
-        streamRecorder.ondataavailable = (e: any) => { chunks.push(e.data) }
-        streamRecorder.onstop = (e: any) => {
-            // send audio to BE
-            const audioBlob = new Blob(chunks, { 'type': 'audio/ogg; codecs=opus' });
-        }
-        return {
-            streamRecorder
-        }
-    }
-
     interface AmplitudePath {
         id: string;
         name: string;
@@ -41,8 +27,6 @@ export default function useStreamRecorder(render: Ref<boolean>) {
          return path;
     }
 
-    const xInitial = 24;
-    const xFinal = 640;
 
     function visualize(w: Ref<number>, p: Ref<number>, paths: Ref<any>) {
 
@@ -92,7 +76,6 @@ export default function useStreamRecorder(render: Ref<boolean>) {
     }
 
     return {
-        initRecorder,
         renderStream
     }
 }
similarity index 92%
rename from src/composables/inputItem/useInputAnims.ts
rename to src/core/UI/input/text/textDetails/useAnimations.ts
index d359d889018c5560a8766f7adf998cc33ec6031b..45a1a8298b1ef6ef486bbb52efa27019c6e3d1d9 100644 (file)
@@ -1,7 +1,10 @@
 import AnimeFunc from "@/types/animejs/index";
 import {inject} from "vue";
 import {Ref} from "@/types/vueRef/index";
-export default function useInputAnims() {
+/*
+ * Anime js animations used by input textController
+*/
+export default function useTextInputAnims() {
 
     // imports animejs safely
     let anime: AnimeFunc;
similarity index 78%
rename from src/composables/inputItem/useTextInput.ts
rename to src/core/UI/input/text/useTextRender.ts
index 58f9c4179171dd5f8e351f8d780e01b09b9ae1ff..e84f243efc534cc4520e3ff061e954675e0eb636 100644 (file)
@@ -1,10 +1,13 @@
-import {ref, computed, watch, inject} from 'vue';
-import useInputAnims from "./useInputAnims";
-import useInputRenderer from './useInputRenderer';
-export default function useTextInput(input: any, audioRender: any) {
+import {ref, computed, inject} from 'vue';
+import useTextInputAnims from "./textDetails/useAnimations";
+import { Ref } from "@/types/vueRef/index";
+/*
+ * text rendering logic used by inputController
+*/
+export default function useTextRender(input: Ref<string>) {
 
   const emitter: any = inject("mitt");
-  const {animateSend, verticalShiftInput, inputAppear} = useInputAnims();
+  const {animateSend, verticalShiftInput, inputAppear} = useTextInputAnims();
 
   const inputHeight = ref(42);
   const inputWidth = ref(0);
diff --git a/src/core/UI/input/useInputController.ts b/src/core/UI/input/useInputController.ts
new file mode 100644 (file)
index 0000000..3c510b1
--- /dev/null
@@ -0,0 +1,88 @@
+import {ref, watch, onUnmounted, onMounted } from "vue";
+import useKeyDownHandler from "@/utils/keyDownHandler/useKeyDownHandler";
+import useMediaStream from "@/utils/mediaStream/useMediaStream";
+import useStreamRecord from "./audio/useStreamRecord";
+import useStreamRender from './audio/useStreamRender';
+import useTextRender from './text/useTextRender';
+
+/* 
+* Input controller logic
+* Will render text input by default as user types or
+* if user holds space bar down, audio media-stream 
+* will be rendered & recorded
+*/
+export default function useInputController() {
+  // program ref varaiables
+  const renderAudio = ref(false);
+  const reactiveWidth = ref(10);
+  const pathOffset = ref(10);
+  const paths = ref([]);
+  // audioStream variables
+  let stream: MediaStream;
+  let recorder: MediaRecorder;
+  
+  // use input ref & keydown handler function
+  const { keyDownHandler, input } = useKeyDownHandler();
+  // use text Offset computed prop and & textRender function
+  const { textInputXoffset, renderTextInput } = useTextRender(input);
+  // use stream render and record logic
+  const { renderStream } =  useStreamRender(renderAudio);
+  const { initRecorder } = useStreamRecord()
+
+  // get stream & initialize recorder object on mount
+  onMounted(async () => {
+    stream = await useMediaStream();
+    recorder = initRecorder(stream);
+  })
+
+  // callback function called on key up event
+  function keyupHandler(e: any) {
+    // stop stream recording on space key up
+    if (e.key === " " && renderAudio.value) {
+      console.log("stop recording");
+      recorder.stop();
+      // reset controller ref variables
+      renderAudio.value = false;
+      input.value = "";
+      reactiveWidth.value = 10;
+      pathOffset.value = 10;
+    }
+  }
+
+  // step 1: add window event keyboard listeners
+  window.addEventListener("keydown", keyDownHandler);
+  window.addEventListener('keyup', keyupHandler);
+
+  // step 2: determine whether to render text or audio based one the keyboard input
+  watch(input, (input, prevInput) => {
+    if (prevInput !== "" || prevInput.length > 0) {
+      if (!renderAudio.value) {
+        renderTextInput();
+      }
+      return;
+    }
+    if (input === " " && renderAudio.value === false) {
+      console.log("record");
+      renderAudio.value = true;
+      recorder.start();
+      renderStream(stream, reactiveWidth, pathOffset, paths);
+      return;
+    }           
+    renderTextInput();
+  });
+
+  // remove Event Listeners on component unMount
+  onUnmounted(() => {
+    window.removeEventListener("keydown", keyDownHandler);
+    window.removeEventListener("keyup", keyupHandler);
+  });
+
+  return {
+    input,
+    renderAudio,
+    reactiveWidth,
+    textInputXoffset,
+    paths
+  }
+
+}
\ No newline at end of file
similarity index 99%
rename from src/composables/scrollView/useScrollView.ts
rename to src/core/UI/scrollView/useScrollView.ts
index a94de231555eb686aa0c8d1637969772f587fe76..6d3a5e3bcf7c9a119810d42d5c506a1142872a74 100644 (file)
@@ -1,6 +1,5 @@
 import {ref, computed, onMounted} from "vue";
 export default function useScrollView({ targetId }: {targetId: string}) {
-
     const scroll = ref(0);
     let scrollTarget: HTMLElement | SVGElement | null;
     const targetHeight = ref(0);
diff --git a/src/core/messenger/message/messageDetails/useAnimations.ts b/src/core/messenger/message/messageDetails/useAnimations.ts
new file mode 100644 (file)
index 0000000..d74a827
--- /dev/null
@@ -0,0 +1,46 @@
+import { ref, onMounted } from "vue";
+import { Ref } from "@/types/vueRef/index";
+export default function useMessageItemAnims({
+    mr,
+    tr,
+}: {
+    mr: Ref<string>;
+    tr: Ref<string>;
+}) {
+    const signatureTranslate = ref("");
+    let messageRect: SVGSVGElement & SVGRectElement;
+    let messageText: SVGSVGElement & SVGTextElement;
+
+    onMounted(async () => {
+        messageRect = (mr.value as unknown) as SVGSVGElement & SVGRectElement;
+        messageText = (tr.value as unknown) as SVGSVGElement & SVGTextElement;
+    });
+
+    function adjustMessageRect(): void {
+        // must get dimensions of text box to fit bubble around
+        const padding = 12.5;
+        const textBox = messageText.getBBox();
+        messageRect.setAttribute("x", String(textBox.x - padding));
+        messageRect.setAttribute("y", String(textBox.y - padding));
+        messageRect.setAttribute("width", String(textBox.width + 2 * padding));
+        messageRect.setAttribute("height", String(textBox.height + 2 * padding));
+    }
+
+    function translateMsgSignature(): void {
+        if (messageRect.getAttribute("height") !== null) {
+            const height = Number(messageRect.getAttribute("height"));
+            signatureTranslate.value = `translate(-10 ${height})`;
+        }
+    }
+
+    async function drawMessage() {
+        // ignore lint error: await needed for proper render
+        await adjustMessageRect();
+        translateMsgSignature();
+    }
+
+    return {
+        drawMessage,
+        signatureTranslate,
+    };
+}
diff --git a/src/core/messenger/message/messageDetails/useComputed.ts b/src/core/messenger/message/messageDetails/useComputed.ts
new file mode 100644 (file)
index 0000000..dc4cfaf
--- /dev/null
@@ -0,0 +1,72 @@
+import { computed, onMounted, ref } from "vue";
+export default function useMessageItemComp(m: string, id: string) {
+    const x = ref(0)
+    const paddingLeft = 30;
+    const winW = 350;
+    const messageWidth = ref(0);
+    const messageMarginTop = 75;
+
+    const textFill = computed(() => {
+        switch (m) {
+            case "sf":
+                return "#fff";
+            default:
+                return "#000";
+        }
+    });
+
+    const bubbleFill = computed(() => {
+        switch (m) {
+            case "sf":
+                return "#61b4f4";
+            default:
+                return "#fff";
+        }
+    });
+
+    const setMessageWidthRef = async () => {
+        const msg = await document.getElementById(id);
+        if (msg) {
+            messageWidth.value = msg.getBoundingClientRect().width;
+        }
+    }
+
+    const selfMessageMarginRight = 2.5;
+    const calculateXoffset = async () => {
+        switch (m) {
+            case "sf":
+                x.value = winW - messageWidth.value - selfMessageMarginRight;
+                break;
+            default:
+                x.value = paddingLeft;
+            // to center a message
+            // x = messageMargin + (winW -messageWidth) / 2;
+        }
+    }
+
+    const startingOffset = computed(() => {
+        const messageRenderer = document.getElementById('messageRenderer');
+        if (messageRenderer) {
+            const rect = messageRenderer.getBoundingClientRect();
+            let Y = 600;
+            if (rect.height > 500) {
+                Y = rect.height + messageMarginTop;
+            }
+            return `translate(${x.value} ${Y})`;
+        }
+    });
+
+    onMounted(async () => {
+        // to calculate X offset:
+        // First: set message width ref
+        await setMessageWidthRef();
+        // Then: calculate message X offset
+        calculateXoffset();
+    })
+
+    return {
+        textFill,
+        bubbleFill,
+        startingOffset
+    };
+}
similarity index 84%
rename from src/composables/messageRenderer/useRendererAnims.ts
rename to src/core/messenger/renderView/renderDetails/useAnimations.ts
index 8a2acb96232fea61b0cb1ba274b895a7f8ce10dd..d57e44e469e8c42b2a326445bf92d593cb7d8eec 100644 (file)
@@ -1,12 +1,20 @@
 import { inject } from "vue";
 import AnimeFunc from "@/types/animejs/index";
 import { MessageAnimeFunc } from '@/types/message/index';
-export default function useRendererAnims() {
+
+/**
+ * anime js animations used by message renderer
+ */
+export default function useRendererAnims(): {
+    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) {
@@ -21,9 +29,10 @@ export default function useRendererAnims() {
         }
     }
 
+    // adds new message at the bottom of the list and shifts existing message list
     const shiftAnimate: MessageAnimeFunc = (el, transform, shiftValue, targetList) => {
         anime({
-            targets: el, 
+            targets: el,
             transform: transform.initialTranslate,
             easing: "easeInOutQuad",
             duration: 500,
@@ -45,6 +54,7 @@ export default function useRendererAnims() {
         });
     }
 
+    // stacks message from top to bottom
     const stackAnimate: MessageAnimeFunc = (el, transform) => {
         anime({
             targets: el,
similarity index 68%
rename from src/composables/messageRenderer/useOffsetCalculator.ts
rename to src/core/messenger/renderView/renderDetails/useOffsetCalculator.ts
index b8e2451bf203c1573b8a5fa52fb3f3fce6897d08..c31ba54625a317409881510b21ec072c3070d440 100644 (file)
@@ -1,4 +1,7 @@
 import { ref } from "vue";
+/**
+ * Calculates vertical and horizontal message offsets
+ */
 export default function useOffsetCalculator() {
     const xOffset = ref(0);
     const yOffset = ref(0);
@@ -6,13 +9,13 @@ export default function useOffsetCalculator() {
     let previousMessageHeight = 0;
     const messagePadding = 15;
 
-    function setXoffset(message: HTMLElement): void {
-        const computedQuery = window.getComputedStyle(message)
+    function calculateX(message: HTMLElement): void {
+        const computedQuery = window.getComputedStyle(message);
         const matrix = new WebKitCSSMatrix(computedQuery.webkitTransform);
         xOffset.value = matrix.m41;
     }
 
-    function setYoffset(messageHeight: number): void {
+    function calculateY(messageHeight: number): void {
         if (previousMessageHeight === 0) {
             yOffset.value = firstChildMarginTop;
         } else {
@@ -21,10 +24,10 @@ export default function useOffsetCalculator() {
         previousMessageHeight = messageHeight;
     }
 
-    const calculateMessageOffsets = (msg: HTMLElement) => {
+    const calculateMessageOffsets = (msg: HTMLElement): { x: number; y: number } => {
         const msgRect = msg.getBoundingClientRect();
-        setXoffset(msg);
-        setYoffset(msgRect.height);
+        calculateX(msg);
+        calculateY(msgRect.height);
         const offsets = {
             x: xOffset.value as number,
             y: yOffset.value as number
diff --git a/src/core/messenger/renderView/useRenderView.ts b/src/core/messenger/renderView/useRenderView.ts
new file mode 100644 (file)
index 0000000..5fee90f
--- /dev/null
@@ -0,0 +1,72 @@
+import useRendererAnims from "./renderDetails/useAnimations";
+import useOffsetCalculator from './renderDetails/useOffsetCalculator';
+import { VueTransitionCallback } from '@/types/vue3/vueTransitionCallback/index';
+
+
+/**
+ * renderView component logic
+ * handles rendering of exisiting user messages
+ * as well as incoming messages
+ */
+export default function useRenderView(): {
+    beforeEnter: VueTransitionCallback;
+    enter: VueTransitionCallback;
+    afterEnter: VueTransitionCallback;
+} {
+    // uses offsetCalculator logic and renderer animations
+    const { calculateMessageOffsets } = useOffsetCalculator();
+    const { shiftAnimate, stackAnimate } = useRendererAnims();
+
+    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) => {
+
+        const transform = {
+            initialTranslate: `translate(${messageOffset.x} ${messageOffset.y})`,
+            finalTranslate: `translate(${messageOffset.x} ${messageOffset.y})`
+        }
+        shift ? shiftAnimate(el, transform, shiftOffset, messageList) : stackAnimate(el, transform);
+    }
+
+    // callback called before message enter
+    const beforeEnter: VueTransitionCallback = () => {
+        const queryResult = document.querySelectorAll(".messageList");
+        if (queryResult.length) messageList = queryResult;
+    }
+
+    // callback called on message enter
+    const enter: VueTransitionCallback = (el) => {
+        // query DOM for latest message as soon as it enters
+        if (el) {
+            message = document.getElementById(el.id);
+        }
+    }
+
+    // callback called after message enter
+    const afterEnter: VueTransitionCallback = (el) => {
+        // get message positioning & shift state before animating
+        if (message) {
+            messageOffset = calculateMessageOffsets(message);
+            shift = messageOffset.y > 445 ? true : false;
+        }
+        if (el) {
+            if (shift) {
+                shiftOffset -= el.getBBox().height + messagePadding;
+            }
+            animateMessage(el);
+        }
+    }
+
+    return {
+        beforeEnter,
+        enter,
+        afterEnter
+    };
+}
diff --git a/src/types/vue3/vueTransitionCallback/index.ts b/src/types/vue3/vueTransitionCallback/index.ts
new file mode 100644 (file)
index 0000000..8c631d4
--- /dev/null
@@ -0,0 +1,3 @@
+export type VueTransitionCallback = {
+    (el?: SVGGElement | null): void;
+}
similarity index 93%
rename from src/composables/keyDownHandler/useKeyDownHandler.ts
rename to src/utils/keyDownHandler/useKeyDownHandler.ts
index f91db9ef12bf4da308f0244064be01cd2b455c58..61d5455aa1319a092314ffcc05081c947e86fc3c 100644 (file)
@@ -1,6 +1,6 @@
 import { ref, inject } from "vue";
-import keyboardNameMap from "./keyboardMaps/keyboardNameMap";
-import keyboardCharMap from "./keyboardMaps/keyboardCharMap";
+import keyboardNameMap from "./keyBoardMaps/keyboardNameMap";
+import keyboardCharMap from "./keyBoardMaps/keyboardCharMap";
 // This catches keys from a physical keyboard, a soft keyboard on a tablet, or a
 // scanner attached via USB
 export default function useKeyDownHandler() {
@@ -65,4 +65,4 @@ export default function useKeyDownHandler() {
     keyDownHandler,
     input
   };
-}
+}
\ No newline at end of file
similarity index 80%
rename from src/composables/mediaStream/useMediaStream.ts
rename to src/utils/mediaStream/useMediaStream.ts
index be232a84577668af39f9a7f246fb99786908d1d6..42fc1ee325abd1e47cbdb548b0de189c90e41bb1 100644 (file)
@@ -1,6 +1,4 @@
 export default async function useMediaStream() {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
-   return {
-     stream
-   }
+   return stream;
 }
\ No newline at end of file