Merge remote-tracking branch 'origin/main' into main

This commit is contained in:
Enrique Hernandez 2021-02-23 14:29:21 -06:00
commit b6402dbdd7
17 changed files with 273 additions and 67 deletions

View file

@ -1,26 +1,89 @@
<template> <template>
<div id="app"> <div id="app">
<button class="titlebar">
</button>
<!-- Menu -->
<span class="menu">
<button class="menuButton exitButton"></button>
<button class="menuButton minimizeButton"></button>
</span>
<!-- Windows -->
<router-view/> <router-view/>
</div> </div>
</template> </template>
<style lang="scss"> <style lang="scss">
html, body { html, body {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
#app { #app {
font-family: Avenir, Helvetica, Arial, sans-serif; font-family: "SF Pro Text";
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 100vh; height: 100vh;
width: 100vw; width: 100vw;
background-color: #EBEBEB;
border-radius: 15px;
} }
.titlebar {
position: fixed;
width: 100vw;
height: 54px;
opacity: 0.75;
background-color: #EBEBEB;
-webkit-user-select: none;
-webkit-app-region: drag;
border: none;
outline: none;
}
.menu {
position: fixed;
margin-left: 20px;
margin-top: 20px;
}
.menuButton {
border: none;
outline:none;
min-width: 14px;
min-height: 14px;
border-radius: 7px;
}
.exitButton {
background-color: #FF6157;
}
.exitButton:active {
background: #c14645;
}
.minimizeButton {
background-color: #FFC12F;
margin-left: 8px;
}
.minimizeButton:active {
background-color: #c08e38;
}
</style> </style>

View file

@ -14,7 +14,7 @@ export async function main() {
// create main window. // create main window.
await createWindow({ await createWindow({
width: 350, width: 350,
height: 525, height: 500,
resizable: true resizable: true
}); });

View file

@ -23,8 +23,8 @@ interface TextMessage {
content: string; content: string;
} }
const ip = 'ws://127.0.0.1'; const ip = 'ws://localhost';
const port = 8081; const port = 8760;
const reconnectTimeout = 3000; //ms const reconnectTimeout = 3000; //ms
let socket: WebSocket; let socket: WebSocket;
let success = false; let success = false;

View file

