diff --git a/src/account.js b/src/account.js
index d75d649..239d89d 100644
--- a/src/account.js
+++ b/src/account.js
@@ -5,9 +5,8 @@ const { postLogin } = require("./api");
const { ipcEmit } = require("./utils/emitter");
const { launchSession, endSession } = require("./session");
-store.set("account", "smith12@gmail.com");
-// store.set("account", "adgundersen@gmail.com");
-// store.delete("account");
+// store.set("account", "smith12@gmail.com");
+store.set("account", "adgundersen@gmail.com");
async function login(_e, email, password)
{
diff --git a/src/audio.js b/src/audio.js
index a10c162..3736ee9 100644
--- a/src/audio.js
+++ b/src/audio.js
@@ -1,9 +1,9 @@
const nodeAudio = require("@crimata/nodeaudio");
-const { encode, decode } = require("base64-arraybuffer");
const { globalShortcut, ipcMain } = require("electron");
const { sendMessage } = require("./io");
const { updateTray } = require("./tray");
+const { encode, decode } = require("./codec");
const { backgroundMitt, ipcEmit } = require("./utils/emitter");
let inputDevice;
@@ -67,8 +67,9 @@ function stopRecording()
setRecordingStatus(false);
sendMessage({
- text: false,
- audio: encode(nodeAudio.utils.mergeChunks(chunks).buffer)
+ category: "audio/L16",
+ text: null,
+ blob: encode(nodeAudio.utils.mergeChunks(chunks).buffer)
});
chunks.length = 0;
@@ -129,3 +130,8 @@ exports.initAudio = initAudio;
exports.terminateAudio = terminateAudio;
exports.playback = playback;
exports.streamState = streamState;
+
+
+// setWriteId = setTimeout(() => {
+// setPlaybackStatus(false);
+// }, 500);
diff --git a/src/codec.js b/src/codec.js
new file mode 100644
index 0000000..3a9a8bf
--- /dev/null
+++ b/src/codec.js
@@ -0,0 +1,13 @@
+const { ipcMain } = require("electron");
+const { encode, decode } = require("base64-arraybuffer");
+
+ipcMain.handle("encode", (_e, arrayBuffer) => {
+ return encode(arrayBuffer);
+});
+
+ipcMain.handle("decode", (_e, b64string) => {
+ return decode(b64string);
+});
+
+exports.encode = encode;
+exports.decode = decode;
\ No newline at end of file
diff --git a/src/io.js b/src/io.js
index b5b2751..a269d49 100644
--- a/src/io.js
+++ b/src/io.js
@@ -1,7 +1,7 @@
const WebSocket = require("ws");
+const { ipcMain } = require("electron");
const config = require("./config");
-const { ipcMain } = require("electron");
const { updateTray } = require("./tray");
const { backgroundMitt, ipcEmit } = require("./utils/emitter");
@@ -22,7 +22,7 @@ function connectToPlatform(account)
.on("error", () => {}) /** keep silent on error */
- .on("message", (payload) => backgroundMitt.emit("ws-message", JSON.parse(payload)))
+ .on("message", (payload) => backgroundMitt.emit("message", JSON.parse(payload)))
.on("close", (code, reason) => {
setConnectionStatus(1);
@@ -55,4 +55,26 @@ ipcMain.on("message", (_e, message) => sendMessage(message));
exports.connectToPlatform = connectToPlatform;
exports.sendMessage = sendMessage;
-exports.disconnectFromPlatform = disconnectFromPlatform;
\ No newline at end of file
+exports.disconnectFromPlatform = disconnectFromPlatform;
+
+
+
+/* ------------- Test Messages------------- */
+
+
+
+setTimeout(() => {
+
+ // sendMessage({
+ // category: "text/plain",
+ // text: "show contacts",
+ // blob: null
+ // })
+
+ sendMessage({
+ category: "text/plain",
+ text: "add contact John Smith, john.smith97@gmail.com",
+ blob: null
+ })
+
+}, 2000);
diff --git a/src/main.js b/src/main.js
index 28b60bd..841579e 100644
--- a/src/main.js
+++ b/src/main.js
@@ -20,7 +20,7 @@ app.on("ready", () =>
initAccount();
});
-app.on("will-quit", terminateAudio);
+// app.on("will-quit", terminateAudio);
// When user clicks app icon (re-open)
app.on("activate", createWin);
diff --git a/src/preview.html b/src/preview.html
new file mode 100644
index 0000000..8c8fc48
--- /dev/null
+++ b/src/preview.html
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/render/assets/crimataAvatar.svg b/src/render/assets/crimataAvatar.svg
deleted file mode 100644
index b4f3fd6..0000000
--- a/src/render/assets/crimataAvatar.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/src/render/assets/mailAvatar.svg b/src/render/assets/mailAvatar.svg
deleted file mode 100644
index e9ac882..0000000
--- a/src/render/assets/mailAvatar.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/render/assets/messageAvatar.svg b/src/render/assets/messageAvatar.svg
deleted file mode 100644
index f187eef..0000000
--- a/src/render/assets/messageAvatar.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/src/render/components/app.js b/src/render/components/app.js
index 49abb6e..08909a6 100644
--- a/src/render/components/app.js
+++ b/src/render/components/app.js
@@ -1,7 +1,6 @@
import Splash from "./splash.js";
import Messenger from "./messenger.js";
import Login from "./login.js";
-import Header from "./header.js";
const account = Vue.ref(null);
@@ -10,8 +9,7 @@ const App =
components: {
Splash,
Messenger,
- Login,
- Header
+ Login
},
setup()
@@ -22,7 +20,7 @@ const App =
template: `
-
+
diff --git a/src/render/components/bubble.js b/src/render/components/bubble.js
index bdd64be..16f7983 100644
--- a/src/render/components/bubble.js
+++ b/src/render/components/bubble.js
@@ -1,23 +1,36 @@
const Bubble =
{
- props: ["modifier", "text", "child"],
+ props: ["category", "text", "blob", "modifier", "child"],
setup(props)
{
+ const getUrl = () => {
+ return `data:${props.category};base64,${props.blob}`;
+ }
+
Vue.onMounted(() => {
-
- const messengerEl = document.getElementById("messenger");
-
- if (messengerEl) {
- messengerEl.dispatchEvent(new CustomEvent('adjust-scroll'));
- }
-
+ document.getElementById("messenger").dispatchEvent(new CustomEvent('adjust-scroll'));
});
+
+ return { getUrl };
},
template: `
-
-
`
+
+
+
{{ text }}
+
+
{{ text }}
+
+
+
+
+
+
{{ text }}
+
+
`
};
export default Bubble;
+
+// TODO: should include other styling/actions for audio bubbles
\ No newline at end of file
diff --git a/src/render/components/context.js b/src/render/components/context.js
index fbfb2c7..b6879ae 100644
--- a/src/render/components/context.js
+++ b/src/render/components/context.js
@@ -1,7 +1,7 @@
const Context =
{
- props: ["modifier", "context", "avatar", "audio", "id"],
+ props: ["modifier", "context", "avatar", "id"],
setup(props) {
const playback = Vue.ref(false);
@@ -9,7 +9,6 @@ const Context =
Vue.onMounted(() => {
window.mainApi.on("playback", (id, status) => {
if (id === props.id) {
- console.log(id, status);
playback.value = status;
}
});
@@ -25,10 +24,10 @@ const Context =
v-show="avatar"
class="context-avatar"
:class="{ audio: playback }"
- >
+ >
+
+
-
-
{{ context }}
diff --git a/src/render/components/control/text.js b/src/render/components/control/text.js
index 9439df8..626746f 100644
--- a/src/render/components/control/text.js
+++ b/src/render/components/control/text.js
@@ -47,7 +47,10 @@ function useText(elementId, left, typing)
if (e.key === "Enter" && el.value)
{
window.mainApi.send("message", {
- text: el.value, audio: null });
+ category: "text/plain",
+ text: el.value,
+ blob: null
+ });
show.value = false;
}
});
@@ -70,4 +73,4 @@ function useText(elementId, left, typing)
return { leftSide, show };
}
-export default useText;
\ No newline at end of file
+export default useText;
diff --git a/src/render/components/input.js b/src/render/components/input.js
index 0bfe8e7..5bc8144 100644
--- a/src/render/components/input.js
+++ b/src/render/components/input.js
@@ -53,5 +53,3 @@ function getInitials(name)
}
export default Input;
-
-
diff --git a/src/render/components/message.js b/src/render/components/message.js
index 28605c5..fd1b41c 100644
--- a/src/render/components/message.js
+++ b/src/render/components/message.js
@@ -8,7 +8,7 @@ const Message =
Context
},
- props: ["modifier", "content", "context", "avatar", "audio", "id"],
+ props: ["modifier", "content", "context", "avatar", "id"],
setup(props)
{
@@ -19,9 +19,11 @@ const Message =
@@ -29,7 +31,6 @@ const Message =
:modifier="modifier"
:context="context"
:avatar="avatar"
- :audio="audio"
:id="id"
/>
@@ -56,4 +57,4 @@ function calcChild(index, len)
}
}
-export default Message;
\ No newline at end of file
+export default Message;
diff --git a/src/render/components/messenger.js b/src/render/components/messenger.js
index dcf009d..668b505 100644
--- a/src/render/components/messenger.js
+++ b/src/render/components/messenger.js
@@ -17,33 +17,54 @@ const Messenger = {
setup()
{
const person = Vue.ref("");
- const messages = Vue.ref([]);
+ const messages = Vue.ref([{
+ modifier: "ai",
+ content: [{
+ category: "text/html",
+ text: `
+
About HTML Parser
+
Return the text of the most recently opened start tag. This should not normally be needed for structured processing, but may be useful in dealing with HTML “as deployed” or for re-generating input with minimal changes (whitespace between attributes can be preserved, etc.).
+
`,
+ blob: null
+ }],
+ context: "Email from David Spade",
+ avatar: null,
+ id: 0
+ }]);
+
+ const onDrop = async (e) => {
+ const file = e.dataTransfer.items[0].getAsFile();
+
+ const buffer = await file.arrayBuffer();
+ const b64String = await window.mainApi.invoke("encode", buffer);
+
+ window.mainApi.send("message", {
+ category: file.type,
+ text: file.name,
+ blob: b64String
+ });
+ }
Vue.onMounted(() => {
- window.mainApi.on("ui-init", (ui) => {
- person.value = ui.person;
- messages.value = ui.messages;
- });
-
- window.mainApi.on("ui-update", (message) => {
-
- if (message.hasOwnProperty("person"))
+ window.mainApi.on("message", (message) => {
+ if (message.person)
{
person.value = message.person;
- return;
+ messages.value = message.messages;
}
-
- let index = messages.value.findIndex(m => m.id===message.id);
- if (index >= 0)
+ else if (message.name)
{
- messages.value[index] = message;
- }
- else
+ person.value = message;
+ }
+ else if (message.content)
{
messages.value.push(message);
}
-
+ else
+ {
+ messages.value[messages.value.length - 1].content.push(message);
+ }
});
initScroll("messenger");
@@ -54,7 +75,7 @@ const Messenger = {
messages.value = [];
});
- return { person, messages };
+ return { person, messages, onDrop };
},
template: `
@@ -62,28 +83,20 @@ const Messenger = {
-
+
`
}
export default Messenger;
-
-// {
-// modifier: "ai",
-// content: [
-// "This is test 2\r\n"
-// ],
-// context: "Email from adgundersen@gmail.com",
-// avatar: "./assets/mailAvatar.svg",
-// audio: null,
-// id: 0
-// }
\ No newline at end of file
diff --git a/src/render/components/settings.js b/src/render/components/settings.js
index c1f9a81..68d69f2 100644
--- a/src/render/components/settings.js
+++ b/src/render/components/settings.js
@@ -4,23 +4,15 @@ const Settings =
setup() {
const active = Vue.ref(false);
- function hideSettings(e) {
- if (e.key == "Escape") {
- active.value = false;
- window.removeEventListener("keydown", hideSettings);
- }
- }
+ window.addEventListener("keydown", (e) => {
+ console.log("toggle settings");
+ })
- function showSettings() {
- active.value = true;
- window.addEventListener("keydown", hideSettings);
- }
-
- async function logout() {
+ const logout = async () => {
await window.mainApi.send("logout");
}
- return { showSettings, active, logout };
+ return { active, logout };
},
template: `
@@ -30,11 +22,7 @@ const Settings =
Logout
-
-
-
-
- `
+
`
}
export default Settings;
\ No newline at end of file
diff --git a/src/render/main.css b/src/render/main.css
index 51e5996..f25adda 100644
--- a/src/render/main.css
+++ b/src/render/main.css
@@ -33,6 +33,53 @@ html, body {
z-index: 1;
}
+.contacts {
+ margin: 0;
+ padding: 0;
+ border-radius: inherit;
+ background-color: #DBDBDB;
+}
+
+.contacts > li {
+ padding: 12px;
+ display: flex;
+}
+
+.contacts img {
+ border-radius: 50%;
+}
+
+.contacts .info {
+ margin-left: 10px;
+ margin-right: 10px;
+}
+
+.contacts .name {
+
+}
+
+.contacts .email {
+ font-family: SF Compact Display;
+ font-weight: bold;
+ font-size: 12px;
+ color: #898989;
+}
+
+.mail {
+ padding: 12px;
+ margin: 0px;
+ background-color: #D6F2FF;
+ border-radius: inherit;
+}
+
+.mail h4 {
+ margin-top: 0px;
+}
+
+.mail p {
+ margin-bottom: 0px;
+}
+
#header-menu {
position: fixed;
margin-left: 20px;
@@ -389,7 +436,6 @@ html, body {
max-width: 66vw;
font-family: "SF Pro Text";
font-size: 14px;
- padding: 10px;
border-radius: 18px;
margin-bottom: 4px;
}
@@ -431,15 +477,29 @@ html, body {
border-top-right-radius: 9px;
}
-.bubble-notify {
- position: absolute;
- width: 12px;
- height: 12px;
- border-radius: 50%;
- background-color: #58D9FF;
- top: -5px;
- left: -5px;
- border: 2px solid #EBEBEB;
+.bubble > p {
+ margin: 0px;
+ padding: 10px;
+}
+
+.bubble > div {
+ border-radius: inherit;
+}
+
+.bubble > img {
+ border-radius: inherit;
+ display: block;
+ max-width: inherit;
+}
+
+.bubble a {
+ border-radius: inherit;
+ font-family: "SF Compact Rounded";
+ background-color: #D9D9D9;
+ font-weight: bold;
+ padding: 12px;
+ color: #727272;
+ margin: 0px;
}
.context {
@@ -472,6 +532,10 @@ html, body {
margin-right: 5px;
}
+.context-avatar img {
+ border-radius: 50%;
+}
+
/* ---------- shared between components ---------- */
.button {
diff --git a/src/render/preload.js b/src/render/preload.js
index 93bd7e6..9b50adf 100644
--- a/src/render/preload.js
+++ b/src/render/preload.js
@@ -4,8 +4,7 @@ const { contextBridge, ipcRenderer } = require("electron");
const validFromMainChannels = [
"set-account",
- "ui-init",
- "ui-update",
+ "message",
"ws-status",
"record",
"playback"
@@ -14,9 +13,10 @@ const validFromMainChannels = [
const validToMain = [
"messenger",
"message",
- "nav-bar",
"login",
- "logout"
+ "logout",
+ "encode",
+ "decode"
]
ipcRenderer.setMaxListeners(250);
diff --git a/src/session.js b/src/session.js
index 9fcbf11..08ece17 100644
--- a/src/session.js
+++ b/src/session.js
@@ -7,78 +7,91 @@ const { initAudio, terminateAudio, playback, streamState } = require("./audio");
let ui; /* wait to receive ui from the platform */
-const updateQueue = [];
+const messageQueue = [];
let processContentId;
-backgroundMitt.on("ws-message", (message) =>
-{
- if (message.hasOwnProperty("ui"))
- {
- ui = message.ui;
- ipcEmit("ui-init", ui);
- }
- else if (message.hasOwnProperty("person"))
- {
- ui.person = message.person;
- ipcEmit("ui-update", message);
- }
- else
- {
- updateQueue.push(message);
- }
-});
+/* Possible messages:
+ * - New UI (set ui)
+ * - New message (add message to ui.messages)
+ * - New content (add content to existing message)
+ * - Update person
+ */
+backgroundMitt.on("message", (message) => messageQueue.push(message));
-function handleMessage()
+function handleMessageQueue()
{
- if (!streamState.pb && !streamState.rec) /* if user is not "busy" */
+ if (!streamState.pb && !streamState.rec)
{
- const message = updateQueue.shift();
- if (message)
+ const update = messageQueue.shift();
+
+ if (update)
{
- let index = ui.messages.findIndex(m => m.id === message.id);
+ console.log("Handling UI Update:", update);
- if (index >= 0)
+ if (update.person)
{
- ui.messages[index] = message;
+ ui = update;
+ }
+ else if (update.name)
+ {
+ ui.person = update;
+ }
+ else if (update.content)
+ {
+ ui.messages.push(update);
}
else
{
- ui.messages.push(message)
+ ui.messages[ui.messages.length - 1].content.push(update);
}
- if (message.modifier === "ai" && !store.get("focus"))
- {
- new Notification({title: message.context, body: message.content[message.content.length - 1]}).show();
- }
+ ipcEmit("message", update);
- ipcEmit("ui-update", message);
-
- if (message.audio) playback(message.audio, message.id);
+ // notify();
}
}
}
+
+function notify()
+{
+ const message = ui.messages[ui.messages.length - 1];
+
+ const content = message.content[message.content.length -1];
+
+ new Notification(
+ {
+ title: message.context,
+ body: content.text
+ }
+ ).show();
+
+ if (content.category == "audio/L16") playback(content.blob, message.id);
+}
+
function launchSession(account)
{
connectToPlatform(account);
- initAudio();
- processContentId = setInterval(handleMessage, 100);
+ // initAudio();
+ processContentId = setInterval(handleMessageQueue, 100);
}
function endSession()
{
clearInterval(processContentId);
- terminateAudio();
+ // terminateAudio();
disconnectFromPlatform();
ui = null;
}
ipcMain.on("messenger", () => {
if (ui) {
- ipcEmit("ui-init", ui);
+ ipcEmit("message", ui);
}
});
exports.launchSession = launchSession;
exports.endSession = endSession;
+
+// ui.messages[ui.messages.findIndex(m => m.id === message.id)].content.push(message);
diff --git a/src/window.js b/src/window.js
index 1525819..77db4ea 100644
--- a/src/window.js
+++ b/src/window.js
@@ -20,12 +20,29 @@ function updateWindowPosition()
})
}
-// Called when a NavBar button is pressed.
-function onNavBar(_e, cmd)
+
+function createPreviewWin(_e, content)
{
- cmd === "close" ? win.close() : win.minimize();
+ console.log("Creating preview window");
+
+ const preview = new BrowserWindow({
+ width: 500,
+ height: 300,
+ x: null,
+ y: null,
+ resizable: true,
+ frame: false,
+ webPreferences: { preload: path.join(__dirname, "/render/preload.js") }
+ });
+
+ preview.loadFile(path.join(__dirname, "preview.html"));
+
+ preview.webContents.on("did-finish-load", () => {
+ preview.webContents.send("preview-init", content);
+ });
}
+
function createWin()
{
if (win) return;
@@ -75,7 +92,6 @@ function createWin()
});
}
-ipcMain.on("nav-bar", onNavBar);
-ipcMain.on("create-win", createWin);
+ipcMain.on("preview", createPreviewWin);
exports.createWin = createWin;