[WIP] refactor, upgrading yarn
This commit is contained in:
parent
a4d6a883b0
commit
f9dcb00e2d
28 changed files with 18227 additions and 13687 deletions
|
|
@ -1,20 +1,23 @@
|
|||
|
||||
import { app } from "electron";
|
||||
import { parseAuthRes } from "@/auth";
|
||||
import { postAuth, postLogin, postLogout } from "@/api/account";
|
||||
import { updateAppUI, launchSession, endSession } from "@/session";
|
||||
import { getToken, setToken, clearToken } from "./store";
|
||||
import { backgroundMitt, ipcEmit } from "@/composables/useEmitter";
|
||||
|
||||
import { LaunchSession, EndSession } from "@/session";
|
||||
import { store } from "@/composables/useStore";
|
||||
import { postAuth, postLogin, postLogout } from "@/api/account";
|
||||
import { backgroundMitt, ipcEmit } from "@/composables/useEmitter";
|
||||
|
||||
/* Either null or a crimataId */
|
||||
let account: string | null = null;
|
||||
|
||||
const parseAuthRes = (authRes: any) => {
|
||||
const token = authRes.headers['set-cookie'][0].split(";")[0].split("=")[1] as string;
|
||||
const crimataId = authRes.data as string;
|
||||
return {token, crimataId}
|
||||
};
|
||||
|
||||
export const accountAuth = async (): Promise<void> => {
|
||||
|
||||
/* attempt to get a login token from the store */
|
||||
const token = getToken();
|
||||
const token = store.get("token");
|
||||
|
||||
try {
|
||||
|
||||
|
|
@ -25,17 +28,17 @@ export const accountAuth = async (): Promise<void> => {
|
|||
const parsed = parseAuthRes(res);
|
||||
|
||||
// save jwt token and profile
|
||||
setToken(parsed.token);
|
||||
store.set("token", parsed.token);
|
||||
account = parsed.crimataId
|
||||
|
||||
// launch session
|
||||
launchSession(parsed.token);
|
||||
LaunchSession(parsed.token);
|
||||
|
||||
} else throw(new Error('Failed to authenticate (no token).'));
|
||||
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
clearToken();
|
||||
store.delete("token");
|
||||
|
||||
} finally {
|
||||
|
||||
|
|
@ -57,11 +60,11 @@ export const accountLogin = async (payload: any): Promise<Error | void> => {
|
|||
const parsed = parseAuthRes(res);
|
||||
|
||||
// save jwt token and profile
|
||||
setToken(parsed.token);
|
||||
store.set("token", parsed.token);
|
||||
account = parsed.crimataId;
|
||||
|
||||
// launch session
|
||||
launchSession(parsed.token);
|
||||
LaunchSession(parsed.token);
|
||||
|
||||
// push state changes to the frontend
|
||||
updateAppState();
|
||||
|
|
@ -69,7 +72,7 @@ export const accountLogin = async (payload: any): Promise<Error | void> => {
|
|||
return;
|
||||
|
||||
} catch(e) {
|
||||
clearToken();
|
||||
store.delete("token");
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
|
@ -82,14 +85,14 @@ export const accountLogout = async (): Promise<Error | void> => {
|
|||
await postLogout();
|
||||
|
||||
// remove key and account
|
||||
clearToken();
|
||||
store.delete("token");
|
||||
account = null;
|
||||
|
||||
// push account state to browser
|
||||
ipcEmit("set-account", account);
|
||||
|
||||
// kill crimata platform session
|
||||
endSession();
|
||||
EndSession();
|
||||
|
||||
return;
|
||||
|
||||
|
|
|
|||
115
src/audio.ts
115
src/audio.ts
|
|
@ -1,65 +1,82 @@
|
|||
const FFT = require('fft.js');
|
||||
import { globalShortcut } from "electron";
|
||||
const nodeAudio = require('@crimata/nodeaudio');
|
||||
|
||||
import { sendMessage } from "@/io";
|
||||
import { updateTray } from "@/tray";
|
||||
import { sendMessage } from "@/session";
|
||||
import { backgroundMitt, ipcEmit } from '@/composables/useEmitter';
|
||||
|
||||
let inputDevice: number;
|
||||
let outputDevice: number;
|
||||
|
||||
let setWriteId: ReturnType<typeof setTimeout>;
|
||||
let setStreamsId: ReturnType<typeof setTimeout>;
|
||||
|
||||
let playbackEl;
|
||||
let writeToOBuffer = false;
|
||||
let recording = false;
|
||||
let playbackId: string;
|
||||
|
||||
const streamState = { rec: false, pb: false };
|
||||
|
||||
const chunks: Int16Array[] = [];
|
||||
|
||||
backgroundMitt.on("data", (int16Arr: Int16Array) => {
|
||||
if (recording) {
|
||||
const fft = new FFT(4);
|
||||
|
||||
function calcFFT(int16Arr: Int16Array)
|
||||
{
|
||||
const out = fft.createComplexArray();
|
||||
fft.realTransform(out, int16Arr);
|
||||
return out;
|
||||
}
|
||||
|
||||
backgroundMitt.on("read", (int16Arr: Int16Array) =>
|
||||
{
|
||||
if (streamState.rec)
|
||||
{
|
||||
chunks.push(int16Arr);
|
||||
ipcEmit("recording", int16Arr);
|
||||
ipcEmit("recording", calcFFT(int16Arr)); /* fft used for animation */
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
backgroundMitt.on("playback", (uid: string, aplitude: number) => {
|
||||
ipcEmit("animate-playback", { uid: uid, aplitude: aplitude });
|
||||
});
|
||||
backgroundMitt.on("write", (int16Arr: Int16Array) =>
|
||||
{
|
||||
ipcEmit("playback", { uid: playbackId, fft: calcFFT(int16Arr) });
|
||||
streamState.pb = true;
|
||||
|
||||
backgroundMitt.on("write", (status: boolean) => {
|
||||
writeToOBuffer = status;
|
||||
});
|
||||
|
||||
const setStreams = () => {
|
||||
clearTimeout(setWriteId);
|
||||
setWriteId = setTimeout(() => streamState.pb = false, 1000);
|
||||
}
|
||||
);
|
||||
|
||||
function setStreams()
|
||||
{
|
||||
const defaultInput = nodeAudio.core.GetDefaultInputDevice();
|
||||
const defaultOutput = nodeAudio.core.GetDefaultOutputDevice();
|
||||
|
||||
if (inputDevice !== defaultInput) {
|
||||
if (inputDevice !== defaultInput)
|
||||
{
|
||||
inputDevice = defaultInput;
|
||||
nodeAudio.core.CloseInputStream(inputDevice);
|
||||
nodeAudio.core.OpenInputStream(inputDevice);
|
||||
}
|
||||
|
||||
if (outputDevice !== defaultOutput) {
|
||||
if (outputDevice !== defaultOutput)
|
||||
{
|
||||
outputDevice = defaultOutput;
|
||||
nodeAudio.core.CloseOutputStream(outputDevice);
|
||||
nodeAudio.core.OpenOutputStream(outputDevice);
|
||||
}
|
||||
}
|
||||
|
||||
const startRecording = () => {
|
||||
|
||||
/* If playback is happening, we kill it */
|
||||
if (playback) nodeAudio.core.ClearOutputBuffer();
|
||||
|
||||
recording = true;
|
||||
updateTray("recording", recording);
|
||||
function startRecording()
|
||||
{
|
||||
streamState.rec = true;
|
||||
updateTray("recording", streamState.rec);
|
||||
}
|
||||
|
||||
const stopRecording = () => {
|
||||
recording = false;
|
||||
updateTray("recording", recording);
|
||||
function stopRecording()
|
||||
{
|
||||
streamState.rec = false;
|
||||
updateTray("recording", streamState.rec);
|
||||
|
||||
/* Send the data to the platform right away */
|
||||
sendMessage({
|
||||
|
|
@ -70,40 +87,38 @@ const stopRecording = () => {
|
|||
chunks.length = 0;
|
||||
}
|
||||
|
||||
export const initAudio = () => {
|
||||
function InitAudio()
|
||||
{
|
||||
nodeAudio.core.Initialize(backgroundMitt.emit.bind(backgroundMitt));
|
||||
setStreamsId = setInterval(setStreams, 2000); // sense device
|
||||
|
||||
/* Toggle recording switch with global shortcut */
|
||||
globalShortcut.register('CommandOrControl+R', () => {
|
||||
if (recording) {
|
||||
globalShortcut.register('CommandOrControl+R', () =>
|
||||
{
|
||||
if (streamState.rec)
|
||||
{
|
||||
stopRecording();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
startRecording();
|
||||
};
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export const playback = (audio: Int16Array, source: string) => {
|
||||
|
||||
/* If existing playback is happening, we kill it */
|
||||
if (playback) nodeAudio.core.ClearOutputBuffer();
|
||||
|
||||
const playbackEl = uid;
|
||||
|
||||
/* Will override an existing playback process */
|
||||
function playback(audio: Int16Array, uid: string)
|
||||
{
|
||||
playbackId = uid; /* uid of message */
|
||||
// nodeAudio.core.CancelPlayback(); /* terminate any current playback */
|
||||
nodeAudio.core.WriteToOutputStream(audio.buffer);
|
||||
}
|
||||
|
||||
export const terminateAudio = () => {
|
||||
function TerminateAudio()
|
||||
{
|
||||
clearInterval(setStreamsId);
|
||||
nodeAudio.core.Terminate();
|
||||
}
|
||||
|
||||
export const getStreamState = () => {
|
||||
let busy = false;
|
||||
if (playback || recording) {
|
||||
busy = true;
|
||||
}
|
||||
return busy;
|
||||
}
|
||||
export { InitAudio, TerminateAudio, playback, streamState };
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
export const parseAuthRes = (authRes: any) => {
|
||||
const token = authRes.headers['set-cookie'][0].split(";")[0].split("=")[1] as string;
|
||||
const crimataId = authRes.data as string;
|
||||
return {token, crimataId}
|
||||
};
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
|
||||
import {config} from "@/config";
|
||||
import fs from 'fs';
|
||||
|
||||
export const saveToJson = (fileName: string, data: any) => {
|
||||
|
||||
fs.writeFile(config.configPath + fileName, JSON.stringify(data), (err) => {
|
||||
if (err) {
|
||||
console.log("Error when saving to json.")
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
12
src/composables/useStore.ts
Normal file
12
src/composables/useStore.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
const Store = require('electron-store');
|
||||
|
||||
const schema = {
|
||||
token: {
|
||||
type: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
export const store = new Store({
|
||||
schema,
|
||||
encryptionKey: "super user test"
|
||||
});
|
||||
|
|
@ -8,17 +8,15 @@ const _connectionCheckTimeout = 4000;
|
|||
const _reconnectTimeout = 1000;
|
||||
let _connectionCheckInterval: ReturnType<typeof setTimeout>;
|
||||
|
||||
/* ws-status key:
|
||||
* 0 - onMessage (connected)
|
||||
* 1 - pongMessage (nominal)
|
||||
* 2 - closeMessage (reconnecting)
|
||||
* 3 - pingErrorMessage (connection lost)
|
||||
*/
|
||||
|
||||
export default function useWebSockets(
|
||||
messageCallback: (message: string) => void,
|
||||
connectionStatusCallback: (status: string) => void,
|
||||
statusOptions?: {
|
||||
openMessage: string;
|
||||
pongMessage: string;
|
||||
closeMessage: string;
|
||||
pingErrorMessage: string;
|
||||
},
|
||||
) {
|
||||
export default function useWebSockets(emit: (eventName: string | symbol, [...args]: any) => boolean)
|
||||
{
|
||||
|
||||
let socket: WebSocket;
|
||||
|
||||
|
|
@ -47,7 +45,7 @@ export default function useWebSockets(
|
|||
|
||||
socket.send(JSON.stringify({key: secret}));
|
||||
|
||||
connectionStatusCallback(statusOptions ? statusOptions.openMessage : "Connection Opened");
|
||||
emit("ws-status", 0);
|
||||
|
||||
// ping server
|
||||
_connectionCheckInterval = setInterval(() => {
|
||||
|
|
@ -55,7 +53,7 @@ export default function useWebSockets(
|
|||
socket.ping(null, true, (e: Error) => {
|
||||
if (e) {
|
||||
socket.close();
|
||||
connectionStatusCallback(statusOptions ? statusOptions.pingErrorMessage : "Connection Lost");
|
||||
emit("ws-status", 3);
|
||||
setTimeout(() => connect(socketUrl, secret), _reconnectTimeout);
|
||||
}
|
||||
});
|
||||
|
|
@ -66,11 +64,11 @@ export default function useWebSockets(
|
|||
|
||||
socket.on("message", (event: WebSocket.MessageEvent) => {
|
||||
console.log("message received", event);
|
||||
messageCallback(event.toString())
|
||||
emit("ws-message", event.toString());
|
||||
});
|
||||
|
||||
socket.on("close", (code: number, reason: string) => {
|
||||
connectionStatusCallback(statusOptions ? statusOptions.closeMessage : "Connection Closed");
|
||||
emit("ws-status", 2);
|
||||
clearInterval(_connectionCheckInterval);
|
||||
if (code !== 1000 || reason !== 'session-logout') {
|
||||
setTimeout(() => {
|
||||
|
|
@ -80,7 +78,7 @@ export default function useWebSockets(
|
|||
|
||||
});
|
||||
|
||||
socket.on("pong", () => connectionStatusCallback(statusOptions ? statusOptions.pongMessage : "Pong"));
|
||||
socket.on("pong", () => emit("ws-status", 1));
|
||||
|
||||
socket.on('error', () => {});
|
||||
|
||||
|
|
|
|||
52
src/init.ts
52
src/init.ts
|
|
@ -6,11 +6,11 @@
|
|||
"use strict";
|
||||
|
||||
import { app, protocol, globalShortcut } from "electron";
|
||||
import createWindow from "./window";
|
||||
import main from "./main";
|
||||
|
||||
import main from "@/main";
|
||||
import { CreateWindow, winState } from "@/window";
|
||||
import { TerminateAudio } from '@/audio';
|
||||
import { backgroundMitt } from '@/composables/useEmitter';
|
||||
import { setWindowOpen, getWindowOpen } from './store';
|
||||
import { terminateAudio } from './audio';
|
||||
|
||||
console.log('Starting Crimata electron app.');
|
||||
|
||||
|
|
@ -21,37 +21,33 @@ protocol.registerSchemesAsPrivileged([
|
|||
|
||||
const isDev = require('electron-is-dev');
|
||||
|
||||
// Listen for window creation.
|
||||
backgroundMitt.on('window-active', (state: boolean) => {
|
||||
setWindowOpen(state)
|
||||
});
|
||||
|
||||
/* Start main process on ready */
|
||||
app.on("ready", async () => {
|
||||
app.on("ready", async () =>
|
||||
{
|
||||
await main();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
app.on("will-quit", () => {
|
||||
terminateAudio();
|
||||
app.on("will-quit", () =>
|
||||
{
|
||||
TerminateAudio();
|
||||
globalShortcut.unregisterAll();
|
||||
});
|
||||
|
||||
// Must keep to ensure app doesn't quit on close.
|
||||
app.on("before-quit", async () => {
|
||||
});
|
||||
|
||||
// Must keep to ensure app doesn't quit on close.
|
||||
app.on("window-all-closed", () => {
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// When user clicks app icon (re-open)
|
||||
app.on("activate", () => {
|
||||
if (!getWindowOpen()) createWindow();
|
||||
});
|
||||
app.on("activate", () =>
|
||||
{
|
||||
if (!winState.open) CreateWindow();
|
||||
}
|
||||
);
|
||||
|
||||
// Exit cleanly on request from parent process in development mode.
|
||||
if (isDev) {
|
||||
process.on("SIGTERM", () => {
|
||||
if (isDev)
|
||||
{
|
||||
process.on("SIGTERM", () =>
|
||||
{
|
||||
app.quit();
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
34
src/io.ts
Normal file
34
src/io.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { config } from "@/config";
|
||||
import { updateTray } from "@/tray";
|
||||
import useWebsockets from "@/composables/useWebsockets";
|
||||
import { backgroundMitt, ipcEmit } from "@/composables/useEmitter";
|
||||
|
||||
backgroundMitt.on("ws-status", (status: any) =>
|
||||
{
|
||||
let simpleStatus = false;
|
||||
if (status == 2 || status == 3) simpleStatus = true;
|
||||
|
||||
updateTray("disconnect", simpleStatus);
|
||||
|
||||
ipcEmit('set-connection-status', status);
|
||||
});
|
||||
|
||||
const { connect, send, close } =
|
||||
useWebsockets(backgroundMitt.emit.bind(backgroundMitt))
|
||||
|
||||
function sendMessage(message: Raw | Request): void
|
||||
{
|
||||
send(message);
|
||||
}
|
||||
|
||||
function ConnectToPlatform(platformKey: string)
|
||||
{
|
||||
connect(config.PLATFORM_URL, platformKey);
|
||||
}
|
||||
|
||||
function DisconnectFromPlatform(code: number, reason: string)
|
||||
{
|
||||
close(code, reason);
|
||||
}
|
||||
|
||||
export { ConnectToPlatform, DisconnectFromPlatform, sendMessage };
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import { sendMessage } from '@/io';
|
||||
import { playback } from "@/audio";
|
||||
import { onNavBar } from "@/window";
|
||||
import { sendMessage } from '@/session';
|
||||
import { setWindowFocus } from '@/store';
|
||||
import { winState, onNavBar } from "@/window";
|
||||
import { updateAppState } from "@/account";
|
||||
import { IpcListener } from "@/composables/useIpcMain"
|
||||
|
||||
|
|
@ -26,12 +25,12 @@ export const navBarListener = new IpcListener({
|
|||
listenerCallback: onNavBar
|
||||
});
|
||||
|
||||
export const windowFocusListener = new IpcListener<FocusPayload>({
|
||||
export const windowFocusListener = new IpcListener<boolean>({
|
||||
channel: POST_WINDOW_FOCUS,
|
||||
listenerCallback: ({ isFocused }) => setWindowFocus(isFocused)
|
||||
listenerCallback: (state) => winState.focus = state
|
||||
});
|
||||
|
||||
export const playbackListener = new IpcListener({
|
||||
channel: PLAYBACK_CHANNEL,
|
||||
listenerCallback: playback
|
||||
});
|
||||
// export const playbackListener = new IpcListener({
|
||||
// channel: PLAYBACK_CHANNEL,
|
||||
// listenerCallback: playback
|
||||
// });
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { initTray } from '@/tray';
|
||||
import createWindow from "@/window";
|
||||
import { CreateWindow } from "@/window";
|
||||
import initIpcMain from "@/ipc/index";
|
||||
import { accountAuth } from "@/account";
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ export default async function main() {
|
|||
initTray();
|
||||
|
||||
/* launch browser window */
|
||||
await createWindow();
|
||||
await CreateWindow();
|
||||
|
||||
/* try to authenticate with token */
|
||||
accountAuth();
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
import { ipcEmit } from "@/composables/useEmitter";
|
||||
|
||||
|
||||
export default class ProfileHandler {
|
||||
|
||||
profile: Profile;
|
||||
|
||||
constructor(profile: Profile) {
|
||||
this.profile = profile;
|
||||
this.emit();
|
||||
}
|
||||
|
||||
emit() {
|
||||
ipcEmit("set-profile", this.profile);
|
||||
}
|
||||
|
||||
update(update: Update) {
|
||||
this.profile = update.data as Profile;
|
||||
this.emit()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -85,23 +85,23 @@ export function animateAudioInput () {
|
|||
|
||||
}
|
||||
|
||||
/* TODO: animation function that takes in a message ID, and data about the
|
||||
* playedback audio. We target the element with the UID and animate it according
|
||||
* to the data. - still very hypothetical...
|
||||
*/
|
||||
export function animatePlayback (uid: string, meta: number) {
|
||||
console.log("animating playback!")
|
||||
}
|
||||
|
||||
// Given index and length of content, return message child status.
|
||||
export function calcChild (index: number, len: number) {
|
||||
if (len === 1) {
|
||||
export function calcChild (index: number, len: number)
|
||||
{
|
||||
if (len === 1)
|
||||
{
|
||||
return "none";
|
||||
} else if (index === 0) {
|
||||
}
|
||||
else if (index === 0)
|
||||
{
|
||||
return "first-child";
|
||||
} else if (index === len - 1) {
|
||||
}
|
||||
else if (index === len - 1)
|
||||
{
|
||||
return "last-child";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return "middle-child";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,13 @@
|
|||
<template>
|
||||
<div
|
||||
id="inputItem"
|
||||
class="input-item"
|
||||
id="input-item"
|
||||
:class="{ playing: recording }"
|
||||
:style="{ top: `${elementY}px`, left: `${elementX}px` }"
|
||||
>
|
||||
|
||||
<!-- show the profile photo in the center of the input item -->
|
||||
<div>{{ profile.photo }}</div>
|
||||
|
||||
<!-- Recording animation on space bar -->
|
||||
<span v-if="recording" class="play"></span>
|
||||
<span v-if="recording" class="pause"></span>
|
||||
<!-- Show the profile photo in the center of the input item -->
|
||||
<!-- Background shadow animates on record -->
|
||||
<div id="profile">{{ profile.photo }}</div>
|
||||
|
||||
<!-- Show text input on key-down -->
|
||||
<input
|
||||
|
|
@ -30,9 +26,7 @@ import { profile } from "@/render/shared/profile";
|
|||
import { recording } from "@/render/shared/audio";
|
||||
import { animateAudioInput } from "@/render/components/controllers/helpers";
|
||||
|
||||
import useTextInputController from
|
||||
"@/render/components/controllers/inputItem.control.text";
|
||||
"@/render/components/controllers/inputItem.control.audio";
|
||||
import useTextInputController from "@/render/components/controllers/inputItemControl";
|
||||
|
||||
export default defineComponent({
|
||||
name: "InputItem",
|
||||
|
|
@ -67,7 +61,8 @@ export default defineComponent({
|
|||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.input-item {
|
||||
|
||||
#input-item {
|
||||
position: absolute;
|
||||
|
||||
display: flex;
|
||||
|
|
@ -93,51 +88,6 @@ export default defineComponent({
|
|||
cursor: pointer;
|
||||
|
||||
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.15);
|
||||
|
||||
.play,
|
||||
.pause {
|
||||
z-index: 5;
|
||||
&::before,
|
||||
&::after {
|
||||
-webkit-border-radius: 1000px;
|
||||
-moz-border-radius: 1000px;
|
||||
border-radius: 1000px;
|
||||
content: "";
|
||||
position: absolute;
|
||||
height: 2.35em;
|
||||
width: 2.35em;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
top: 50%;
|
||||
z-index: 0;
|
||||
}
|
||||
}
|
||||
.play::before {
|
||||
box-shadow: 0 0 0 rgba(195, 195, 195, 0);
|
||||
}
|
||||
.pause {
|
||||
opacity: 0;
|
||||
}
|
||||
&.playing {
|
||||
.play {
|
||||
opacity: 0;
|
||||
}
|
||||
.pause {
|
||||
opacity: 1;
|
||||
&::before {
|
||||
-moz-animation: circle1 1.5s infinite ease-in-out;
|
||||
-o-animation: circle1 1.5s infinite ease-in-out;
|
||||
-webkit-animation: circle1 1.5s infinite ease-in-out;
|
||||
animation: circle1 1.5s infinite ease-in-out;
|
||||
}
|
||||
&::after {
|
||||
-moz-animation: circle2 2.2s infinite ease-in-out;
|
||||
-o-animation: circle2 2.2s infinite ease-in-out;
|
||||
-webkit-animation: circle2 2.2s infinite ease-in-out;
|
||||
animation: circle2 2.2s infinite ease-in-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rec-icon {
|
||||
|
|
@ -160,38 +110,6 @@ export default defineComponent({
|
|||
}
|
||||
}
|
||||
|
||||
@keyframes circle1 {
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 0 0 0.4em rgba(195, 195, 195, 0.4);
|
||||
}
|
||||
25% {
|
||||
box-shadow: 0 0 0 0.15em rgba(195, 195, 195, 0.15);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 0 0.55em rgba(195, 195, 195, 0.55);
|
||||
}
|
||||
75% {
|
||||
box-shadow: 0 0 0 0.25em rgba(195, 195, 195, 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes circle2 {
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 0 0 0.25em rgba(195, 195, 195, 0.15);
|
||||
}
|
||||
25% {
|
||||
box-shadow: 0 0 0 0.4em rgba(195, 195, 195, 0.3);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 0 0.15em rgba(195, 195, 195, 0.05);
|
||||
}
|
||||
75% {
|
||||
box-shadow: 0 0 0 0.55em rgba(195, 195, 195, 0.45);
|
||||
}
|
||||
}
|
||||
|
||||
#textInput {
|
||||
position: absolute;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,14 +28,20 @@
|
|||
export default defineComponent({
|
||||
name: "Message",
|
||||
|
||||
props: ["modifier", "content", "context", "seen", "uid"],
|
||||
props: ["modifier", "content", "context", "seen", "uid", "playback"],
|
||||
|
||||
components: {
|
||||
Bubble,
|
||||
Context
|
||||
},
|
||||
|
||||
setup() {
|
||||
setup(props) {
|
||||
|
||||
watch(props.playback, (val, _oldval) =>
|
||||
{
|
||||
boxShadow = val/200;
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ export default defineComponent({
|
|||
setup() {
|
||||
|
||||
const onFocus = () => {
|
||||
postWindowFocus({ isFocused: true });
|
||||
postWindowFocus(true);
|
||||
postMessage({
|
||||
intent: "focus",
|
||||
params: { "focus": true },
|
||||
|
|
@ -56,7 +56,7 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
const onBlur = () => {
|
||||
postWindowFocus({ isFocused: false });
|
||||
postWindowFocus(false);
|
||||
postMessage({
|
||||
intent: "focus",
|
||||
params: { "focus": false },
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ export const invokeLogout = async (): Promise<void> => (
|
|||
*
|
||||
*/
|
||||
|
||||
export const postPlayback = (payload: string): void => (
|
||||
post('post-playback', payload)
|
||||
);
|
||||
// export const postPlayback = (audio: Int16Array, uid: string): void => (
|
||||
// post('post-playback', payload)
|
||||
// );
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -60,7 +60,7 @@ export const postNavBar = (payload: string): void => (
|
|||
*
|
||||
*/
|
||||
|
||||
export const postWindowFocus = (payload: { isFocused: boolean }): void => (
|
||||
export const postWindowFocus = (payload: boolean): void => (
|
||||
post('post-window-focus', payload)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ import {
|
|||
setMessages,
|
||||
addMessage,
|
||||
updateMessage,
|
||||
deleteMessage
|
||||
deleteMessage,
|
||||
animatePlayback
|
||||
} from "./shared/messages";
|
||||
import { setAccount } from "./shared/account";
|
||||
import { setProfile } from "./shared/profile";
|
||||
|
|
@ -23,8 +24,11 @@ const INIT_MESSAGES_CHANNEL = "init-messages";
|
|||
const ADD_MESSAGE_CHANNEL = "add-message";
|
||||
const UPDATE_MESSAGE_CHANNEL = "update-message";
|
||||
const DELETE_MESSAGE_CHANNEL = "delete-message";
|
||||
|
||||
const CONNECTION_STATUS_CHANNEL = "set-connection-status";
|
||||
const RECORDING_STATUS_CHANNEL = "recording-status";
|
||||
|
||||
const RECORDING_CHANNEL = "recording";
|
||||
const PLAYBACK_CHANNEL = "playback";
|
||||
|
||||
export const setAccountListener = new IpcRendererListener({
|
||||
channel: SET_ACCOUNT_CHANNEL,
|
||||
|
|
@ -46,7 +50,6 @@ export const initMessagesListener = new IpcRendererListener({
|
|||
listenerCallback: setMessages
|
||||
});
|
||||
|
||||
|
||||
export const addMessagesListener = new IpcRendererListener({
|
||||
channel: ADD_MESSAGE_CHANNEL,
|
||||
listenerCallback: addMessage
|
||||
|
|
@ -67,12 +70,12 @@ export const connectionStatusListener = new IpcRendererListener({
|
|||
listenerCallback: setConnectionStatus
|
||||
});
|
||||
|
||||
export const recordingStatusListener = new IpcRendererListener({
|
||||
channel: RECORDING_STATUS_CHANNEL,
|
||||
export const recordingListener = new IpcRendererListener({
|
||||
channel: RECORDING_CHANNEL,
|
||||
listenerCallback: setRecording
|
||||
});
|
||||
|
||||
export const animatePlaybackListener = new IpcRendererListener({
|
||||
channel: PLAYBACK_LISTENER,
|
||||
export const playbackListener = new IpcRendererListener({
|
||||
channel: PLAYBACK_CHANNEL,
|
||||
listenerCallback: animatePlayback
|
||||
});
|
||||
|
|
@ -4,7 +4,8 @@ import { ref } from "vue";
|
|||
export const recording = ref();
|
||||
|
||||
export const setRecording: IpcListenerCallback<boolean> = (payload) => {
|
||||
recording.value = payload;
|
||||
console.log("Recording");
|
||||
// recording.value = payload;
|
||||
}
|
||||
|
||||
export default {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,24 @@ export const updateMessage: IpcListenerCallback<Annotation> = (payload) => {
|
|||
|
||||
}
|
||||
|
||||
let playbackId: ReturnType<typeof setTimeout>;
|
||||
|
||||
export const animatePlayback: IpcListenerCallback<any> = (payload) => {
|
||||
console.log("animatePlayback");
|
||||
// clearTimeout(playbackId);
|
||||
|
||||
// const context = payload as AnimationContext;
|
||||
|
||||
// const el = document.getElementById(context.uid);
|
||||
|
||||
// el.style.boxShadow = `0px 0px 0px 20px rgba(0,0,0,${payload.fft})`;
|
||||
|
||||
// /* box shadow will return to 0 in 300ms if no more playback is done */
|
||||
// playbackId = setTimeout(() => {
|
||||
// el.style.boxShadow = `0px 0px 0px 20px rgba(0,0,0,0)`;
|
||||
// }, 300);
|
||||
}
|
||||
|
||||
export const deleteMessage: IpcListenerCallback<string> = (payload) => {
|
||||
const uid = payload as string;
|
||||
|
||||
|
|
@ -56,5 +74,6 @@ export default {
|
|||
messages,
|
||||
setMessages,
|
||||
addMessage,
|
||||
updateMessage
|
||||
updateMessage,
|
||||
animatePlayback
|
||||
};
|
||||
|
|
|
|||
111
src/session.ts
111
src/session.ts
|
|
@ -1,112 +1,97 @@
|
|||
import { Notification } from 'electron';
|
||||
|
||||
import UIState from "@/uiState";
|
||||
import { config } from "@/config";
|
||||
import { updateTray } from "@/tray";
|
||||
import { getWindowFocus, getWindowOpen } from '@/store';
|
||||
import useWebsockets from "@/composables/useWebsockets";
|
||||
import UIState from "@/ui";
|
||||
import { winState } from "@/window";
|
||||
import { ConnectToPlatform, DisconnectFromPlatform } from "@/io";
|
||||
import { backgroundMitt, ipcEmit } from "@/composables/useEmitter";
|
||||
import { initAudio, terminateAudio, playback, getStreamState } from "@/audio";
|
||||
import { InitAudio, TerminateAudio, playback, streamState } from "@/audio";
|
||||
|
||||
let processContentId: ReturnType<typeof setInterval>;
|
||||
|
||||
const contentQueue: Update[] = [];
|
||||
|
||||
const uiState = new UIState();
|
||||
|
||||
const onMessageCallback = async (payload: string) =>
|
||||
backgroundMitt.on("ws-message", (payload: string) =>
|
||||
{
|
||||
const message = JSON.parse(payload) as ClientProtocol;
|
||||
|
||||
if (message.header == "init") {
|
||||
uiState.set(message.body as Init);
|
||||
return;
|
||||
}
|
||||
|
||||
if (content)
|
||||
if (message.header == "init")
|
||||
{
|
||||
contentQueue.push(message.body)
|
||||
}
|
||||
uiState.set(message.body as Init);
|
||||
}
|
||||
else
|
||||
{
|
||||
uiState.update(message.body as Update);
|
||||
const update = message.body as Update;
|
||||
|
||||
if (update.notify)
|
||||
{
|
||||
contentQueue.push(update);
|
||||
}
|
||||
else
|
||||
{
|
||||
uiState.update(update);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const statusOptions = { openMessage: 'Connected',
|
||||
pongMessage: 'Nominal',
|
||||
closeMessage: 'Reconnecting',
|
||||
pingErrorMessage: 'Connection Lost' };
|
||||
|
||||
const connectionStatusCallback = (status: string) =>
|
||||
{
|
||||
/* Simplify connectionStatus for tray state */
|
||||
let connectionStatusSimple = false;
|
||||
if (status == statusOptions.pingErrorMessage || statusOptions.closeMessage)
|
||||
{
|
||||
connectionStatusSimple = true;
|
||||
}
|
||||
|
||||
updateTray("disconnect", connectionStatusSimple);
|
||||
|
||||
ipcEmit('set-connection-status', status);
|
||||
}
|
||||
|
||||
const { connect, send, close } = useWebsockets(onMessageCallback,
|
||||
connectionStatusCallback, statusOptions);
|
||||
|
||||
export function sendMessage(message: Raw | Request): void
|
||||
{
|
||||
send(message);
|
||||
}
|
||||
|
||||
let processContentId: ReturnType<typeof setTimeout>;
|
||||
);
|
||||
|
||||
/* launch a new session (the main process for authenticated users) */
|
||||
export function launchSession(platformKey: string)
|
||||
function LaunchSession(platformKey: string)
|
||||
{
|
||||
/* connect to the platform */
|
||||
connect(config.PLATFORM_URL, platformKey);
|
||||
ConnectToPlatform(platformKey);
|
||||
|
||||
initAudio();
|
||||
InitAudio();
|
||||
|
||||
/* Process new content every 100ms */
|
||||
processContentId = setInterval(() =>
|
||||
{
|
||||
if (getStreamState())
|
||||
if (!streamState.rec || !streamState.pb)
|
||||
{
|
||||
if (contentQueue.length > 0)
|
||||
{
|
||||
const update = contentQueue.shift() as Update;
|
||||
|
||||
/* Update the UI */
|
||||
uiState.update(update);
|
||||
|
||||
/* Spawn notification if window not in focus */
|
||||
if (!getWindowFocus())
|
||||
if (!winState.focus)
|
||||
{
|
||||
new Notification({
|
||||
title: "New Message",
|
||||
subtitle: data.context.text,
|
||||
body: data.content[0].text
|
||||
}).show();
|
||||
new Notification(update.notify as NotifyOptions).show();
|
||||
}
|
||||
|
||||
/* Play audio if audio */
|
||||
if (update.data.content[-1].audio)
|
||||
let uid: string;
|
||||
let content: Content[];
|
||||
|
||||
if (update.name == "add")
|
||||
{
|
||||
playback(message.audio, message.uid);
|
||||
const message = update.data as Message;
|
||||
content = message.content;
|
||||
uid = message.uid;
|
||||
}
|
||||
else
|
||||
{
|
||||
const annotation = update.data as Annotation;
|
||||
content = annotation.data as Content[];
|
||||
uid = annotation.uid;
|
||||
}
|
||||
|
||||
const audio = content[-1].audio;
|
||||
if (audio) playback(audio, uid);
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
export function endSession()
|
||||
function EndSession()
|
||||
{
|
||||
terminateAudio();
|
||||
TerminateAudio();
|
||||
|
||||
close(1000, 'session-logout');
|
||||
DisconnectFromPlatform(1000, 'session-logout');
|
||||
|
||||
clearInterval(processContentId)
|
||||
|
||||
uiState.reset();
|
||||
}
|
||||
|
||||
export { LaunchSession, EndSession };
|
||||
|
|
|
|||
58
src/store.ts
58
src/store.ts
|
|
@ -1,58 +0,0 @@
|
|||
const Store = require('electron-store');
|
||||
|
||||
const schema = {
|
||||
token: {
|
||||
type: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
const store = new Store({
|
||||
schema,
|
||||
encryptionKey: "super user test"
|
||||
});
|
||||
|
||||
/*
|
||||
* Token state management
|
||||
* */
|
||||
export const setToken = (token: string): void => {
|
||||
store.set("token", token);
|
||||
}
|
||||
|
||||
export const getToken = (): string | undefined => {
|
||||
return store.get("token");
|
||||
}
|
||||
|
||||
export const clearToken = (): void => {
|
||||
store.delete("token");
|
||||
}
|
||||
|
||||
/*
|
||||
* Window state management
|
||||
* */
|
||||
export const setWindowOpen = (state: boolean): void => {
|
||||
store.set("window.isOpen", state);
|
||||
}
|
||||
|
||||
export const getWindowOpen = (): boolean | undefined => {
|
||||
return store.get("window.isOpen");
|
||||
}
|
||||
|
||||
export const setWindowFocus = (state: boolean): void => {
|
||||
store.set("window.isFocused", state);
|
||||
}
|
||||
|
||||
export const getWindowFocus = (): boolean | undefined => {
|
||||
return store.get("window.isFocused");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Icon state management
|
||||
* */
|
||||
export const setIconState = (state: string): void => {
|
||||
store.set("iconStatus", state);
|
||||
}
|
||||
|
||||
export const getIconState = (): string | undefined => {
|
||||
return store.get("iconStatus");
|
||||
}
|
||||
20
src/types.ts
20
src/types.ts
|
|
@ -21,6 +21,13 @@ interface Init {
|
|||
interface Update {
|
||||
name: string;
|
||||
data: Profile | Message[] | Message | Annotation | string;
|
||||
notifiy: NotifyOptions | false;
|
||||
}
|
||||
|
||||
interface NotifyOptions {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
body: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -72,6 +79,11 @@ interface PlatformRequest {
|
|||
}
|
||||
|
||||
interface WindowState {
|
||||
open: boolean;
|
||||
focus: boolean;
|
||||
}
|
||||
|
||||
interface WindowPosition {
|
||||
width: number;
|
||||
height: number;
|
||||
x: number | null;
|
||||
|
|
@ -89,6 +101,10 @@ interface AccountCredentials {
|
|||
password: string;
|
||||
}
|
||||
|
||||
interface FocusPayload {
|
||||
isFocused: boolean;
|
||||
}
|
||||
|
||||
/*
|
||||
* Electron Ipc
|
||||
*/
|
||||
|
|
@ -125,7 +141,3 @@ interface IpcRendererEvent<T> {
|
|||
payload: T | null;
|
||||
}
|
||||
|
||||
interface FocusPayload {
|
||||
isFocused: boolean;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ class Profile implements Profile
|
|||
photo = "";
|
||||
}
|
||||
|
||||
export default class UIState
|
||||
export default class UI
|
||||
{
|
||||
profile: Profile;
|
||||
messages: Message[];
|
||||
209
src/window.ts
209
src/window.ts
|
|
@ -1,157 +1,120 @@
|
|||
"use strict";
|
||||
|
||||
import { BrowserWindow, ipcMain, app } from "electron";
|
||||
import { createProtocol } from "vue-cli-plugin-electron-builder/lib";
|
||||
import { backgroundMitt } from './composables/useEmitter';
|
||||
import { saveToJson } from "./composables/useSaveToJSON";
|
||||
import * as path from "path";
|
||||
import fs from 'fs';
|
||||
import path from "path";
|
||||
import { BrowserWindow, app } from "electron";
|
||||
import { createProtocol } from "vue-cli-plugin-electron-builder/lib";
|
||||
|
||||
import { config } from "@/config";
|
||||
const { autoUpdater } = require('electron-updater');
|
||||
import { store } from "@/composables/useStore";
|
||||
import { backgroundMitt } from '@/composables/useEmitter';
|
||||
|
||||
let win: BrowserWindow | null;
|
||||
|
||||
/* x, y coordinates and size, must persist; initialized with defaults */
|
||||
let winPosition: WindowPosition = { width: 600, height: 500, x: null, y: null }
|
||||
|
||||
/* Focused and open states */
|
||||
let winState: WindowState;
|
||||
|
||||
const loadWinState = (fileName: string): WindowState => {
|
||||
let state: WindowState;
|
||||
function updateWindowPosition()
|
||||
{
|
||||
if (win)
|
||||
{
|
||||
const bounds = win.getBounds();
|
||||
const pos = win.getPosition();
|
||||
|
||||
try {
|
||||
state = JSON.parse(fs.readFileSync(config.configPath + fileName).toString());
|
||||
winPosition.width = bounds.width;
|
||||
winPosition.height = bounds.height;
|
||||
winPosition.x = pos[0];
|
||||
winPosition.y = pos[1];
|
||||
|
||||
store.set("window-position", winPosition);
|
||||
}
|
||||
|
||||
catch (error) {
|
||||
state = {
|
||||
width: 600,
|
||||
height: 500,
|
||||
x: null,
|
||||
y: null,
|
||||
}
|
||||
}
|
||||
|
||||
return state
|
||||
|
||||
}
|
||||
|
||||
// Called when a NavBar button is pressed.
|
||||
export const onNavBar: IpcListenerCallback<string> = (payload): void => {
|
||||
if (win) {
|
||||
if (payload === "close") {
|
||||
function onNavBar(payload: string): void
|
||||
{
|
||||
if (win)
|
||||
{
|
||||
if (payload === "close")
|
||||
{
|
||||
win.close();
|
||||
} else {
|
||||
backgroundMitt.removeAllListeners("ipc-renderer");
|
||||
}
|
||||
else
|
||||
{
|
||||
win.minimize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Util function to render message on ipc-renderer event.
|
||||
const postToWindow = <T>(e: IpcRendererEvent<T>): void => {
|
||||
if (win) {
|
||||
const postToWindow = <T>(e: IpcRendererEvent<T>): void =>
|
||||
{
|
||||
if (win)
|
||||
{
|
||||
win.webContents.send(e.channel, e.payload);
|
||||
}
|
||||
}
|
||||
|
||||
// Write a json with position and size of window.
|
||||
const saveWindowState = () => {
|
||||
if (win) {
|
||||
const bounds = win.getBounds();
|
||||
const position = win.getPosition();
|
||||
|
||||
if (winState) {
|
||||
|
||||
winState.width = bounds.width;
|
||||
winState.height = bounds.height;
|
||||
winState.x = position[0];
|
||||
winState.y = position[1]
|
||||
|
||||
saveToJson("window.json", winState)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do this on window mount.
|
||||
const onWindowMount = (): void => {
|
||||
|
||||
// Must tell initApp that window exists.
|
||||
backgroundMitt.emit('window-active', true);
|
||||
|
||||
// Gateway for messages to the frontend.
|
||||
backgroundMitt.removeAllListeners("ipc-renderer")
|
||||
backgroundMitt.on("ipc-renderer", postToWindow);
|
||||
|
||||
}
|
||||
|
||||
// Do this on window dismount (close).
|
||||
const onWindowDismount = (): void => {
|
||||
win = null;
|
||||
backgroundMitt.emit('window-active', false);
|
||||
}
|
||||
|
||||
// function used by run.ts to create the main window.
|
||||
export default async function createWindow(): Promise<void> {
|
||||
return new Promise((resolve, _reject) => {
|
||||
async function CreateWindow(): Promise<void>
|
||||
{
|
||||
return new Promise((resolve, _reject) =>
|
||||
{
|
||||
if (win) resolve(); /* no duplicate */
|
||||
|
||||
// avoid creating duplicate windows.
|
||||
if (win) resolve();
|
||||
const pos = store.get("window-position");
|
||||
if (pos) winPosition = pos;
|
||||
|
||||
// Load the saved window state.
|
||||
winState = loadWinState("window.json")
|
||||
win = new BrowserWindow(
|
||||
{
|
||||
width: winPosition.width,
|
||||
height: winPosition.height,
|
||||
x: winPosition.x as number,
|
||||
y: winPosition.y as number,
|
||||
resizable: true,
|
||||
backgroundColor: '#EBEBEB',
|
||||
frame: false,
|
||||
minWidth: 350,
|
||||
minHeight: 500,
|
||||
webPreferences: { nodeIntegration: (process.env.ELECTRON_NODE_INTEGRATION as unknown) as boolean, preload: path.join(__dirname, "preload.js") }
|
||||
}
|
||||
);
|
||||
|
||||
// Define the browser window.
|
||||
win = new BrowserWindow({
|
||||
width: winState.width,
|
||||
height: winState.height,
|
||||
x: winState.x as number,
|
||||
y: winState.y as number,
|
||||
resizable: true,
|
||||
backgroundColor: '#EBEBEB',
|
||||
frame: false,
|
||||
minWidth: 350,
|
||||
minHeight: 500,
|
||||
webPreferences: {
|
||||
nodeIntegration: (process.env.ELECTRON_NODE_INTEGRATION as unknown) as boolean, preload: path.join(__dirname, "preload.js")
|
||||
}
|
||||
});
|
||||
if (win) winState.open = true;
|
||||
|
||||
// Load the URL.
|
||||
if (process.env.WEBPACK_DEV_SERVER_URL) {
|
||||
win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string); // dev
|
||||
}
|
||||
// Load the URL.
|
||||
if (process.env.WEBPACK_DEV_SERVER_URL)
|
||||
{
|
||||
win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string); // dev
|
||||
}
|
||||
else
|
||||
{
|
||||
createProtocol("app");
|
||||
win.loadURL("app://./index.html"); // prod
|
||||
}
|
||||
|
||||
else {
|
||||
createProtocol("app");
|
||||
win.loadURL("app://./index.html"); // prod
|
||||
}
|
||||
// Handle window close.
|
||||
win.on("closed", () => win = null);
|
||||
|
||||
// Handle window close.
|
||||
win.on("closed", onWindowDismount);
|
||||
// Save window state on resize and move.
|
||||
win.on("moved", updateWindowPosition);
|
||||
win.on("resize", updateWindowPosition);
|
||||
|
||||
// Save window state on resize and move.
|
||||
win.on("moved", saveWindowState);
|
||||
win.on("resize", saveWindowState);
|
||||
// For showing/hiding the splash screen.
|
||||
win.webContents.on('did-finish-load', () =>
|
||||
{
|
||||
if (win)
|
||||
win.webContents.send('window-ready', { message: true });
|
||||
|
||||
win.once('ready-to-show', () => {
|
||||
autoUpdater.checkForUpdatesAndNotify();
|
||||
if (win) win.show()
|
||||
})
|
||||
backgroundMitt.on("ipc-renderer", postToWindow);
|
||||
|
||||
// For showing/hiding the splash screen.
|
||||
win.webContents.on('did-finish-load', () => {
|
||||
if (win) win.webContents.send('window-ready', {
|
||||
message: true
|
||||
});
|
||||
|
||||
onWindowMount();
|
||||
resolve();
|
||||
});
|
||||
|
||||
});
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
autoUpdater.on('update-available', () => {
|
||||
if (win) win.webContents.send('update_available');
|
||||
});
|
||||
|
||||
autoUpdater.on('update-downloaded', () => {
|
||||
if (win) win.webContents.send('update_downloaded');
|
||||
});
|
||||
export { CreateWindow, onNavBar, winState };
|
||||
|
|
|
|||
Loading…
Reference in a new issue