This commit is contained in:
Andrew Gundersen 2021-03-30 10:48:45 -05:00
commit 81662942a2
24 changed files with 506 additions and 402 deletions

View file

@ -49,11 +49,11 @@ export default function useAudioInputController (typing: Ref) {
// Start recording on space bar.
if (cmd == "SPACE" && !recording.value && !typing.value) {
post('start-recording', "");
console.log("INPT:Starting record.")
post("start-recording", "");
showRecIcon()
recording.value = true;
console.log("Recording...")
}
@ -70,7 +70,8 @@ export default function useAudioInputController (typing: Ref) {
emitter.emit("self-message", message);
// Stop recording and get audio from recorder.
const audio = await invoke('stop-recording', "");
console.log("INPT:Stopping record.")
const audio = await invoke("stop-recording", "");
// Send message to the backend for processing.
const clientM = clientMessage("", audio, message.uid);
@ -78,7 +79,6 @@ export default function useAudioInputController (typing: Ref) {
hideRecIcon()
recording.value = false;
console.log("Stopping record...")
}

View file

@ -23,29 +23,27 @@
<script lang="ts">
import { defineComponent, ref, onMounted, onUnmounted } from "vue";
import { defineComponent } from "vue";
import draggify from "@/modules/draggify";
import TextInput from "@/components/inputItem/textInput.vue";
import TextInput from "@/components/textInput.vue";
import useTextInputController from
"@/components/inputItem/controllers/textCtrl";
"@/components/controllers/textCtrl";
import useAudioInputController from
"@/components/inputItem/controllers/audioCtrl";
"@/components/controllers/audioCtrl";
export default defineComponent({
name: "InputItem",
props: ["initials"],
components: {
TextInput
},
setup() {
// Mark input item with user's initials.
const initials = ref("")
// Set initials.
const initialData = window.localStorage.getItem("initials")
if (initialData) initials.value = initialData
// Default values for position.
const xStart = 15;
const yStart = window.innerHeight - 200;
@ -57,25 +55,10 @@ export default defineComponent({
const { typing } = useTextInputController(elementX)
const { recording } = useAudioInputController(typing)
// Update profile functionality.
const onUpdateProfile = (_event: any, payload: any) => {
initials.value = payload.message.first[0] + payload.message.last[0]
window.localStorage.setItem("initials", initials.value)
}
onMounted(() => {
window.ipcRenderer.on("update-profile", onUpdateProfile);
})
onUnmounted(() => {
window.ipcRenderer.removeAllListeners("update-profile");
})
return {
elementX,
elementY,
recording,
initials
recording
};
},
});

View file

@ -29,16 +29,14 @@
</form>
<!-- back to login button: position: fixed -->
<button class="createAccountButton button" @click.prevent="switchView">Create account</button>
<!-- <button class="createAccountButton button" @click.prevent="switchView">Create account</button> -->
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
import { useAuth } from "@/modules/auth";
import { useIpc } from "@/modules/ipc";
import useMessages from "@/modules/messages";
import { authRequest } from '@/modules/message';
import { authRequest } from '@/modules/message';
export default defineComponent({
name: "Login",
@ -46,11 +44,9 @@ export default defineComponent({
setup() {
const { post } = useIpc();
const { setToken } = useAuth();
const { resetMessages } = useMessages();
let usr = ref("");
let pwd = ref("");
const usr = ref("");
const pwd = ref("");
// Submit login credentials to the backend.
const submitForm = () => {

View file

@ -9,6 +9,14 @@
<!-- Three types of messages: self (sf), friend (fr), and crimata (ai) -->
<!-- !denoted by the modifier attribute -->
<!-- Shows when a new session is created with Crimata. -->
<div
v-if="message.context === 'launch'"
class="divider"
>
<div>new session</div>
</div>
<!-- Includes bubble and context. -->
<div
:id="`${message.modifier}MessageBox`"
@ -21,6 +29,12 @@
:class="`${message.modifier}-${message.isChild}ChildBubble`"
:id="`${message.modifier}Bubble`"
>
<!-- Notification dot for new messages. -->
<div v-if="notify === true"
class="notify"
/>
<!-- Show loader when audio is being transcribed. -->
<div
v-if="message.content.text === ''"
@ -73,21 +87,60 @@
<script lang='ts'>
import {defineComponent, ref, onMounted} from 'vue';
import { RenderMessage } from "@/types/message/index";
export default defineComponent({
name: "MessageItem",
props: {
message: {
type: Object,
required: true
}
},
props: ["message"],
setup(props) {
let addListener = false;
const notify = ref(false)
const isPlaying = ref(false);
if (!props.message.seen) {
// newMessages always render with blue dot.
if (props.message.newMessage) {
console.log("MSG:New message, notifying.")
props.message.seen = true;
notify.value = true;
}
else {
// Do nothing if window is visible on setup.
if (document.visibilityState === "visible") {
props.message.seen = true;
}
// We must listen for window visible event.
else {
console.log("MSG:Unseen, adding listener.")
addListener = true;
}
}
}
// Callback for window visibilityState.
const onVisibilityChange = (event: any) => {
if (document.visibilityState === "visible") {
console.log("MSG:Window visible, notifying.")
props.message.seen = true;
notify.value = true; // triggers blue dot anim.
// Once complete we can remove.
document.removeEventListener("visibilitychange", onVisibilityChange)
}
}
const onStopPlayback = (e: any) => {
window.ipcRenderer.removeAllListeners("stop-playback-anim");
isPlaying.value = false
@ -95,6 +148,11 @@
onMounted(() => {
// Listen for window focus event.
if (addListener) {
document.addEventListener("visibilitychange", onVisibilityChange)
}
// Turn on audio playback animation if audio.
if (props.message.content.audio === true) {
window.ipcRenderer.on("stop-playback-anim", onStopPlayback);
@ -104,6 +162,7 @@
})
return {
notify,
isPlaying
}
}
@ -133,6 +192,20 @@
margin-bottom: 18px;
}
.divider {
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
font-family: "SF Compact Display";
font-size: 12px;
font-weight: bold;
color: #9B9B9B;
margin-bottom: 18px;
}
.firstChildMessage {
padding-bottom: 2px;
}
@ -183,6 +256,8 @@
}
.bubble {
position: relative;
max-width: 66vw;
display: flex;
@ -244,6 +319,30 @@
border-top-left-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);
}
}
.context {
display: flex;
align-items: center;

View file

@ -1,51 +1,66 @@
<template>
<InputItem />
<InputItem :initials="profile.initials"/>
<Settings />
<div id="recIcon" />
<!-- List of message bubbles. -->
<div id="messenger">
<MessageItem v-for="message in messages" :message="message[1]" :key="message[0]" />
<Message
v-for="message in messages"
:message="message[1]"
:key="message[0]"
/>
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, onUnmounted } from "vue";
import MessageItem from "@/components/messageItem.vue";
import InputItem from "@/components/inputItem/inputItem.vue";
import Message from "@/components/message.vue";
import InputItem from "@/components/inputItem.vue";
import Settings from "@/components/settings.vue";
import useMitt from "@/modules/mitt";
import useMessages from '@/modules/messages';
import useMessages from "@/modules/messages";
export default defineComponent({
name: "Messenger",
props: ["profile", "newMessages"],
components: {
MessageItem,
Message,
InputItem,
Settings
},
setup() {
setup(props) {
// Listen for self-messages from inputItem.
const { emitter } = useMitt();
// Handle messages in view.
const { messages, updateMessageView } = useMessages();
// Update message view on new content.
const onNewContent = (_event: any, payload: any) => {
updateMessageView(payload.message)
}
const { messages, prepMessageView, updateMessageView } = useMessages();
onMounted(() => {
const crimataId = props.profile.crimataId;
console.log(`MSGR:Initializing messenger for ${crimataId}.`)
// Front end listener.
// Load the message history.
if (crimataId === window.localStorage.getItem("last_usr")) {
prepMessageView(props.newMessages)
} else {
messages.value.clear()
}
// New content listeners.
emitter.on('self-message', (message) => updateMessageView(message));
window.ipcRenderer.on("render-message", (_e: any, payload: any) => {
updateMessageView(payload.message)
});
// Back end listener.
window.ipcRenderer.on("render-message", onNewContent);
// Save the usr for next time.
window.localStorage.setItem("last_usr", crimataId)
});
@ -58,11 +73,14 @@ export default defineComponent({
return {
messages
};
},
});
</script>
<style lang="scss" scoped>
#messenger {
width: 100vw;
height: 100vh;

View file

@ -26,7 +26,6 @@
<script lang="ts">
import { defineComponent, ref } from "vue";
import { useAuth } from "@/modules/auth";
import { useIpc } from "@/modules/ipc";
import { logoutRequest } from '@/modules/message';