From 51c4ad8ed7f89f92399537bda0c7d087fc65379a Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Fri, 25 Jun 2021 18:28:29 -0500 Subject: [PATCH] new message anim --- src/account.ts | 3 +- src/messages.ts | 24 ++ src/render/components/bubble.vue | 397 +++++------------- src/render/components/controllers/helpers.ts | 51 ++- .../controllers/inputItem.control.audio.ts | 2 +- .../controllers/inputItem.control.text.ts | 11 +- src/render/components/message.vue | 142 +++++++ src/render/components/messenger.vue | 11 +- src/render/ipc.ts | 2 +- src/render/shared/messages.ts | 40 +- src/session.ts | 49 +-- src/types.ts | 16 +- 12 files changed, 379 insertions(+), 369 deletions(-) create mode 100644 src/messages.ts create mode 100644 src/render/components/message.vue diff --git a/src/account.ts b/src/account.ts index 581da0e..ac53b23 100644 --- a/src/account.ts +++ b/src/account.ts @@ -4,6 +4,7 @@ import { endSession, launchSession } from "@/session"; import { getToken, setToken, setProfile, getProfile, clearStore } from "./store"; import { parseAuthRes } from "./auth"; import { ipcEmit } from "@/composables/useEmitter"; +import { messages } from "@/messages"; export const accountAuth = async (): Promise => { @@ -89,7 +90,7 @@ export const updateAppState = (): void => { ipcEmit("set-profile", profile); - // ipcEmit('messages') etc + ipcEmit("init-messages", messages) } diff --git a/src/messages.ts b/src/messages.ts new file mode 100644 index 0000000..fdd9d15 --- /dev/null +++ b/src/messages.ts @@ -0,0 +1,24 @@ +import { ipcEmit } from "@/composables/useEmitter"; + +export let messages: Message[] = []; + +export const setMessages = (init: {messages: Message[]}) => { + messages = init.messages; + ipcEmit("init-messages", messages); +} + +export const newMessage = (message: Message) => { + messages.push(message); + ipcEmit("add-message", message); +} + +export const annotateMessage = (annotation: Annotation) => { + for (let i in messages) { + if (messages[i].uid == annotation.uid) { + messages[i].context = annotation.context; + ipcEmit("update-message", annotation) + break; + } + } +} + diff --git a/src/render/components/bubble.vue b/src/render/components/bubble.vue index 982cef3..a3ca4f7 100644 --- a/src/render/components/bubble.vue +++ b/src/render/components/bubble.vue @@ -1,19 +1,6 @@ @@ -24,27 +11,16 @@ export default defineComponent({ name: "Bubble", - props: ["text", "context", "type", "position"], - - setup() { + props: ["modifier", "content", "child"], - const seen = ref(false); - /* initialize seen state */ - if (document.visibilityState === "visible") { - seen.value = true; - } else seen.value = false; + setup(props) { onMounted(() => { - if(seen.value) - document.addEventListener("visibilitychange", () => { - seen.value = true - }); - }); return { - seen + }; } @@ -55,277 +31,92 @@ - - +.bubble { + position: relative; + max-width: 66vw; + font-family: "SF Pro Text"; + font-size: 14px; + padding: 10px; + border-radius: 18px; + margin-left: 15px; + margin-right: 15px; + margin-bottom: 4px; + animation-name: bubble-init-anim; + animation-duration: 0.5s; +} + +@keyframes bubble-init-anim { + from { + opacity: 0; + transform: translateY(25px); + } to { + opacity: 1; + transform: translateY(0px); + } +} + +.ai-bubble { + background-color: #FFFFFF; +} + +.client-bubble { + color: white; + background-color: #58C4FD; +} + +.ai-first-child { + border-bottom-left-radius: 9px; +} + +.ai-middle-child { + border-top-left-radius: 9px; + border-bottom-left-radius: 9px; +} + +.ai-last-child { + border-top-left-radius: 9px; +} + +.client-first-child { + border-bottom-right-radius: 9px; +} + +.client-middle-child { + border-top-right-radius: 9px; + border-bottom-right-radius: 9px; +} + +.client-last-child { + border-top-right-radius: 9px; +} + +.ai-none-child, .client-none-child { + border-top-right-radius: 9px; +} + + +// .notify { +// position: absolute; +// width: 12px; +// height: 12px; +// border-radius: 50%; +// background-color: #58D9FF; +// top: -5px; +// left: -5px; +// border: 2px solid #EBEBEB; +// transform: scale(0); + +// animation-name: notify-anim; +// animation-duration: 5s; +// } + +// @keyframes notify-anim { +// 0%, 90% { +// transform: scale(1); +// } +// 100% { +// transform: scale(0); +// } +// } + + \ No newline at end of file diff --git a/src/render/components/controllers/helpers.ts b/src/render/components/controllers/helpers.ts index 23976a8..f20a11a 100644 --- a/src/render/components/controllers/helpers.ts +++ b/src/render/components/controllers/helpers.ts @@ -1,4 +1,4 @@ -import { ref } from "vue"; +import { ref, Ref } from "vue"; import anime from "animejs"; import { v4 as uuidv4 } from 'uuid'; @@ -86,17 +86,40 @@ export function animateAudioInput () { } - -export function newMessage ({ - text=false, - audio=false, - context=false, - uid=uuidv4() -}) { - return { - text: text, - audio: audio, - context: context, - uid: uid - }; +// animate a message annotation. +//! probably could be improved. +export function annotateAnim (uid: string, val: string, contextRef: Ref) { + + anime({ + targets: `#${uid} span`, + opacity: [1, 0], + duration: 500, + easing: 'easeOutExpo' + }) + + .finished.then(() => { + contextRef.value = val; + }) + + .then(() => { + anime({ + targets: `#${uid} span`, + opacity: [0, 1], + duration: 500, + easing: 'easeOutExpo' + }) + }) } + +// Given index and length of content, return message child status. +export function calcChild (index: number, len: number) { + if (len === 1) { + return "none"; + } else if (index === 0) { + return "first-child"; + } else if (index === len - 1) { + return "last-child"; + } else { + return "middle-child"; + } +} \ No newline at end of file diff --git a/src/render/components/controllers/inputItem.control.audio.ts b/src/render/components/controllers/inputItem.control.audio.ts index facf30c..9852e53 100644 --- a/src/render/components/controllers/inputItem.control.audio.ts +++ b/src/render/components/controllers/inputItem.control.audio.ts @@ -1,6 +1,6 @@ import { onMounted, onUnmounted, ref, Ref } from "vue"; import { postMessage } from "@/render/ipc"; -import { newMessage, animateAudioInput } from "./helpers"; +import { animateAudioInput } from "./helpers"; import { invokeReturnAudio, postAudioChunk } from "@/render/ipc"; export default function useAudioInputController (typing: Ref) { diff --git a/src/render/components/controllers/inputItem.control.text.ts b/src/render/components/controllers/inputItem.control.text.ts index 941ae89..51edfe0 100644 --- a/src/render/components/controllers/inputItem.control.text.ts +++ b/src/render/components/controllers/inputItem.control.text.ts @@ -1,6 +1,6 @@ import { Ref, ref, watch, onMounted, onUnmounted } from "vue"; import { postMessage } from "@/render/ipc"; -import { newMessage, animateTextInput } from "./helpers"; +import { animateTextInput } from "./helpers"; export default function useTextInputController(elementX: Ref) { @@ -36,11 +36,12 @@ export default function useTextInputController(elementX: Ref) { if (textInput) { // Send it to the backend for processing. - const message = newMessage({ - text: false - }); + const message: Raw = { + text: textInput.value, + audio: false + }; - // postMessage(message); + postMessage(message); clearInput() } diff --git a/src/render/components/message.vue b/src/render/components/message.vue new file mode 100644 index 0000000..d27df6e --- /dev/null +++ b/src/render/components/message.vue @@ -0,0 +1,142 @@ + + + + + + + diff --git a/src/render/components/messenger.vue b/src/render/components/messenger.vue index 8a7f6ad..619eeff 100644 --- a/src/render/components/messenger.vue +++ b/src/render/components/messenger.vue @@ -7,11 +7,12 @@
-
@@ -22,7 +23,7 @@ import { defineComponent, onMounted, onUnmounted } from "vue"; import InputItem from "@/render/components/inputItem.vue"; import Settings from "@/render/components/settings.vue"; -import Bubble from "@/render/components/bubble.vue"; +import Message from "@/render/components/message.vue"; import { profile } from "@/render/shared/profile"; import { messages } from "@/render/shared/messages"; @@ -33,7 +34,7 @@ export default defineComponent({ components: { InputItem, Settings, - Bubble + Message }, setup() { diff --git a/src/render/ipc.ts b/src/render/ipc.ts index 6601dde..cb14778 100644 --- a/src/render/ipc.ts +++ b/src/render/ipc.ts @@ -41,7 +41,7 @@ export const invokeReturnAudio = async (): Promise => ( * */ -export const postMessage = (payload: Message): void => ( +export const postMessage = (payload: Raw): void => ( post('post-session-send', payload) ); diff --git a/src/render/shared/messages.ts b/src/render/shared/messages.ts index f731584..cd8fa26 100644 --- a/src/render/shared/messages.ts +++ b/src/render/shared/messages.ts @@ -5,26 +5,54 @@ import useScroll from "@/render/composables/useScroll"; export const messages: Ref> = ref([]); export const setMessages: IpcListenerCallback> = (payload) => { - messages.value = payload as Array; + // messages.value = payload as Array; } export const addMessage: IpcListenerCallback = (payload) => { messages.value.push(payload as Message); } -export const updateMessage: IpcListenerCallback = (payload) => { - const message = payload as Message; +export const updateMessage: IpcListenerCallback = (payload) => { + const annotation = payload as Annotation; let targetMessage = messages.value.filter((m: Message) => { - return m.uid = message.uid; + return m.uid === annotation.uid; })[0]; if (targetMessage) { - targetMessage = message; + targetMessage.content = annotation.content; + targetMessage.context = annotation.context; } - } +messages.value = [ +{ + content: ["Welcome Andrew"], + context: "Crimata", + modifier: "ai", + uid: "b5dd3d1b-cef0-4057-aa0f-c72e5c4cd67d" +}, +{ + content: ["show contacts"], + context: "show contacts", + modifier: "client", + uid: "ee2819a3-1125-4881-9942-ca5b3d0ad502" +}] + +setTimeout(() => { + + console.log("updating message"); + + updateMessage({ + content: ["show contacts", "msg"], + context: "show contacts", + uid: "ee2819a3-1125-4881-9942-ca5b3d0ad502" + }); + + + +}, 2000); + export default { messages, setMessages, diff --git a/src/session.ts b/src/session.ts index 01a105c..df0c122 100644 --- a/src/session.ts +++ b/src/session.ts @@ -3,26 +3,27 @@ // import useAudio from "@/audio"; -import { ipcEmit } from "@/composables/useEmitter"; +import { setMessages, newMessage, annotateMessage } from "./messages"; import useWebsockets from "./composables/useWebsockets"; import {config} from "@/config"; -/* data structure of messages that's tied to the UI */ -const uiState: any | null = null; - /* start and stop audio functionality */ // const { initAudio, closeAudio } = useAudio(); -const isInitMessage = (message: any): boolean => { - return true; +const isInitMessage = (object: any): object is Message[] => { + return 'messages' in object; }; -const deauthenticate = (): void => { - console.log('deauthenticating') +const isNewMessage = (object: any): object is Message => { + return 'content' in object; }; -const isAddMessage = (message: any): boolean => { - return true; +const isAnnotation = (object: any): object is Annotation => { + return 'messages' in object; +}; + +const deauthenticate = (): void => { + console.log('deauthenticating') }; /** @@ -30,33 +31,25 @@ const isAddMessage = (message: any): boolean => { * Takes an onMessage callback which we define below. */ - const onMessageCallback = (payload: string) => { - const message = JSON.parse(payload); + const message = JSON.parse(payload); - /* if the platform fails to authenticate, we must back down */ if (message === "CLOSE_AUTH_FAIL") { deauthenticate(); - return; } - ipcEmit("add-message", message) - return - - /* on init, platform sends state, used to init canvas */ - // if (isInitMessage(message)) { - // ipcEmit("init-messages", message) - // } - + else if (isInitMessage(message)) { + setMessages(message); + } - // else if (isAddMessage(message)) { - // ipcEmit("add-messages", message) - // } + else if (isNewMessage(message)) { + newMessage(message); + } - // else { - // ipcEmit("update-messages", message) - // } + else if (isAnnotation(message)) { + annotateMessage(message); + } } diff --git a/src/types.ts b/src/types.ts index 2139a86..7b6d964 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,14 +1,20 @@ interface Message { - text: boolean | string; + modifier: string; + content: string[]; context: boolean | string; - audio: boolean | string; - type: 1 | 2 | 3; uid: string; } -interface ViewMessage extends Message { - child: string; +interface Annotation { + content: string[]; + context: string; + uid: string; +} + +interface Raw { + text: string | boolean; + audio: string | boolean; } interface WindowState { -- 2.43.0