polish
This commit is contained in:
parent
d3f99d6133
commit
5d74c67648
17 changed files with 101 additions and 212 deletions
|
|
@ -67,7 +67,7 @@ function stopRecording()
|
|||
setRecordingStatus(false);
|
||||
|
||||
sendMessage({
|
||||
category: "audio/L16",
|
||||
category: "audio",
|
||||
text: null,
|
||||
blob: encode(nodeAudio.utils.mergeChunks(chunks).buffer)
|
||||
});
|
||||
|
|
|
|||
22
src/io.js
22
src/io.js
|
|
@ -56,25 +56,3 @@ ipcMain.on("message", (_e, message) => sendMessage(message));
|
|||
exports.connectToPlatform = connectToPlatform;
|
||||
exports.sendMessage = sendMessage;
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ const { createWin } = require("./window");
|
|||
const { initAccount } = require("./account");
|
||||
const { terminateAudio } = require("./audio");
|
||||
|
||||
app.commandLine.appendSwitch("enable-transparent-visuals");
|
||||
|
||||
// Assert a light theme
|
||||
nativeTheme.themeSource = "light";
|
||||
|
||||
|
|
@ -20,7 +22,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);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24.87" height="23.001" viewBox="0 0 24.87 23.001">
|
||||
<g id="Group_541" data-name="Group 541" transform="translate(-4127 -507)">
|
||||
<g id="Group_33" data-name="Group 33" transform="translate(4127 507)">
|
||||
<g id="Group_32" data-name="Group 32" transform="translate(0 0)">
|
||||
<g id="Group_31" data-name="Group 31" transform="translate(0 11.948)">
|
||||
<circle id="Ellipse_50" data-name="Ellipse 50" cx="5.527" cy="5.527" r="5.527" transform="translate(0 0)" fill="#383838"/>
|
||||
<circle id="Ellipse_51" data-name="Ellipse 51" cx="5.527" cy="5.527" r="5.527" transform="translate(13.817 0)" fill="#383838"/>
|
||||
</g>
|
||||
<circle id="Ellipse_52" data-name="Ellipse 52" cx="5.527" cy="5.527" r="5.527" transform="translate(6.898 0)" fill="#383838"/>
|
||||
<path id="Path_150" data-name="Path 150" d="M36.27,83.67" transform="translate(-30.733 -66.196)" fill="#ff0"/>
|
||||
<svg id="logo" xmlns="http://www.w3.org/2000/svg" width="24.87" height="23.001" viewBox="0 0 24.87 23.001">
|
||||
<g id="Group_33" data-name="Group 33">
|
||||
<g id="Group_32" data-name="Group 32" transform="translate(0 0)">
|
||||
<g id="Group_31" data-name="Group 31" transform="translate(0 11.948)">
|
||||
<circle id="Ellipse_50" data-name="Ellipse 50" cx="5.527" cy="5.527" r="5.527" transform="translate(0 0)" fill="#383838"/>
|
||||
<circle id="Ellipse_51" data-name="Ellipse 51" cx="5.527" cy="5.527" r="5.527" transform="translate(13.817 0)" fill="#383838"/>
|
||||
</g>
|
||||
<circle id="Ellipse_52" data-name="Ellipse 52" cx="5.527" cy="5.527" r="5.527" transform="translate(6.898)" fill="#383838"/>
|
||||
<path id="Path_150" data-name="Path 150" d="M36.27,83.67" transform="translate(-30.733 -66.196)" fill="#ff0"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 973 B After Width: | Height: | Size: 845 B |
|
|
@ -1,6 +1,7 @@
|
|||
import Splash from "./splash.js";
|
||||
import Messenger from "./messenger.js";
|
||||
import Login from "./login.js";
|
||||
import Splash from "./splash.js";
|
||||
import Header from "./header.js";
|
||||
import Messenger from "./messenger.js";
|
||||
|
||||
const account = Vue.ref(null);
|
||||
|
||||
|
|
@ -8,6 +9,7 @@ const App =
|
|||
{
|
||||
components: {
|
||||
Splash,
|
||||
Header,
|
||||
Messenger,
|
||||
Login
|
||||
},
|
||||
|
|
@ -20,7 +22,7 @@ const App =
|
|||
template: `
|
||||
<main id="app" v-if="account !== null">
|
||||
|
||||
<button id="header-titlebar" />
|
||||
<Header />
|
||||
|
||||
<Messenger v-if="account"/>
|
||||
<Login v-else />
|
||||
|
|
@ -31,7 +33,6 @@ const App =
|
|||
}
|
||||
|
||||
window.mainApi.on("set-account", (account_) => {
|
||||
console.log("setting-account");
|
||||
account.value = account_;
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const Bubble =
|
||||
{
|
||||
props: ["category", "text", "blob", "modifier", "child"],
|
||||
props: ["category", "text", "html", "blob", "modifier", "child"],
|
||||
|
||||
setup(props)
|
||||
{
|
||||
|
|
@ -9,7 +9,7 @@ const Bubble =
|
|||
}
|
||||
|
||||
Vue.onMounted(() => {
|
||||
document.getElementById("messenger").dispatchEvent(new CustomEvent('adjust-scroll'));
|
||||
document.dispatchEvent(new CustomEvent("scroll"));
|
||||
});
|
||||
|
||||
return { getUrl };
|
||||
|
|
@ -18,13 +18,13 @@ const Bubble =
|
|||
template: `
|
||||
<div :class="'bubble ' + modifier + '-bubble ' + modifier +'-'+ child">
|
||||
|
||||
<p v-if="category=='text/plain'">{{ text }}</p>
|
||||
<p v-if="category=='text'">{{ text }}</p>
|
||||
|
||||
<p v-else-if="category=='audio/L16'">{{ text }}</p>
|
||||
<p v-else-if="category=='audio'">{{ text }}</p>
|
||||
|
||||
<div v-else-if="category=='text/html'" v-html="text"></div>
|
||||
<div v-else-if="category=='html'" v-html="html"></div>
|
||||
|
||||
<img v-else-if="category.startsWith('image/')" :src="getUrl()" />
|
||||
<img v-else-if="category == 'image'" :src="getUrl()" />
|
||||
|
||||
<a v-else :href="getUrl()">{{ text }}</a>
|
||||
|
||||
|
|
|
|||
|
|
@ -20,15 +20,10 @@ const Context =
|
|||
template: `
|
||||
<span :class="'context ' + modifier + '-context'">
|
||||
|
||||
<div
|
||||
v-show="avatar"
|
||||
class="context-avatar"
|
||||
<img v-show="avatar" class="context-avatar"
|
||||
:class="{ audio: playback }"
|
||||
>
|
||||
|
||||
<img :src="'data:image/png;base64,' + avatar" />
|
||||
|
||||
</div>
|
||||
:src="'data:image/png;base64,' + avatar"
|
||||
/>
|
||||
|
||||
{{ context }}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,13 +7,11 @@ const initScroll = (elementId) => {
|
|||
}
|
||||
|
||||
const isBottom = () => {
|
||||
if (el) {
|
||||
return el.scrollHeight - el.clientHeight <= el.scrollTop + 1;
|
||||
}
|
||||
return el.scrollHeight - el.clientHeight <= el.scrollTop + 1;
|
||||
}
|
||||
|
||||
const adjustScroll = () => {
|
||||
if (el) {
|
||||
if (isBottom()) {
|
||||
el.scrollTo({
|
||||
top: el.scrollHeight - el.clientHeight,
|
||||
behavior: 'smooth'
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ function useText(elementId, left, typing)
|
|||
|
||||
window.addEventListener("keydown", (e) => {
|
||||
|
||||
if (!show.value && !metaKeys.includes(e.key))
|
||||
if (!show.value && !metaKeys.includes(e.key) && !e.ctrlKey)
|
||||
{
|
||||
show.value = true;
|
||||
}
|
||||
|
|
@ -47,7 +47,7 @@ function useText(elementId, left, typing)
|
|||
if (e.key === "Enter" && el.value)
|
||||
{
|
||||
window.mainApi.send("message", {
|
||||
category: "text/plain",
|
||||
category: "text",
|
||||
text: el.value,
|
||||
blob: null
|
||||
});
|
||||
|
|
|
|||
19
src/render/components/drop.js
Normal file
19
src/render/components/drop.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
const onDrop = async (e) => {
|
||||
const file = e.dataTransfer.items[0].getAsFile();
|
||||
|
||||
const buffer = await file.arrayBuffer();
|
||||
const b64String = await window.mainApi.invoke("encode", buffer);
|
||||
|
||||
let category = "file";
|
||||
if (file.type.startsWith("image/")) {
|
||||
category = "image"
|
||||
}
|
||||
|
||||
window.mainApi.send("message", {
|
||||
category: category,
|
||||
text: file.name,
|
||||
blob: b64String
|
||||
});
|
||||
}
|
||||
|
||||
export default onDrop;
|
||||
|
|
@ -22,6 +22,7 @@ const Message =
|
|||
v-for="(c, index) in content"
|
||||
:category="c.category"
|
||||
:text="c.text"
|
||||
:html="c.html"
|
||||
:blob="c.blob"
|
||||
:modifier="modifier"
|
||||
:child="calcChild(index, content.length)"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import initScroll from "./control/scroll.js";
|
||||
import onDrop from "./control/drop.js";
|
||||
import adjustScroll from "./control/scroll.js";
|
||||
|
||||
import WS from "./ws.js";
|
||||
import Input from "./input.js";
|
||||
|
|
@ -17,62 +18,32 @@ const Messenger = {
|
|||
setup()
|
||||
{
|
||||
const person = Vue.ref("");
|
||||
const messages = Vue.ref([{
|
||||
modifier: "ai",
|
||||
content: [{
|
||||
category: "text/html",
|
||||
text: `<div class="mail">
|
||||
<h4>About HTML Parser</h4>
|
||||
<p>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.).</p>
|
||||
</div>`,
|
||||
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
|
||||
});
|
||||
}
|
||||
const messages = Vue.ref([]);
|
||||
|
||||
Vue.onMounted(() => {
|
||||
|
||||
window.mainApi.on("message", (message) => {
|
||||
if (message.person)
|
||||
window.mainApi.on("update", (update) => {
|
||||
|
||||
if (update.name)
|
||||
{
|
||||
person.value = message.person;
|
||||
messages.value = message.messages;
|
||||
person.value = update;
|
||||
}
|
||||
else if (message.name)
|
||||
else if (typeof update == Array)
|
||||
{
|
||||
person.value = message;
|
||||
messages.value.push(...update);
|
||||
}
|
||||
else if (message.content)
|
||||
{
|
||||
messages.value.push(message);
|
||||
messages.value.push(update);
|
||||
}
|
||||
else
|
||||
else if (update.new)
|
||||
{
|
||||
messages.value[messages.value.length - 1].content.push(message);
|
||||
messages.value.at(-1)[update.new] = update.val;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
initScroll("messenger");
|
||||
window.mainApi.send("messenger");
|
||||
});
|
||||
|
||||
Vue.onUnmounted(() => {
|
||||
messages.value = [];
|
||||
window.mainApi.send("message", "win");
|
||||
});
|
||||
|
||||
return { person, messages, onDrop };
|
||||
|
|
|
|||
|
|
@ -4,15 +4,23 @@ const Settings =
|
|||
setup() {
|
||||
const active = Vue.ref(false);
|
||||
|
||||
window.addEventListener("keydown", (e) => {
|
||||
console.log("toggle settings");
|
||||
})
|
||||
function hideSettings(e) {
|
||||
if (e.key == "Escape") {
|
||||
active.value = false;
|
||||
window.removeEventListener("keydown", hideSettings);
|
||||
}
|
||||
}
|
||||
|
||||
function showSettings() {
|
||||
active.value = true;
|
||||
window.addEventListener("keydown", hideSettings);
|
||||
}
|
||||
|
||||
const logout = async () => {
|
||||
await window.mainApi.send("logout");
|
||||
}
|
||||
|
||||
return { active, logout };
|
||||
return { showSettings, active, logout };
|
||||
},
|
||||
|
||||
template: `
|
||||
|
|
@ -22,7 +30,11 @@ const Settings =
|
|||
Logout
|
||||
</button>
|
||||
|
||||
</div>`
|
||||
</div>
|
||||
|
||||
<button v-else class="settings-icon" @click="showSettings">
|
||||
<img src="./assets/settingsIcon.svg">
|
||||
</button>`
|
||||
}
|
||||
|
||||
export default Settings;
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: rgba(235, 235, 235, 0.75);
|
||||
}
|
||||
|
||||
/* The first word of the class is the component that it modifys. */
|
||||
|
|
@ -46,6 +47,7 @@ html, body {
|
|||
}
|
||||
|
||||
.contacts img {
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
|
|
@ -60,26 +62,10 @@ html, body {
|
|||
|
||||
.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;
|
||||
|
|
@ -251,6 +237,7 @@ html, body {
|
|||
content: '';
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.ws-dot::before {
|
||||
|
|
@ -493,13 +480,13 @@ html, body {
|
|||
}
|
||||
|
||||
.bubble a {
|
||||
display:inline-block;
|
||||
text-decoration: none;
|
||||
border-radius: inherit;
|
||||
font-family: "SF Compact Rounded";
|
||||
background-color: #D9D9D9;
|
||||
font-weight: bold;
|
||||
padding: 12px;
|
||||
padding: 10px;
|
||||
color: #727272;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.context {
|
||||
|
|
@ -522,18 +509,9 @@ html, body {
|
|||
}
|
||||
|
||||
.context-avatar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background-color: white;
|
||||
border-radius: 15px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.context-avatar img {
|
||||
border-radius: 50%;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
/* ---------- shared between components ---------- */
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ const { contextBridge, ipcRenderer } = require("electron");
|
|||
|
||||
const validFromMainChannels = [
|
||||
"set-account",
|
||||
"message",
|
||||
"update",
|
||||
"ws-status",
|
||||
"record",
|
||||
"playback"
|
||||
|
|
@ -16,7 +16,8 @@ const validToMain = [
|
|||
"login",
|
||||
"logout",
|
||||
"encode",
|
||||
"decode"
|
||||
"decode",
|
||||
"nav-bar"
|
||||
]
|
||||
|
||||
ipcRenderer.setMaxListeners(250);
|
||||
|
|
|
|||
|
|
@ -5,21 +5,13 @@ const { backgroundMitt, ipcEmit } = require("./utils/emitter");
|
|||
const { connectToPlatform, disconnectFromPlatform } = require("./io");
|
||||
const { initAudio, terminateAudio, playback, streamState } = require("./audio");
|
||||
|
||||
let ui; /* wait to receive ui from the platform */
|
||||
|
||||
const messageQueue = [];
|
||||
|
||||
let processContentId;
|
||||
|
||||
/* 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 handleMessageQueue()
|
||||
function handleUpdateQueue()
|
||||
{
|
||||
if (!streamState.pb && !streamState.rec)
|
||||
{
|
||||
|
|
@ -27,71 +19,32 @@ function handleMessageQueue()
|
|||
|
||||
if (update)
|
||||
{
|
||||
console.log("Handling UI Update:", update);
|
||||
|
||||
if (update.person)
|
||||
if (update.title)
|
||||
{
|
||||
ui = update;
|
||||
new Notification(update).show();
|
||||
}
|
||||
else if (update.name)
|
||||
else if (update.audio)
|
||||
{
|
||||
ui.person = update;
|
||||
playback(update);
|
||||
}
|
||||
else if (update.content)
|
||||
{
|
||||
ui.messages.push(update);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui.messages[ui.messages.length - 1].content.push(update);
|
||||
}
|
||||
|
||||
ipcEmit("message", update);
|
||||
|
||||
// notify();
|
||||
else { ipcEmit("update", update); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
initAudio();
|
||||
processContentId = setInterval(handleMessageQueue, 100);
|
||||
}
|
||||
|
||||
function endSession()
|
||||
{
|
||||
clearInterval(processContentId);
|
||||
// terminateAudio();
|
||||
terminateAudio();
|
||||
disconnectFromPlatform();
|
||||
ui = null;
|
||||
}
|
||||
|
||||
ipcMain.on("messenger", () => {
|
||||
if (ui) {
|
||||
ipcEmit("message", ui);
|
||||
}
|
||||
});
|
||||
|
||||
exports.launchSession = launchSession;
|
||||
exports.endSession = endSession;
|
||||
|
||||
// ui.messages[ui.messages.findIndex(m => m.id === message.id)].content.push(message);
|
||||
|
|
|
|||
|
|
@ -21,28 +21,11 @@ function updateWindowPosition()
|
|||
}
|
||||
|
||||
|
||||
function createPreviewWin(_e, content)
|
||||
function onNavBar(_e, cmd)
|
||||
{
|
||||
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);
|
||||
});
|
||||
cmd === "close" ? win.close() : win.minimize();
|
||||
}
|
||||
|
||||
|
||||
function createWin()
|
||||
{
|
||||
if (win) return;
|
||||
|
|
@ -56,7 +39,6 @@ function createWin()
|
|||
x: pos.x,
|
||||
y: pos.y,
|
||||
resizable: true,
|
||||
backgroundColor: "#EBEBEB",
|
||||
frame: false,
|
||||
minWidth: 350,
|
||||
minHeight: 500,
|
||||
|
|
@ -92,6 +74,6 @@ function createWin()
|
|||
});
|
||||
}
|
||||
|
||||
ipcMain.on("preview", createPreviewWin);
|
||||
ipcMain.on("nav-bar", onNavBar);
|
||||
|
||||
exports.createWin = createWin;
|
||||
|
|
|
|||
Loading…
Reference in a new issue