@ -55,6 +55,9 @@ export const createWindow = async (options: WindowSettings): Promise<void> => {
width: options.width, width: options.width,
height: options.height, height: options.height,
resizable: options.resizable, resizable: options.resizable,
frame: false,
minWidth: 350,
minHeight: 500,
webPreferences: { webPreferences: {
// Use pluginOptions.nodeIntegration, leave this alone // Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info

View file

@ -4,6 +4,7 @@
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xlink="http://www.w3.org/1999/xlink"
:viewBox="scrollView" :viewBox="scrollView"
@click="emittMessage"
> >
<g id="messageView" transform="translate(0, 20)"> <g id="messageView" transform="translate(0, 20)">
<g v-for="(item, index) in renderArr" :key="index" preserverAspectRatio="none"> <g v-for="(item, index) in renderArr" :key="index" preserverAspectRatio="none">
@ -21,24 +22,33 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import TextBubble from "@/components/textBubble/index.vue"; import TextBubble from "@/components/textBubble/index.vue";
import { Message } from "@/types/message/index"; import { Message } from "@/types/message/index";
import useTransitions from "./viewDetails/transitions";
import useScrollView from "@/modules/scrollView";
import useMitt from "@/modules/mitt";
import { useIpc } from "@/modules/ipc"; import { useIpc } from "@/modules/ipc";
import { Queue } from '@/modules/queue'; import { Queue } from '@/modules/queue';
import { defineComponent, reactive, onMounted, onUnmounted, watch } from "vue";
import useTransitions from "./viewDetails/transitions";
import useScrollView from "@/modules/scrollView";
import useMitt from "@/modules/mitt";
import { defineComponent, reactive, onMounted, onUnmounted, watch, ref } from "vue";
export default defineComponent({ export default defineComponent({
name: "MessageView", name: "MessageView",
components: { TextBubble }, components: { TextBubble },
setup() { setup() {
const { emitter } = useMitt(); const { emitter } = useMitt();
const renderArr: Message[] = reactive([]); const renderArr: Message[] = reactive([]);
const renderQ = new Queue(); const renderQ = new Queue();
const { invoke } = useIpc("message"); const { invoke } = useIpc("message");
// Each method will be called on their respective lifecycle event.
const { beforeEnter, enter, afterEnter, rendering } = useTransitions(); const { beforeEnter, enter, afterEnter, rendering } = useTransitions();
const { scrollView } = useScrollView({ const { scrollView } = useScrollView({
targetId: "messageView", targetId: "messageView",
@ -60,6 +70,8 @@ export default defineComponent({
}) })
onMounted(() => { onMounted(() => {
// Call render function on event "render-message."
window.ipcRenderer.on("render-message", (event, payload) => { window.ipcRenderer.on("render-message", (event, payload) => {
const m = payload.message; const m = payload.message;
if (m.content) render(m); if (m.content) render(m);
@ -90,3 +102,13 @@ export default defineComponent({
}, },
}); });
</script> </script>
<style lang="scss" scoped>
#messageView {
width: 1000px;
height: 100vh;
color: red;
}
</style>

View file

@ -5,7 +5,7 @@ import { ref } from "vue";
export default function useOffsetCalculator() { export default function useOffsetCalculator() {
const xOffset = ref(0); const xOffset = ref(0);
const yOffset = ref(0); const yOffset = ref(0);
const firstChildMarginTop = 0; const firstChildMarginTop = 45;
let previousMessageHeight = 0; let previousMessageHeight = 0;
const messagePadding = 15; const messagePadding = 15;

View file

@ -33,9 +33,12 @@ export default function useTransitions() {
const animateMessage = async (el: SVGGElement) => { const animateMessage = async (el: SVGGElement) => {
// Where the message gets translated to.
const elTransform = `translate(${messageOffset.x} ${messageOffset.y})`; const elTransform = `translate(${messageOffset.x} ${messageOffset.y})`;
const viewTransform = `translate(0 ${-vB})`; const viewTransform = `translate(0 ${-vB})`;
// Shift of view height > window height.
if (shift) { if (shift) {
await shiftAnimate(el, elTransform, messageView, viewTransform); await shiftAnimate(el, elTransform, messageView, viewTransform);
} else { } else {
@ -44,6 +47,7 @@ export default function useTransitions() {
rendering.value = false; rendering.value = false;
} }
// Get height of messageView.
const beforeEnter: VueTransitionCallback = () => { const beforeEnter: VueTransitionCallback = () => {
rendering.value = true; rendering.value = true;
// query DOM for messageView element // query DOM for messageView element

View file

@ -1,17 +1,33 @@
<template> <template>
<audio-stream v-if="visualizeStream" :bubbleWidth="audioBubbleWidth" :paths="paths" />
<text-input v-else :input="input" :textXoffset="textInputXoffset" /> <!-- render audio or text input-->
<AudioStream
v-if="visualizeStream"
:bubbleWidth="audioBubbleWidth"
:paths="paths"
/>
<TextInput
v-else
:input="input"
:textXoffset="textInputXoffset"
:textYoffset="textInputYoffset"
/>
</template> </template>
<script lang="ts"> <script lang="ts">
// input child components
// import child components
import TextInput from "./textDetails/text.vue"; import TextInput from "./textDetails/text.vue";
import AudioStream from "./audioDetails/audio.vue"; import AudioStream from "./audioDetails/audio.vue";
import useInputController from "./inputController"; import useInputController from "./inputController";
import { defineComponent } from "vue"; import { defineComponent } from "vue";
export default defineComponent({ export default defineComponent({
name: "TextAudioInput", name: "TextAudioInput",
components: { TextInput, AudioStream }, components: { TextInput, AudioStream },
setup() { setup() {
@ -24,14 +40,20 @@ export default defineComponent({
const { const {
input, input,
visualizeStream, visualizeStream,
textInputXoffset, textInputXoffset,
textInputYoffset,
audioBubbleWidth, audioBubbleWidth,
paths, paths,
} = useInputController(); } = useInputController();
return { return {
input, input,
textInputXoffset, textInputXoffset,
textInputYoffset,
visualizeStream, visualizeStream,
audioBubbleWidth, audioBubbleWidth,
paths, paths,

View file

@ -32,9 +32,18 @@ export default function useInputController() {
emitter.emit("user-message", message); emitter.emit("user-message", message);
} }
const { visualizeStreamAsPaths, expandBubble } = useAudioVisualizer(visualizeStream); const {
visualizeStreamAsPaths,
expandBubble
} = useAudioVisualizer(visualizeStream);
const { keyDownHandler, input } = useKeyDownHandler(enterCallback); const { keyDownHandler, input } = useKeyDownHandler(enterCallback);
const { textInputXoffset, renderTextInput } = useTextVisualizer(input);
const {
textInputXoffset,
textInputYoffset,
renderTextInput
} = useTextVisualizer(input);
// stops stream recording on space key up // stops stream recording on space key up
function keyupHandler(e: any) { function keyupHandler(e: any) {
@ -83,6 +92,7 @@ export default function useInputController() {
input, input,
visualizeStream, visualizeStream,
textInputXoffset, textInputXoffset,
textInputYoffset,
audioBubbleWidth, audioBubbleWidth,
paths paths
} }

View file

@ -1,38 +1,52 @@
<template> <template>
<foreignObject class="inputContainer" :x="textXoffset" y="450" width="55%" height="50%">
<foreignObject
class="inputContainer"
:x="textXoffset"
:y="textYoffset"
width="55%"
height="50%"
>
<div xmlns="http://www.w3.org/1999/xhtml"> <div xmlns="http://www.w3.org/1999/xhtml">
<div class="inputBubble" contenteditable v-show="input.length > 0"> <div class="inputBubble" v-show="input.length > 0">
<p>{{ input }}</p> <p>{{ input }}</p>
</div> </div>
</div> </div>
</foreignObject> </foreignObject>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from "vue"; import { defineComponent } from "vue";
export default defineComponent({ export default defineComponent({
name: "TextInput", name: "TextInput",
props: { props: {
input: String, input: String,
textXoffset: String, textXoffset: String,
textYoffset: String,
}, },
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
div[contenteditable] { .inputBubble {
width: auto;
max-width: 180px; max-width: 180px;
height: auto; min-height: 32px;
min-height: 36px;
display: table; display: table;
justify-items: center; justify-items: center;
border: 0;
border-radius: 10px; border-radius: 10px;
color: #000; background-color: #B9B9B9;
background-color: #b9b9b9;
font-size: 14; font-size: 14px;
text-align: left;
p { p {
max-width: 150px; max-width: 150px;
overflow-wrap: break-word; overflow-wrap: break-word;

View file

@ -50,8 +50,13 @@ export default function useTextVisualizer(input: Ref<string>) {
return `calc(50% - ${inputWidth.value / 2})`; return `calc(50% - ${inputWidth.value / 2})`;
}); });
const textInputYoffset = computed(() => {
return `calc(97% - ${inputHeight.value})`;
});
return { return {
textInputXoffset, textInputXoffset,
textInputYoffset,
renderTextInput renderTextInput
} }
} }

View file

@ -6,6 +6,7 @@ import { computed, onMounted, ref } from "vue";
export default function useComputedBubble(m: string, id: string) { export default function useComputedBubble(m: string, id: string) {
const x = ref(0) const x = ref(0)
const paddingLeft = 30; const paddingLeft = 30;
const winW = 350; const winW = 350;
const messageWidth = ref(0); const messageWidth = ref(0);
const messageMarginTop = 75; const messageMarginTop = 75;
@ -39,7 +40,7 @@ export default function useComputedBubble(m: string, id: string) {
const calculateXoffset = async () => { const calculateXoffset = async () => {
switch (m) { switch (m) {
case "sf": case "sf":
x.value = winW - messageWidth.value - selfMessageMarginRight; x.value = 800 - messageWidth.value - selfMessageMarginRight;
break; break;
default: default:
x.value = paddingLeft; x.value = paddingLeft;

View file

@ -1,7 +1,7 @@
<template> <template>
<g :id="item.id" :class="item.modifier" :transform="startingOffset"> <g :id="item.id" :class="item.modifier" :transform="startingOffset">
<rect ref="messageRect" x="30" y="10" width="196" height="63" rx="10" :fill="bubbleFill" /> <rect ref="messageRect" x="30" y="10" width="196" height="63" rx="10" :fill="bubbleFill" />
<text font-size="14" font-family="SF Pro" ref="messageText" :fill="textFill"> <text font-size="14" font-family="SF Pro Text" ref="messageText" :fill="textFill">
<tspan dy="16" x="0" v-for="(item, index) in textArr" :key="index">{{ item }}</tspan> <tspan dy="16" x="0" v-for="(item, index) in textArr" :key="index">{{ item }}</tspan>
</text> </text>
<g :transform="signatureTranslate"> <g :transform="signatureTranslate">

View file

@ -12,30 +12,44 @@ export default function useScrollView({ targetId }: { targetId: string }) {
let topBound: number; let topBound: number;
const scrollStartHeight = 445; const scrollStartHeight = 445;
const clampedScroll = computed(() => {
if (targetHeight.value === 0) { return 0; }
topBound = -targetHeight.value + 450;
return Math.max(topBound, Math.min(scroll.value, 0)) as number;
})
const scrollView = computed(() => { const scrollView = computed(() => {
if (clampedScroll.value === 0) { if (clampedScroll.value === 0) {
scroll.value = 0; scroll.value = 0;
} else if (clampedScroll.value === topBound) { } else if (clampedScroll.value === topBound) {
scroll.value = topBound; scroll.value = topBound;
} }
// x, y, width, height
// width and height should be dynamic
return `0 ${clampedScroll.value} 350 500`; return `0 ${clampedScroll.value} 350 500`;
}); });
const clampedScroll = computed(() => {
if (targetHeight.value === 0) { return 0; }
topBound = -targetHeight.value + 450;
return Math.max(topBound, Math.min(scroll.value, 0)) as number;
})
const getHeight = () => { const getHeight = () => {
if (scrollTarget) { if (scrollTarget) {
return scrollTarget.getBoundingClientRect().height as number; return scrollTarget.getBoundingClientRect().height as number;
} }
} }
const updateView = (verticalScroll: number) => { const getWidth = () => {
if (scrollTarget) { if (scrollTarget) {
return scrollTarget.getBoundingClientRect().width as number;
}
}
const updateView = (verticalScroll: number) => {
if (scrollTarget) {
const heightResult = getHeight(); const heightResult = getHeight();
const widthResult = getWidth();
if (heightResult) { if (heightResult) {
// only scroll if renderer scrollStart // only scroll if renderer scrollStart
if (heightResult > scrollStartHeight) { if (heightResult > scrollStartHeight) {

View file

@ -4,6 +4,7 @@
version="1.1" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xlink="http://www.w3.org/1999/xlink"
@click="emittMessage"
> >
<MessageView /> <MessageView />
<TextAudioInput /> <TextAudioInput />
@ -11,22 +12,26 @@
</template> </template>
<script lang="ts"> <script lang="ts">
// Home consists on MessageView and Text/Audio imput component.
import MessageView from "@/components/messageView/index.vue"; import MessageView from "@/components/messageView/index.vue";
import TextAudioInput from "@/components/taInput/index.vue"; import TextAudioInput from "@/components/taInput/index.vue";
import { defineComponent } from "vue"; import { defineComponent } from "vue";
export default defineComponent({ export default defineComponent({
name: "Messenger", name: "Messenger",
components: { MessageView, TextAudioInput }, components: { MessageView, TextAudioInput },
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
#messenger {
width: 350px; #messenger {
height: 500px; width: 100vw;
background-color: #e6e6e6; height: 100vh;
box-shadow: 0px 3px 10px 0px rgba(0, 0, 0, 0.3); background-color: #EBEBEB;
// border-radius: 20px; }
}
</style> </style>

View file

@ -1,5 +1,6 @@
<template> <template>
<form id="login" @submit.prevent="submit"> <form id="login" @submit.prevent="submit">
<!-- login title --> <!-- login title -->
<div id="loginTitle"> <div id="loginTitle">
<div>Login</div> <div>Login</div>
@ -8,19 +9,27 @@
<!-- username and password forms --> <!-- username and password forms -->
<div id="loginBox"> <div id="loginBox">
<!-- username --> <!-- username -->
<input class="input" type="text" v-model="email" placeholder="username" /> <div class="inputBox">
<input class="input" type="text" v-model="email" />
<div class="inputModifier">Email</div>
</div>
<!-- password --> <!-- password -->
<input class="input" type="password" v-model="password" placeholder="Password" /> <div class="inputBox">
<input class="input" type="password" v-model="password" />
<div class="inputModifier">Password</div>
</div>
</div> </div>
<input type="checkbox" id="checkbox" v-model="rememberMe" /> <input type="checkbox" id="checkbox" v-model="rememberMe" />
<label for="checkbox">Remember Me</label> <label for="checkbox">Remember Me</label>
<!-- submit button; position: fixed --> <!-- submit button; position: fixed -->
<button class="button" @click.prevent="submit">Submit</button> <button class="submitButton button" @click.prevent="submit">Submit</button>
<!-- back to login button: position: fixed --> <!-- back to login button: position: fixed -->
<button class="createAccountButton button" @click.prevent="switchView">Create account</button>
</form> </form>
</template> </template>
@ -80,33 +89,44 @@ export default defineComponent({
<style lang="scss" scoped> <style lang="scss" scoped>
#login { #login {
width: 350px; width: 100vw;
height: 500px; height: 100vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background-color: #e6e6e6;
} }
#loginTitle { #loginTitle {
font-family: "SF Pro Text";
min-width: 181px; min-width: 181px;
font-size: 24px; font-size: 24px;
font-weight: bold; font-weight: bold;
text-align: left; text-align: left;
padding-bottom: 10px;
} }
#loginBox { #loginBox {
font-family: "SF Compact Display";
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding-bottom: 30px;
}
.inputBox {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 10px;
} }
.input { .input {
background-color: #B9B9B9; background-color: #B9B9B9;
border: none; border: none;
color: white; outline: none;
padding: 16px; padding: 16px;
text-decoration: none; text-decoration: none;
margin: 4px 2px; margin: 4px 2px;
@ -114,25 +134,49 @@ export default defineComponent({
border-radius: 10px; border-radius: 10px;
} }
.button { .inputModifier {
min-width: 181px;
font-size: 12px;
font-weight: bold;
text-align: left;
margin-left: 15px;
}
.submitButton {
font-family: "SF Compact Display";
position: fixed; position: fixed;
margin-top: 141px; margin-top: 141px;
background-color: #58C4FD; background-color: #58C4FD;
border: none;
color: white; color: white;
padding: 10px 20px; padding: 10px 30px;
text-decoration: none;
border-radius: 20px; border-radius: 20px;
font-size: 14px;
font-weight: bold; font-weight: bold;
} }
.button2 { .submitButton:active {
position: fixed; background-color: #4296C3;
margin-top: 225px; }
.createAccountButton {
position: absolute;
border: none; border: none;
background-color: #e6e6e6; background-color: #EBEBEB;
text-decoration: none; text-decoration: none;
color: #58C4FD; color: #58C4FD;
font-weight: bold; font-weight: bold;
bottom: 20px;
right: 20px;
} }
.button {
border: none;
outline: none;
text-decoration: none;
}
.button:hover {
cursor: pointer;
}
</style> </style>

View file

@ -59,14 +59,13 @@ export default defineComponent({
<style lang="scss" scoped> <style lang="scss" scoped>
#splash { #splash {
width: 350px; width: 100vw;
height: 500px; height: 100vh;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background-color: #EBEBEB;
box-shadow: 0px 3px 10px 0px rgba(0, 0, 0, 0.3);
// border-radius: 20px;
} }
</style> </style>