From a6ebab0dea735a3c55f85623d8a82a3a0ab8428f Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Wed, 17 Mar 2021 09:32:32 -0500 Subject: [PATCH] improvments --- .../inputItem/controllers/audioCtrl.ts | 78 ++++++++ .../inputItem/controllers/textCtrl.ts | 173 ++++++++++++++++ src/components/inputItem/inputController.ts | 189 ------------------ src/components/inputItem/inputItem.vue | 39 ++-- src/components/inputItem/menu.vue | 70 ------- src/components/inputItem/menuController.ts | 22 -- src/components/inputItem/textInput.vue | 60 +++--- src/modules/draggify.ts | 4 +- 8 files changed, 303 insertions(+), 332 deletions(-) create mode 100644 src/components/inputItem/controllers/audioCtrl.ts create mode 100644 src/components/inputItem/controllers/textCtrl.ts delete mode 100644 src/components/inputItem/inputController.ts delete mode 100644 src/components/inputItem/menu.vue delete mode 100644 src/components/inputItem/menuController.ts diff --git a/src/components/inputItem/controllers/audioCtrl.ts b/src/components/inputItem/controllers/audioCtrl.ts new file mode 100644 index 0000000..723d31a --- /dev/null +++ b/src/components/inputItem/controllers/audioCtrl.ts @@ -0,0 +1,78 @@ +import { onMounted } from "vue"; +import useMitt from "@/modules/mitt"; +import { useIpc } from '@/modules/ipc'; +import keyboardNameMap from "../keyBoardMaps/keyboardNameMap"; +import { renderMessage } from '@/modules/message'; + + + + + + +export default function useAudioInputController () { + + // For sending messages. + const { post } = useIpc(); + const { emitter } = useMitt(); + + // Keepp track of when we are recording. + let recording = false; + + // Utility function to render message. + const render = (text: string, audio: boolean | string, context: string, modifier: string): string => { + const m = renderMessage({ text, audio, context, modifier }); + emitter.emit("self-message", m); + return m.uid; + } + + //---Callbacks----------------------------------------------- + + const onKeyDown = (e: KeyboardEvent) => { + const cmd = keyboardNameMap[e.keyCode]; + + // Start recording on space bar. + if (cmd == "SPACE" && !recording) { + + post('update-recorder', { + isRecording: true, + uid: null + }); + + recording = true; + + } + + } + + const onKeyUp = (e: KeyboardEvent) => { + const cmd = keyboardNameMap[e.keyCode]; + + // Stop recording on space up. + if (cmd == "SPACE" && recording) { + + // Render audio immediately. + const uid = render("", "", "", "sf"); + + post('update-recorder', { + isRecording: false, + uid: uid + }); + + recording = false; + + } + + } + + //----------------------------------------------------------- + + onMounted(() => { + window.addEventListener("keydown", onKeyDown); + window.addEventListener("keyup", onKeyUp); + }) + + return { + recording + } + +} diff --git a/src/components/inputItem/controllers/textCtrl.ts b/src/components/inputItem/controllers/textCtrl.ts new file mode 100644 index 0000000..0955096 --- /dev/null +++ b/src/components/inputItem/controllers/textCtrl.ts @@ -0,0 +1,173 @@ +import anime from "animejs"; +import useMitt from "@/modules/mitt"; +import { useIpc } from '@/modules/ipc'; +import { Ref, watch, onMounted } from "vue"; +import keyboardNameMap from "../keyBoardMaps/keyboardNameMap"; +import { clientMessage, renderMessage } from '@/modules/message'; + +// Post a message to the backend. +const { post } = useIpc(); + + +//---Animations----------------------------------------------- + +let side = "right"; // Side of parent we are on. +let visible = false; // Whether textInput is visible. + +function showTextInput () { + let t1 = (side === "right") ? 50 : -70; + let t2 = (side === "right") ? 110 : -130; + + anime({ + targets: '#textInput', + opacity: [0, 1], + translateX: [t1, t2], + scale: [0.3, 1], + duration: 500, + easing: 'easeOutExpo', + }) + + visible = true +} + +function hideTextInput() { + let t = (side === "right") ? 50 : -80; + + anime({ + targets: '#textInput', + opacity: 0, + translateX: t, + scale: 0.3, + duration: 500, + easing: 'easeOutExpo', + }) + + visible = false +} + +function switchSide(currentSide: string) { + let t = (currentSide === "right") ? -130 : 110; + + anime({ + targets: '#textInput', + translateX: t, + duration: 500, + easing: 'easeOutExpo', + }) + +} + +//------------------------------------------------------------ + + +export default function useTextInputController(elementX: Ref) { + let textInput: HTMLInputElement | null; + + let length: number; + + // For sending messages. + const { post } = useIpc(); + const { emitter } = useMitt(); + + // Keep track of first key press. + let firstKey = true; + + // Clear text input. + const clearInput = () => { + if (textInput) textInput.value = ""; + hideTextInput() + firstKey = true; + } + + // Utility function to render message. + const render = (text: string, audio: boolean | string, context: string, modifier: string): string => { + const m = renderMessage({ text, audio, context, modifier }); + emitter.emit("self-message", m); + return m.uid; + } + + // Send a message and clean up after. + const sendMessage = () => { + if (textInput) { + + // Render message + const uid = render(textInput.value, false, "", "sf"); + + // Send it to the backend for processing. + const clientM = clientMessage(textInput.value, false, uid); + post('client-message', clientM); + } + } + + //---Callbacks----------------------------------------------- + + const onKeyDown = (e: KeyboardEvent) => { + + if (textInput) { + const key = keyboardNameMap[e.keyCode] + + // Reveal textInput on first key press. + if (firstKey) { + + // Handle for space bar + if (key == "SPACE") { + return + } + + showTextInput() + firstKey = false + } + + textInput.focus(); + + if (textInput.value == "" && !firstKey) { + clearInput() + } + + if (key == "ENTER") { + if (textInput.value) { + sendMessage() + clearInput() + } + } + + if (key == "ESCAPE") { + clearInput() + + } + } + } + + //----------------------------------------------------------- + + // Watch parent position and update side. + watch(elementX, (elementX, previous) => { + const winW = window.innerWidth + + // Logic depends on the side we are on. + if (side === "right") { + if (winW - elementX < 230) { + switchSide(side) + side = "left" + } + } + + else { + if (winW - elementX > 230) { + switchSide(side) + side = "right" + } + } + + }); + + onMounted(() => { + textInput = document.getElementById("textInput") as HTMLInputElement; + window.addEventListener("keydown", onKeyDown); + }) + + return { + + } + +} diff --git a/src/components/inputItem/inputController.ts b/src/components/inputItem/inputController.ts deleted file mode 100644 index 0ef68ee..0000000 --- a/src/components/inputItem/inputController.ts +++ /dev/null @@ -1,189 +0,0 @@ -/* -* Main logic used by inputItem component. -* Will visualize text input by default as user types. -* If user holds space bar down, input audio stream will -* be recorded and sent to the backend for analysis. -*/ - -import { ref, watch, onUnmounted, onMounted } from "vue"; -import useMitt from "@/modules/mitt"; -import { useIpc } from '@/modules/ipc'; -import keyboardNameMap from "./keyBoardMaps/keyboardNameMap"; -import keyboardCharMap from "./keyBoardMaps/keyboardCharMap"; -import anime from "animejs"; -import { clientMessage, renderMessage } from '@/modules/message'; - -let textInput: HTMLInputElement | null; - -// Animation functions for text input element. -function expandInput() { - anime({ - targets: textInput, - width: ['0px', '150px'], - duration: 500, - easing: 'easeOutExpo', - }) -} - -function retractInput() { - anime({ - targets: textInput, - width: ['150px', '0px'], - duration: 500, - easing: 'easeOutExpo', - begin: function() { - if (textInput) textInput.blur(); - } - }) -} - -export default function useInputController() { - - const { emitter } = useMitt(); - const { post } = useIpc(); - const isRecording = ref(false); - const isTyping = ref(false); - const input = ref(""); - const capsLock = ref(false); - - // Utility function to render message. - const render = (text: string, audio: boolean | string, context: string, modifier: string): string => { - const m = renderMessage({ text, audio, context, modifier }); - emitter.emit("self-message", m); - console.log(m.time) - return m.uid; - } - - // send message on ENTER. - const onEnter = () => { - - if (input.value) { - - // Render the message immediately and get its unique id. - const uid = render(input.value, false, "", "sf"); - - // Then send it to the backend for processing. - const clientM = clientMessage(input.value, false, uid); - post('client-message', clientM); - - // Reset the text input. - if (textInput) textInput.value = ''; - input.value = " "; - } - - } - - // update input on keydown event & listen for special commands. - const onKeyDown = (e: KeyboardEvent) => { - if (textInput) { - textInput.focus(); - textInput.value = input.value; - } - - // keyboardCharMap is an array of arrays, with each inner - // array having 2 columns - un-shifted, and shifted values. - // iCol = 0 is the un-shifted value, while iCol=1 is the shifted value. - // See the "keyboardCharMap" module for possible keys. - // MODIFY keyboardCharMap to suit your needs if you want - // more/less/different characters to be considered "printable". - let iCol = 0; - if (e.shiftKey || capsLock.value) { - iCol = 1; - } - - const ch = keyboardCharMap[e.keyCode][iCol]; - - // Optionally do things with non-printables, - // like CR, ESC, Backspace, LF, Tab, Arrows, F1-F24, etc. - // See the arrary "keyboardNameMap" module for possible keys. - const cmd = keyboardNameMap[e.keyCode]; - - switch (cmd) { - case "ENTER": - onEnter(); - break; - case "BACK_SPACE": - input.value = input.value.slice(0, -1); - break; - case "CAPS_LOCK": - capsLock.value = true; - break; - case "ESCAPE": - if (textInput) textInput.value = '' - input.value = ""; - break; - default: - input.value += ch; - input.value.trim(); - break; - } - - } - - // stop stream recording and render audio message on space key up event. - const onKeyUp = (e: KeyboardEvent) => { - if (e.key === " " && isRecording.value) { - - isRecording.value = false; - - // // Render the message immediately and get its unique id. - const uid = render("", "", "", "sf"); - // Notify main process to stop recording and send send audio to backend for analysis. - post('update-recorder', { - isRecording: isRecording.value, - uid - }); - - // Reset input. - input.value = '' - } - else if (e.code === "CapsLock") { - capsLock.value = false; - } - } - - onMounted(() => { - textInput = document.getElementById('textInput') as HTMLInputElement; - // add window event keyboard listeners - window.addEventListener("keydown", onKeyDown); - window.addEventListener('keyup', onKeyUp); - }) - - onUnmounted(() => { - window.removeEventListener("keydown", onKeyDown); - window.removeEventListener("keyup", onKeyUp); - }); - - // watch keyboard input & update inputItem state. - watch(input, (input, prevInput) => { - if (isTyping.value && input.length === 0) { - retractInput(); - } - - // Do nothing if user is typing. - if (prevInput !== "" || prevInput.length > 0) { - return; - } - - // Begin stream recording on space bar. - if (input === " " && isRecording.value === false) { - isTyping.value = false; - isRecording.value = true; - // tell main process to begin stream recording. - post('update-recorder', { - isRecording: isRecording.value, - uid: null - }); - return; - } - - isTyping.value = true; - expandInput() - }); - - return { - isRecording, - isTyping - } - -} diff --git a/src/components/inputItem/inputItem.vue b/src/components/inputItem/inputItem.vue index ff367dc..052e9dd 100644 --- a/src/components/inputItem/inputItem.vue +++ b/src/components/inputItem/inputItem.vue @@ -2,22 +2,25 @@
AG - - - + + + + + +
- + - +
@@ -26,8 +29,12 @@ import { defineComponent } from "vue"; import draggify from "@/modules/draggify"; -import useInputController from "./inputController"; + import TextInput from "@/components/inputItem/textInput.vue" +import useTextInputController from + "@/components/inputItem/controllers/textCtrl" +import useAudioInputController from + "@/components/inputItem/controllers/audioCtrl" export default defineComponent({ name: "InputItem", @@ -39,14 +46,14 @@ export default defineComponent({ // Calculate position of inputItem on drag. const { elementX, elementY } = draggify({ elementId: "inputItem" }); - // determine whether the user is typing or recording. - const { isRecording, isTyping } = useInputController(); + // Controllers for text and audio. + useTextInputController(elementX) + const { recording } = useAudioInputController() return { elementX, elementY, - isRecording, - isTyping, + recording }; }, }); @@ -57,6 +64,8 @@ export default defineComponent({ .input-item { position: absolute; + opacity: 1.0; + display: flex; align-items: center; justify-content: center; @@ -66,12 +75,12 @@ export default defineComponent({ width: 40px; height: 40px; - border: 4px solid #C6C6C6; - border-radius: 24px; - z-index: 3; - background-color: white; + // border: 4px solid #C6C6C6; + border-radius: 20px; + + background-color: #EBEBEB; cursor: pointer; diff --git a/src/components/inputItem/menu.vue b/src/components/inputItem/menu.vue deleted file mode 100644 index 3ecda9b..0000000 --- a/src/components/inputItem/menu.vue +++ /dev/null @@ -1,70 +0,0 @@ - - - - - diff --git a/src/components/inputItem/menuController.ts b/src/components/inputItem/menuController.ts deleted file mode 100644 index 8868281..0000000 --- a/src/components/inputItem/menuController.ts +++ /dev/null @@ -1,22 +0,0 @@ - - - - -export default function useMenu() { - - const submitSuggestion = (suggestion: string) => { - console.log(`Submit...${suggestion}`) - - // // Render the message immediately and get its unique id. - // const uid = render(suggestion, false, "", "sf"); - - // // Then send it to the backend for processing. - // const clientM = clientMessage(suggestion, false, uid); - // post('client-message', clientM); - } - - return { - submitSuggestion - } - -} \ No newline at end of file diff --git a/src/components/inputItem/textInput.vue b/src/components/inputItem/textInput.vue index ba9dd3f..d9c2dad 100644 --- a/src/components/inputItem/textInput.vue +++ b/src/components/inputItem/textInput.vue @@ -1,11 +1,9 @@ @@ -15,54 +13,48 @@ import { defineComponent, ref, watch } from "vue"; export default defineComponent({ name: "TextInput", - data: { - - // Where is avatar? - position: Number - - }, - - setup(data) { - - const side = ref("") - side.value = "left" - - // Watch the position of parent. - // watch(data.position, (position, prevPosition) => { - // console.log("position moved") - // }) - - return { - side - } - } }) \ No newline at end of file diff --git a/src/modules/draggify.ts b/src/modules/draggify.ts index b357ddf..be9c0de 100644 --- a/src/modules/draggify.ts +++ b/src/modules/draggify.ts @@ -113,8 +113,8 @@ export default function draggify(input: { elementId: string }) { }); // Initialize the coordinants. - elementX.value = 20; - elementY.value = 200 - 38 - 20; + elementX.value = 15; + elementY.value = 300; // remove event listeners on component dismount. onUnmounted(() => { -- 2.43.0