]> Repos - mime-chat/commitdiff
message playback anim
authorAndrew Gundersen <gundersena@xavier.edu>
Thu, 11 Mar 2021 21:46:34 +0000 (15:46 -0600)
committerAndrew Gundersen <gundersena@xavier.edu>
Fri, 12 Mar 2021 02:26:47 +0000 (20:26 -0600)
src/background/audio.ts
src/background/session.ts
src/components/inputItem/inputItem.vue
src/components/messageItem.vue

index de1c6888d6810bd16b63dce96b3626fa88ac2067..5b0ef127d5e008ec221d3f5c2e5de09703dbebf0 100644 (file)
@@ -4,6 +4,8 @@
 
 import { sendAudio } from './session'
 import { ipcMain } from "electron";
+import { backgroundMitt } from './emitter';
+
 const portAudio = require('naudiodon');
 
 let ai: typeof portAudio.AudioIO | null = null;
@@ -83,9 +85,14 @@ export function play(input: Buffer): void {
 
     const audio = bufSplit(input, 8192);
 
-    // call this fuction after last audio chunk has been written.
+    // Called on end of write.
     const callback = () => {
-        // TODO: clear portAudio writable buffer on write end.
+
+        // We stop audio playback anim.
+        backgroundMitt.emit('ipc-renderer', {
+            endpoint: 'stop-playback-anim'
+        });
+
     }
 
     write();
index b68229c399aa3ddd3b454d6ffabbcaa006693acd..5948978aad61cee2f08ca6913f1afa1d2c1fd178 100644 (file)
@@ -55,14 +55,18 @@ const onMessage = (message: string): void => {
 
     // check to see if this is a Render Message.
     if (m.content) {
+
         // If there is audio, play it.
         if (m.content.audio) {
             const audioBytes = Buffer.from(m.content.audio as string, 'hex');
+            m.content.audio = true;
             play(audioBytes);
+        } else {
+            m.content.audio = false;
         }
 
         // if there is no unique id, add it.
-        if(!m.uid) m.uid = uuidv4();   
+        if(!m.uid) m.uid = uuidv4();
     }
 
     backgroundMitt.emit('ipc-renderer', {
index 7b14bb4d6b80fb213da59f394c6cb5bd38d3946f..803b6a7d168e5b4cfbd81fddefe884c34b0c2781 100644 (file)
@@ -143,28 +143,22 @@ export default defineComponent({
     .pause {
       opacity: 1;
       &::before {
-        -moz-animation: audio1 1.5s infinite ease-in-out;
-        -o-animation: audio1 1.5s infinite ease-in-out;
-        -webkit-animation: audio1 1.5s infinite ease-in-out;
-        animation: audio1 1.5s infinite ease-in-out;
+        -moz-animation: circle1 1.5s infinite ease-in-out;
+        -o-animation: circle1 1.5s infinite ease-in-out;
+        -webkit-animation: circle1 1.5s infinite ease-in-out;
+        animation: circle1 1.5s infinite ease-in-out;
       }
       &::after {
-        -moz-animation: audio2 2.2s infinite ease-in-out;
-        -o-animation: audio2 2.2s infinite ease-in-out;
-        -webkit-animation: audio2 2.2s infinite ease-in-out;
-        animation: audio2 2.2s infinite ease-in-out;
+        -moz-animation: circle2 2.2s infinite ease-in-out;
+        -o-animation: circle2 2.2s infinite ease-in-out;
+        -webkit-animation: circle2 2.2s infinite ease-in-out;
+        animation: circle2 2.2s infinite ease-in-out;
       }
     }
   }
 }
 
-.animate-audio1 {
-  -moz-animation: audio1 1.5s infinite ease-in-out;
-  -o-animation: audio1 1.5s infinite ease-in-out;
-  -webkit-animation: audio1 1.5s infinite ease-in-out;
-  animation: audio1 1.5s infinite ease-in-out;
-}
-@keyframes audio1 {
+@keyframes circle1 {
   0%,
   100% {
     box-shadow: 0 0 0 0.4em rgba(195, 195, 195, 0.4);
@@ -179,13 +173,8 @@ export default defineComponent({
     box-shadow: 0 0 0 0.25em rgba(195, 195, 195, 0.25);
   }
 }
-.animate-audio2 {
-  -moz-animation: audio2 2.2s infinite ease-in-out;
-  -o-animation: audio2 2.2s infinite ease-in-out;
-  -webkit-animation: audio2 2.2s infinite ease-in-out;
-  animation: audio2 2.2s infinite ease-in-out;
-}
-@keyframes audio2 {
+
+@keyframes circle2 {
   0%,
   100% {
     box-shadow: 0 0 0 0.25em rgba(195, 195, 195, 0.15);
index 22a9f14003acb473373a053ec4c0e3994479d1cb..78d43c59beec59e9000b3b975ec8695ae0a721df 100644 (file)
@@ -50,7 +50,9 @@
         </div>
 
         <!-- Render Crimata icon or friend's initials. -->
-        <div v-if="message.modifier == 'fr'" class="photo">
+        <div v-if="message.modifier == 'fr'" class="photo"
+          :class="{ playing: isPlaying }"
+        >
           {{ message.context[0] }}
         </div>
 
@@ -65,7 +67,7 @@
 
 <script lang='ts'>
 
- import {defineComponent} from 'vue';
+ import {defineComponent, ref, onMounted} from 'vue';
 
  export default defineComponent({
   name: "MessageItem",
         type: Object,
         required: true
       } 
+  },
+
+  setup(props) {
+    let isPlaying = ref(false);
+
+    const onStopPlayback = (e: any) => {
+      window.ipcRenderer.removeAllListeners("stop-playback-anim");
+      isPlaying.value = false
+    }
+
+    onMounted(() => {
+
+      // Turn on audio playback animation if audio.
+      if (props.message.content.audio === true) {
+        window.ipcRenderer.on("stop-playback-anim", onStopPlayback);
+        isPlaying.value = true
+      }
+
+    })
+
+    return {
+      isPlaying
+    }
   }
 
  })
     animation-duration: 0.25s;
   }
 
+  @keyframes appear {
+    from {
+      transform: scale(0.3);
+    }
+    to {
+      transform: scale(1);
+    }
+  }
+
   #aiBubble {
     background-color: white;
   }
     border-radius: 15px;
   }
 
-  @keyframes appear {
-    from {
-      transform: scale(0.3);
+  // Apply for audio message playback.
+  .playing {
+    animation-name: circle1;
+    animation-duration: 2s;
+    animation-iteration-count: infinite;
+  }
+
+  @keyframes circle1 {
+    0%,
+    100% {
+      box-shadow: 0 0 0 0.4em rgba(195, 195, 195, 0.4), 0 0 0 0.25em rgba(195, 195, 195, 0.15);
     }
-    to {
-      transform: scale(1);
+    25% {
+      box-shadow: 0 0 0 0.15em rgba(195, 195, 195, 0.15), 0 0 0 0.4em rgba(195, 195, 195, 0.3);
+    }
+    50% {
+      box-shadow: 0 0 0 0.55em rgba(195, 195, 195, 0.55), 0 0 0 0.15em rgba(195, 195, 195, 0.05);
+    }
+    75% {
+      box-shadow: 0 0 0 0.25em rgba(195, 195, 195, 0.25), 0 0 0 0.55em rgba(195, 195, 195, 0.45);
     }
   }