input item enhancements

This commit is contained in:
Andrew Gundersen 2021-03-17 15:51:47 -05:00
commit eff3c808ba
12 changed files with 195 additions and 163 deletions

View file

@ -55,12 +55,7 @@ const onMessage = (messageStr: string): void => {
// Check to see if this is a Render Message. // Check to see if this is a Render Message.
if (m.content) { if (m.content) {
message = renderMessage({ message = renderMessage(m.content.text, m.content.audio, m.context, m.modifier);
text: m.content.text,
audio: m.content.audio,
context: m.context,
modifier: m.modifier,
});
// Play audio if any. // Play audio if any.
if (message.content.audio) { if (message.content.audio) {

View file

@ -1,44 +1,62 @@
import { onMounted } from "vue"; import anime from "animejs";
import { onMounted, onUnmounted, ref, Ref } from "vue";
import useMitt from "@/modules/mitt"; import useMitt from "@/modules/mitt";
import { useIpc } from '@/modules/ipc'; import { useIpc } from '@/modules/ipc';
import keyboardNameMap from "../keyBoardMaps/keyboardNameMap"; import keyboardNameMap from "../keyBoardMaps/keyboardNameMap";
import { renderMessage } from '@/modules/message'; import { renderMessage } from '@/modules/message';
function showRecIcon () {
anime({
targets: '#recIcon',
opacity: [0, 0.75],
scale: [0.0, 1],
duration: 250,
easing: 'linear',
})
}
function hideRecIcon () {
anime({
targets: '#recIcon',
opacity: [0.75, 0],
scale: [1, 0],
duration: 250,
easing: 'linear',
})
}
export default function useAudioInputController (typing: Ref) {
export default function useAudioInputController () {
// For sending messages. // For sending messages.
const { post } = useIpc(); const { post } = useIpc();
const { emitter } = useMitt(); const { emitter } = useMitt();
// Keepp track of when we are recording. // Keepp track of when we are recording.
let recording = false; const recording = 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);
return m.uid;
}
//---Callbacks----------------------------------------------- //---Callbacks-----------------------------------------------
const onKeyDown = (e: KeyboardEvent) => { const onKeyDown = (e: KeyboardEvent) => {
const cmd = keyboardNameMap[e.keyCode]; const cmd = keyboardNameMap[e.keyCode];
// console.log(cmd)
// Start recording on space bar. // Start recording on space bar.
if (cmd == "SPACE" && !recording) { if (cmd == "SPACE" && !recording.value && !typing.value) {
post('update-recorder', { post('update-recorder', {
isRecording: true, isRecording: true,
uid: null uid: null
}); });
recording = true; showRecIcon()
recording.value = true;
console.log("Recording...")
} }
@ -48,17 +66,20 @@ export default function useAudioInputController () {
const cmd = keyboardNameMap[e.keyCode]; const cmd = keyboardNameMap[e.keyCode];
// Stop recording on space up. // Stop recording on space up.
if (cmd == "SPACE" && recording) { if (cmd == "SPACE" && recording.value) {
// Render audio immediately. // Render audio immediately.
const uid = render("", "", "", "sf"); const message = renderMessage("", "", "", "sf")
emitter.emit("self-message", message);
post('update-recorder', { post('update-recorder', {
isRecording: false, isRecording: false,
uid: uid uid: message.uid
}); });
recording = false; hideRecIcon()
recording.value = false;
console.log("Stopping record...")
} }
@ -71,6 +92,12 @@ export default function useAudioInputController () {
window.addEventListener("keyup", onKeyUp); window.addEventListener("keyup", onKeyUp);
}) })
onUnmounted(() => {
window.removeEventListener("keydown", onKeyDown);
window.removeEventListener("keyup", onKeyUp);
});
return { return {
recording recording
} }

View file

@ -1,18 +1,13 @@
import anime from "animejs"; import anime from "animejs";
import useMitt from "@/modules/mitt"; import useMitt from "@/modules/mitt";
import { useIpc } from '@/modules/ipc'; import { useIpc } from '@/modules/ipc';
import { Ref, watch, onMounted } from "vue"; import { Ref, ref, watch, onMounted, onUnmounted } from "vue";
import keyboardNameMap from "../keyBoardMaps/keyboardNameMap"; import keyboardNameMap from "../keyBoardMaps/keyboardNameMap";
import { clientMessage, renderMessage } from '@/modules/message'; import { clientMessage, renderMessage } from '@/modules/message';
// Post a message to the backend.
const { post } = useIpc();
//---Animations----------------------------------------------- //---Animations-----------------------------------------------
let side = "right"; // Side of parent we are on. let side = "right"; // Side of parent we are on.
let visible = false; // Whether textInput is visible.
function showTextInput () { function showTextInput () {
const t1 = (side === "right") ? 50 : -70; const t1 = (side === "right") ? 50 : -70;
@ -27,7 +22,6 @@ function showTextInput () {
easing: 'easeOutExpo', easing: 'easeOutExpo',
}) })
visible = true
} }
function hideTextInput() { function hideTextInput() {
@ -35,14 +29,13 @@ function hideTextInput() {
anime({ anime({
targets: '#textInput', targets: '#textInput',
opacity: 0, opacity: [1, 0],
translateX: t, translateX: t,
scale: 0.3, scale: 0.3,
duration: 500, duration: 500,
easing: 'easeOutExpo', easing: 'easeOutExpo',
}) })
visible = false
} }
function switchSide(currentSide: string) { function switchSide(currentSide: string) {
@ -63,27 +56,29 @@ function switchSide(currentSide: string) {
export default function useTextInputController(elementX: Ref) { export default function useTextInputController(elementX: Ref) {
let textInput: HTMLInputElement | null; let textInput: HTMLInputElement | null;
let length: number;
// For sending messages.
const { post } = useIpc(); const { post } = useIpc();
const { emitter } = useMitt(); const { emitter } = useMitt();
// Keep track of first key press.
let firstKey = true; let firstKey = true;
const typing = ref(false);
// Clear text input. // Prep inputItem for typing.
const clearInput = () => { const prepInput = () => {
if (textInput) textInput.value = ""; showTextInput()
hideTextInput() typing.value = true
firstKey = true;
} }
// Utility function to render message. // Clear and hide inputItem after done typing.
const render = (text: string, audio: boolean | string, context: string, modifier: string): string => { const clearInput = () => {
const m = renderMessage({ text, audio, context, modifier });
emitter.emit("self-message", m); if (textInput) {
return m.uid; textInput.value = "";
textInput.blur();
}
hideTextInput()
firstKey = true;
typing.value = false;
} }
// Send a message and clean up after. // Send a message and clean up after.
@ -91,50 +86,53 @@ export default function useTextInputController(elementX: Ref) {
if (textInput) { if (textInput) {
// Render message // Render message
const uid = render(textInput.value, false, "", "sf"); const message = renderMessage(textInput.value, false, "", "sf")
emitter.emit("self-message", message);
// Send it to the backend for processing. // Send it to the backend for processing.
const clientM = clientMessage(textInput.value, false, uid); const clientM = clientMessage(textInput.value, false, message.uid);
post('client-message', clientM); post('client-message', clientM);
clearInput()
} }
} }
//---Callbacks----------------------------------------------- //---Callbacks-----------------------------------------------
const onKeyDown = (e: KeyboardEvent) => { const onKeyDown = (e: KeyboardEvent) => {
const key = keyboardNameMap[e.keyCode]
console.log(key)
if (textInput) { if (textInput) {
const key = keyboardNameMap[e.keyCode]
// Reveal textInput on first key press. // First-key handler.
if (firstKey) { if (firstKey) {
if (key == "SPACE") return
// Handle for space bar prepInput()
if (key == "SPACE") {
return
}
showTextInput()
firstKey = false
} }
textInput.focus(); textInput.focus();
// Close input when no text or on ESC.
if (textInput.value == "" && !firstKey) { if (textInput.value == "" && !firstKey) {
clearInput() clearInput()
return
} }
if (key == "ENTER") { if (key === "ESCAPE") {
clearInput()
return
}
// Close and send on enter.
if (key === "ENTER") {
if (textInput.value) { if (textInput.value) {
sendMessage() sendMessage()
clearInput() return
} }
} }
if (key == "ESCAPE") { if (firstKey) firstKey = false
clearInput()
}
} }
} }
@ -166,8 +164,12 @@ export default function useTextInputController(elementX: Ref) {
window.addEventListener("keydown", onKeyDown); window.addEventListener("keydown", onKeyDown);
}) })
onUnmounted(() => {
window.removeEventListener("keydown", onKeyDown);
});
return { return {
typing
} }
} }

View file

@ -7,14 +7,9 @@
> >
AG AG
<!-- Show audio input on spacebar --> <!-- Recording animation on space bar -->
<AudioInput />
<span v-if="recording" class="play"></span> <span v-if="recording" class="play"></span>
<span v-if="recording" class="pause"> <span v-if="recording" class="pause"></span>
<div class="rec-icon"></div>
</span>
<!-- Show text input on key-down --> <!-- Show text input on key-down -->
<TextInput /> <TextInput />
@ -43,12 +38,19 @@ export default defineComponent({
}, },
setup() { setup() {
// Initial position.
const xStart = 15;
const yStart = window.innerHeight - 200;
// Calculate position of inputItem on drag. // Calculate position of inputItem on drag.
const { elementX, elementY } = draggify({ elementId: "inputItem" }); const { elementX, elementY } = draggify(
{ elementId: "inputItem" },
{ x: xStart, y: yStart }
);
// Controllers for text and audio. // Controllers for text and audio.
useTextInputController(elementX) const { typing } = useTextInputController(elementX)
const { recording } = useAudioInputController() const { recording } = useAudioInputController(typing)
return { return {
elementX, elementX,
@ -64,8 +66,6 @@ export default defineComponent({
.input-item { .input-item {
position: absolute; position: absolute;
opacity: 1.0;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -80,7 +80,8 @@ export default defineComponent({
// border: 4px solid #C6C6C6; // border: 4px solid #C6C6C6;
border-radius: 20px; border-radius: 20px;
background-color: #EBEBEB; // Set opacity here to not affect child.
background-color: rgba(235, 235, 235, 0.75);
cursor: pointer; cursor: pointer;

View file

@ -8,7 +8,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, ref, watch } from "vue"; import { defineComponent } from "vue";
export default defineComponent({ export default defineComponent({
name: "TextInput", name: "TextInput",
@ -46,15 +46,4 @@ export default defineComponent({
} }
@keyframes appear {
from {
opacity: 0;
transform: translateX(50px) scale(0.3);
}
to {
opacity: 1;
transform: translateX(110px) scale(1.0);
}
}
</style> </style>

View file

@ -30,7 +30,7 @@ function calcPosition (elementPosition: number, percent: number,
return elementPosition return elementPosition
} }
export default function draggify(input: { elementId: string }) { export default function draggify(input: { elementId: string }, initPosition: { x: number; y: number}) {
let element: HTMLElement | null; let element: HTMLElement | null;
@ -113,8 +113,8 @@ export default function draggify(input: { elementId: string }) {
}); });
// Initialize the coordinants. // Initialize the coordinants.
elementX.value = 15; elementX.value = initPosition.x;
elementY.value = 300; elementY.value = initPosition.y;
// remove event listeners on component dismount. // remove event listeners on component dismount.
onUnmounted(() => { onUnmounted(() => {

View file

@ -1,27 +1,20 @@
import { RenderMessage, ClientMessage } from "@/types/message/index"; import { RenderMessage, ClientMessage } from "@/types/message/index";
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
interface RenderParams {
text: string;
audio: boolean | string;
context: string;
modifier: string;
}
function getTimeStamp(): number { function getTimeStamp(): number {
const currentdate = new Date(); const currentdate = new Date();
return currentdate.getTime(); return currentdate.getTime();
} }
// Create a RenderMessage object. // Create a RenderMessage object.
export const renderMessage = (params: RenderParams): RenderMessage => ( export const renderMessage = (text: boolean | string, audio: boolean | string, context: string, modifier: string): RenderMessage => (
{ {
content: { content: {
text: params.text, text: text,
audio: params.audio audio: audio
}, },
context: params.context, context: context,
modifier: params.modifier, modifier: modifier,
time: getTimeStamp(), time: getTimeStamp(),
uid: uuidv4(), uid: uuidv4(),
isChild: "none" isChild: "none"

View file

@ -66,13 +66,16 @@ export default function useMessages() {
updateScrollRef() updateScrollRef()
// update message if in the map. // update message if in the map.
const m = messages.value.get(a.uid) const message = messages.value.get(a.uid)
m.context = a.context message.context = a.context
m.text = a.text message.content.text = a.text
setTimeout(adjustScroll, 10); setTimeout(adjustScroll, 10);
return m console.log(`Annotation: ${a.text}`)
console.log(`Annotation: ${a.context}`)
return message
} }
const saveMessages = () => { const saveMessages = () => {

View file

@ -13,5 +13,3 @@ export default function useMitt() {
emitter emitter
} }
} }

View file

@ -5,7 +5,7 @@ export interface UserCreds {
export interface RenderMessage { export interface RenderMessage {
content: { content: {
text: string; text: boolean | string;
audio: boolean | string; audio: boolean | string;
}; };
context: string; context: string;

View file

@ -2,6 +2,8 @@
<InputItem /> <InputItem />
<Settings /> <Settings />
<div id="recIcon" />
<!-- List of message bubbles. --> <!-- List of message bubbles. -->
<div id="messenger"> <div id="messenger">
<MessageItem v-for="message in messages" :message="message[1]" :key="message[0]" /> <MessageItem v-for="message in messages" :message="message[1]" :key="message[0]" />
@ -109,4 +111,26 @@ export default defineComponent({
#messenger::-webkit-scrollbar { #messenger::-webkit-scrollbar {
display: none; display: none;
} }
#recIcon {
position: fixed;
right: 0;
opacity: 0;
transform: scale(0.0);
margin-top: 24px;
margin-right: 66px;
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #FF3B3B;
z-index: 2;
}
</style> </style>