diff --git a/audio/audioNode.ts b/audio/audioNode.ts new file mode 100644 index 0000000..e69de29 diff --git a/package.json b/package.json index 24d13b1..081698f 100644 --- a/package.json +++ b/package.json @@ -66,25 +66,9 @@ "spectron": "11.0.0", "typescript": "~3.9.3", "vue-cli-plugin-electron-builder": "~2.0.0-rc.6", - "vue-jest": "^5.0.0-0" - }, - "vue": { - "lintOnSave": false, - "pluginOptions": { - "electronBuilder": { - "mainProcessFile": "./src/init.ts", - "rendererProcessFile": "./src/render/main.ts", - "preload": "./src/render/preload.ts", - "builderOptions": { - "appId": "com.crimata.ElectronUpdaterApp", - "artifactName": "${productName}-${version}.${ext}", - "publish": { - "provider": "generic", - "url": "https://gitlab.com/api/v4/projects/25637892/jobs/artifacts/main/raw/dist_electron?job=build" - } - } - } - } + "vue-jest": "^5.0.0-0", + "worker-loader": "^3.0.8", + "worklet-loader": "^1.0.0" }, "gitHooks": { "pre-commit": "lint-staged" diff --git a/public/processor.js b/public/processor.js new file mode 100644 index 0000000..df735a5 --- /dev/null +++ b/public/processor.js @@ -0,0 +1,12 @@ + +class AudioProcessor extends AudioWorkletProcessor { + process (inputs, outputs, parameters) { + console.log(inputs); + console.log(outputs); + console.log(parameters); + return true + } +} + +registerProcessor('processor', AudioProcessor) + diff --git a/public/worklet/audioProcessor.ts b/public/worklet/audioProcessor.ts new file mode 100644 index 0000000..8c8336f --- /dev/null +++ b/public/worklet/audioProcessor.ts @@ -0,0 +1,33 @@ +interface AudioWorkletProcessor { + readonly port: MessagePort; + process( + inputs: Float32Array[][], + outputs: Float32Array[][], + parameters: Record + ): boolean; +} + +declare let AudioWorkletProcessor: { + prototype: AudioWorkletProcessor; + new (options?: AudioWorkletNodeOptions): AudioWorkletProcessor; +}; + +declare function registerProcessor( + name: string, + processorCtor: (new ( + options?: AudioWorkletNodeOptions + ) => AudioWorkletProcessor) & { + parameterDescriptors?: AudioParamDescriptor[]; + } +): undefined; + +class AudioProcessor extends AudioWorkletProcessor { + process (inputs: Float32Array[][], outputs: Float32Array[][], parameters: Record) { + console.log(inputs); + console.log(outputs); + console.log(parameters); + return true + } +} + +registerProcessor('audio-processor', AudioProcessor) diff --git a/src/account.ts b/src/account.ts index 581da0e..965502c 100644 --- a/src/account.ts +++ b/src/account.ts @@ -1,7 +1,7 @@ import { postAuth, postLogin, postLogout } from "@/api/account"; import { endSession, launchSession } from "@/session"; -import { getToken, setToken, setProfile, getProfile, clearStore } from "./store"; +import { getToken, setToken, setProfile, clearStore } from "./store"; import { parseAuthRes } from "./auth"; import { ipcEmit } from "@/composables/useEmitter"; @@ -83,13 +83,4 @@ export const accountLogout = async (): Promise => { } -export const updateAppState = (): void => { - - const profile = getProfile(); - - ipcEmit("set-profile", profile); - - // ipcEmit('messages') etc - -} diff --git a/src/composables/useIpcMain.ts b/src/composables/useIpcMain.ts index ebfc4bc..4c3ba24 100644 --- a/src/composables/useIpcMain.ts +++ b/src/composables/useIpcMain.ts @@ -71,12 +71,10 @@ export class IpcListener implements IIpcListener { ipcMain.removeAllListeners(this.channel); } - private _onPost = (_e: IpcMainEvent, payload?: string | null): void => { + private _onPost = (_e: IpcMainEvent, payload: InputParam): void => { console.log(`[IPC] Post: ${this.channel}`); - - const params = payload ? JSON.parse(payload) : null; - this._listenerCallback(params); + this._listenerCallback(payload); } } diff --git a/src/composables/useWebsockets.ts b/src/composables/useWebsockets.ts index d1cfc02..aed517c 100644 --- a/src/composables/useWebsockets.ts +++ b/src/composables/useWebsockets.ts @@ -11,7 +11,13 @@ let _connectionCheckInterval: ReturnType; export default function useWebSockets( messageCallback: (message: string) => void, - connectionStatusCallback: (alive: boolean) => void, + connectionStatusCallback: (status: string) => void, + statusOptions?: { + openMessage: string, + pongMessage: string, + closeMessage: string, + pingErrorMessage: string, + }, ) { let socket: WebSocket; @@ -41,13 +47,15 @@ export default function useWebSockets( socket.send(JSON.stringify({key: secret})); + connectionStatusCallback(statusOptions ? statusOptions.openMessage : "Connection Opened"); + // ping server _connectionCheckInterval = setInterval(() => { socket.ping(null, true, (e: Error) => { if (e) { socket.close(); - connectionStatusCallback(false); + connectionStatusCallback(statusOptions ? statusOptions.pingErrorMessage : "Connection Lost"); setTimeout(() => connect(socketUrl, secret), _reconnectTimeout); } }); @@ -62,15 +70,20 @@ export default function useWebSockets( }); socket.on("close", (event: WebSocket.CloseEvent) => { - connectionStatusCallback(false); + connectionStatusCallback(statusOptions ? statusOptions.closeMessage : "Connection Closed"); clearInterval(_connectionCheckInterval); if (!event.wasClean) { - setTimeout(() => connect(socketUrl, secret), _reconnectTimeout); + setTimeout(() => { + connect(socketUrl, secret), _reconnectTimeout + }); + } }); - socket.on("pong", () => connectionStatusCallback(true)); + socket.on("pong", () => connectionStatusCallback(statusOptions ? statusOptions.pongMessage : "Pong")); + + socket.on('error', () => {}); } @@ -78,7 +91,7 @@ export default function useWebSockets( if (socket) { socket.close(); } - } + }; return { connect, diff --git a/src/ipc/handlers.ts b/src/ipc/handlers.ts index 5529662..7a9ba49 100644 --- a/src/ipc/handlers.ts +++ b/src/ipc/handlers.ts @@ -1,7 +1,7 @@ "use strict"; -import { accountLogin, accountLogout, accountProfile } from "@/account"; +import { accountLogin, accountLogout } from "@/account"; import { IpcHandler } from "@/composables/useIpcMain"; import { flush } from "@/audio"; diff --git a/src/ipc/listeners.ts b/src/ipc/listeners.ts index 8ef5d45..17af103 100644 --- a/src/ipc/listeners.ts +++ b/src/ipc/listeners.ts @@ -2,11 +2,14 @@ import { IpcListener } from "@/composables/useIpcMain" import { sendMessage } from '@/session'; import { collect } from "@/audio"; -import { updateAppState } from "@/account"; +import { updateAppState } from "@/session"; +import { onNavBar } from "@/window"; const CLIENT_MESSAGE_CHANNEL = "post-session-send" const GET_AUDIO_CHANNEL = "post-audio-collect"; const APP_MOUNT_CHANNEL = "post-app-mount"; +const NAV_BAR_CHANNEL = "post-nav-bar"; +const WINDOW_BLUR_CHANNEL = "post-window-focus"; export const messageListener = new IpcListener({ channel: CLIENT_MESSAGE_CHANNEL, @@ -22,3 +25,22 @@ export const appMountListener = new IpcListener({ channel: APP_MOUNT_CHANNEL, listenerCallback: updateAppState }); + +export const navBarListener = new IpcListener({ + channel: NAV_BAR_CHANNEL, + listenerCallback: onNavBar +}); + + +const onWindowFocus: IpcListenerCallback<{ isFocused: boolean }> = (payload) => { + if (payload.isFocused) { + console.log('window is focused') + } else { + console.log('window is blurred') + } +} + +export const windowFocusListener = new IpcListener({ + channel: WINDOW_BLUR_CHANNEL, + listenerCallback: onWindowFocus +}); diff --git a/src/main.ts b/src/main.ts index a360835..6df9f6c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -10,8 +10,8 @@ */ import initIpcMain from "@/ipc/index"; -import { accountAuth, updateAppState } from "./account"; -import { launchSession } from "./session"; +import { accountAuth } from "./account"; +import { launchSession, updateAppState } from "./session"; import createWindow from "./window"; let authState: AuthState | null; diff --git a/src/messages.ts b/src/messages.ts new file mode 100644 index 0000000..9a72b38 --- /dev/null +++ b/src/messages.ts @@ -0,0 +1,67 @@ +import { ipcEmit } from "@/composables/useEmitter"; + +export default class Messages { + + messages: Message[]; + + constructor(messages: Message[]) { + console.log(messages); + this.messages = messages; + this.emit(); + } + + emit() { + ipcEmit("init-messages", this.messages); + } + + update(update: Update) { + + if (update.name === "add") { + this.messages.push(update.data as Message); + ipcEmit("add-message", update.data); + } + + else if (update.name === "annotate") { + this._annotate(update.data as Annotation); + ipcEmit("update-message", update.data); + } + + else { + this._delete(update.data as string); + ipcEmit("delete-message", update.data); + } + + } + + _annotate(annotation: Annotation) { + + for (let i in this.messages) { + + if (this.messages[i].uid == annotation.uid) { + + if (annotation.name == "content") { + this.messages[i].content = annotation.data as string[]; + } + + if (annotation.name == "context") { + this.messages[i].context = annotation.data as string; + } + + ipcEmit("update-message", annotation); + + } + + } + + } + + _delete(uid: string) { + for (var i = 0; i < this.messages.length; i++) { + if (this.messages[i].uid === uid) { + this.messages.splice(i, 1); + break; + } + } + } + +} \ No newline at end of file diff --git a/src/render/App.vue b/src/render/App.vue index 686591b..ba56bac 100644 --- a/src/render/App.vue +++ b/src/render/App.vue @@ -21,7 +21,7 @@ + + + diff --git a/src/render/components/context.vue b/src/render/components/context.vue new file mode 100644 index 0000000..0efcb7a --- /dev/null +++ b/src/render/components/context.vue @@ -0,0 +1,88 @@ + + + + + \ No newline at end of file diff --git a/src/render/components/controllers/helpers.ts b/src/render/components/controllers/helpers.ts index 23976a8..017cfb3 100644 --- a/src/render/components/controllers/helpers.ts +++ b/src/render/components/controllers/helpers.ts @@ -1,6 +1,5 @@ -import { ref } from "vue"; +import { ref, Ref } from "vue"; import anime from "animejs"; -import { v4 as uuidv4 } from 'uuid'; export function animateTextInput () { @@ -86,17 +85,40 @@ export function animateAudioInput () { } +// animate a message annotation. +//! probably could be improved. +export function annotateAnim (uid: string, val: string, contextRef: Ref) { -export function newMessage ({ - text=false, - audio=false, - context=false, - uid=uuidv4() -}) { - return { - text: text, - audio: audio, - context: context, - uid: uid - }; + anime({ + targets: `#${uid} span`, + opacity: [1, 0], + duration: 250, + easing: 'easeOutExpo' + }) + + .finished.then(() => { + contextRef.value = val; + }) + + .then(() => { + anime({ + targets: `#${uid} span`, + opacity: [0, 1], + duration: 250, + 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/controllers/messenger.control.ts b/src/render/components/controllers/messenger.control.ts deleted file mode 100644 index b9c3a96..0000000 --- a/src/render/components/controllers/messenger.control.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { ref } from 'vue'; -import useScroll from "@/render/composables/useScroll"; - -const messagesRef = ref(); - -/* seed the canvas with messages */ -const seedCanvas = (messages: Message[]) => { - messagesRef.value = messages; -} - -const addMessage = (message: Message) => { - messagesRef.value.push(message); -} - -const updateMessage = (message: Message) => { - - let target_message = messagesRef.value.filter((m: Message) => { - return m.uid = message.uid; - })[0]; - - if (target_message) { - target_message = message; - } - -} - -export default function useMessages() { - - const { updateScrollRef, adjustScroll } = useScroll("messenger"); - - return { - messagesRef, - seedCanvas, - addMessage, - updateMessage - }; - -} diff --git a/src/render/components/header.vue b/src/render/components/header.vue index 63716c8..a97f061 100644 --- a/src/render/components/header.vue +++ b/src/render/components/header.vue @@ -9,6 +9,7 @@ class="menuButton minimizeButton" @click.prevent="postNavBarMin" /> + @@ -16,16 +17,20 @@ // import { postNavBarExit, postNavBarMin } from "@/render/ipc"; import { defineComponent } from "vue"; + import { postNavBar } from "@/render/ipc"; + + import ConnectionStatus from "./connectionStatus.vue"; export default defineComponent({ name: "Header", + components: { ConnectionStatus }, setup() { - const postNavBarExit = () => {}; - const postNavBarMin = () => {}; - return { - postNavBarExit, - postNavBarMin - } + const postNavBarExit = () => postNavBar('close'); + const postNavBarMin = () => postNavBar('min'); + return { + postNavBarExit, + postNavBarMin + } } }); diff --git a/src/render/components/inputItem.vue b/src/render/components/inputItem.vue index edd844f..5deb739 100644 --- a/src/render/components/inputItem.vue +++ b/src/render/components/inputItem.vue @@ -32,7 +32,7 @@ import draggify from "@/render/composables/useDraggify"; import useTextInputController from "@/render/components/controllers/inputItem.control.text"; -import useAudioInputController from +// import useAudioInputController from "@/render/components/controllers/inputItem.control.audio"; export default defineComponent({ @@ -51,7 +51,8 @@ export default defineComponent({ // Controllers for text and audio. const { typing } = useTextInputController(elementX) - const { recording } = useAudioInputController(typing) + // const { recording } = useAudioInputController(typing) + const recording = false; return { elementX, diff --git a/src/render/components/login.vue b/src/render/components/login.vue index bece6ea..1de47ca 100644 --- a/src/render/components/login.vue +++ b/src/render/components/login.vue @@ -35,7 +35,7 @@ + + + + diff --git a/src/render/components/messenger.vue b/src/render/components/messenger.vue index ee56549..d1c27d7 100644 --- a/src/render/components/messenger.vue +++ b/src/render/components/messenger.vue @@ -7,11 +7,12 @@
-
@@ -19,13 +20,13 @@