dynamic initials

This commit is contained in:
Andrew Gundersen 2021-03-18 15:53:32 -05:00
commit 2b61fbac96
10 changed files with 153 additions and 109 deletions

View file

@ -19,7 +19,9 @@
<router-view/> <router-view/>
</div> </div>
<Splash v-else /> <Splash v-else />
</template> </template>
<script lang="ts"> <script lang="ts">

View file

@ -6,7 +6,7 @@ import { ipcMain } from "electron";
import { play } from './audio'; import { play } from './audio';
import { import {
AuthMessage, Creds,
Profile, Profile,
Annotation, Annotation,
StandardMessage, StandardMessage,
@ -22,7 +22,7 @@ let socket: WebSocket;
let success = false; let success = false;
let auth = false; let auth = false;
const onAuthSession = async (e: any, payload: string | null): Promise<string> => { const onAuthSession = async (e: any, payload: string | Creds) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -41,13 +41,13 @@ const onAuthSession = async (e: any, payload: string | null): Promise<string> =>
}); });
// payload == token if (typeof payload !== "string") {
if (payload) { payload = JSON.stringify(payload)
socket.send(payload);
} else {
socket.send("no-token");
} }
// Send token to backend
socket.send(payload);
}); });
}; };
@ -59,9 +59,10 @@ const handleAuthMessage = (message: string) => {
} }
const handleProfileMessage = (message: Profile) => { const handleProfileMessage = (message: Profile) => {
console.log("Updating profile...")
backgroundMitt.emit('ipc-renderer', { backgroundMitt.emit('ipc-renderer', {
endpoint: 'update-profile', endpoint: 'update-profile',
message: message message: message
}); });
} }
@ -85,6 +86,7 @@ const handleStandardMessage = (m: StandardMessage) => {
} }
const handleAnnotationMessage = (message: Annotation) => { const handleAnnotationMessage = (message: Annotation) => {
console.log("Annotation message")
backgroundMitt.emit('ipc-renderer', { backgroundMitt.emit('ipc-renderer', {
endpoint: 'annotate-message', endpoint: 'annotate-message',
message: message message: message

View file

@ -101,7 +101,6 @@ export default function useTextInputController(elementX: Ref) {
const onKeyDown = (e: KeyboardEvent) => { const onKeyDown = (e: KeyboardEvent) => {
const key = keyboardNameMap[e.keyCode] const key = keyboardNameMap[e.keyCode]
console.log(key)
if (textInput) { if (textInput) {

View file

@ -23,11 +23,9 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, ref, onMounted } from "vue"; import { defineComponent, ref, onMounted, onUnmounted } from "vue";
import draggify from "@/modules/draggify"; import draggify from "@/modules/draggify";
import { Profile } from "@/types/message/index";
import TextInput from "@/components/inputItem/textInput.vue"; import TextInput from "@/components/inputItem/textInput.vue";
import useTextInputController from import useTextInputController from
"@/components/inputItem/controllers/textCtrl"; "@/components/inputItem/controllers/textCtrl";
@ -42,7 +40,7 @@ export default defineComponent({
setup() { setup() {
// Mark input item with user's initials. // Mark input item with user's initials.
let initials = ref("") const initials = ref("")
initials.value = "IN"; initials.value = "IN";
// Initial position. // Initial position.
@ -60,19 +58,23 @@ export default defineComponent({
const { recording } = useAudioInputController(typing) const { recording } = useAudioInputController(typing)
// Update profile functionality. // Update profile functionality.
const onUpdateProfile = (_event: any, payload: Profile) => { const onUpdateProfile = (_event: any, payload: any) => {
window.localStorage.setItem("profile", JSON.stringify(payload)); initials.value = payload.message.first[0] + payload.message.last[0]
initials.value = payload.first[0] + payload.last[0]
} }
onMounted(() => { onMounted(() => {
window.ipcRenderer.on("update-profile", onUpdateProfile); window.ipcRenderer.on("update-profile", onUpdateProfile);
}) })
onUnmounted(() => {
window.ipcRenderer.removeAllListeners("update-profile");
})
return { return {
elementX, elementX,
elementY, elementY,
recording recording,
initials
}; };
}, },
}); });

View file

@ -25,6 +25,12 @@ const authToken = async () => {
const { invoke } = useIpc(); const { invoke } = useIpc();
try { try {
token = window.localStorage.getItem(AUTH_KEY); token = window.localStorage.getItem(AUTH_KEY);
if (!token) {
token = "no-token"
}
console.log(`Token ${token}`)
const res = await invoke('auth-session', token); const res = await invoke('auth-session', token);
window.localStorage.setItem(AUTH_KEY, res); window.localStorage.setItem(AUTH_KEY, res);
state.accessToken = res; state.accessToken = res;

View file

@ -1,4 +1,5 @@
import { ref } from 'vue'; import { ref } from 'vue';
import useScroll from "@/modules/scroll";
import { RenderMessage, Annotation } from "@/types/message/index"; import { RenderMessage, Annotation } from "@/types/message/index";
const messagesKey = "CRIMATA_MESSAGES"; const messagesKey = "CRIMATA_MESSAGES";
@ -7,7 +8,7 @@ const sizeLimit = 200;
// list of messages where the first item is the oldest message. // list of messages where the first item is the oldest message.
const messages = ref(new Map()); const messages = ref(new Map());
// get stored messages. // Get stored messages.
const messagesString = window.localStorage.getItem(messagesKey); const messagesString = window.localStorage.getItem(messagesKey);
if (messagesString) { if (messagesString) {
@ -17,51 +18,75 @@ if (messagesString) {
messages.value = new Map(Object.entries(parsed)); messages.value = new Map(Object.entries(parsed));
} }
// utility function to remove oldest message from the messages map. // Remove oldest message from the messages map.
function deleteOldest() { function deleteOldest() {
// create array of map keys and get the key of the oldest message.
const lastKey = Array.from(messages.value.keys()).shift(); const lastKey = Array.from(messages.value.keys()).shift();
messages.value.delete(lastKey); messages.value.delete(lastKey);
} }
// Is the message div scrolled to the bottom? //---Message Grouping-----------------------------------------------
let isScrolledToBottom: boolean;
// Update isScrolledToBottom let prevRef: string;
const updateScrollRef = () => { let activeGroup = false;
const e = document.getElementById("messenger")
if (e) {
isScrolledToBottom = e.scrollHeight - e.clientHeight <= e.scrollTop + 1
}
}
// Adjust scroll after we add content to the messenger. const updateGrouping = (currentMessageRef: string) => {
const adjustScroll = () => { if (prevRef) {
const e = document.getElementById("messenger")
if (e) { // Get references to the two most recent messages.
if (isScrolledToBottom) { const prev = messages.value.get(prevRef)
e.scrollTo({ const current = messages.value.get(currentMessageRef)
top: e.scrollHeight - e.clientHeight,
behavior: 'smooth' // See if they should be grouped.
}); if (current.time < prev.time + 20000) {
if (prev.modifier === current.modifier) {
if (prev.context === current.context) {
// Update grouping accordingly.
if (activeGroup) {
prev.isChild = "middle";
}
else {
prev.isChild = "first";
}
current.isChild = "last";
activeGroup = true;
}
// If messages unrealated, reset activeGroup.
else {
activeGroup = false;
}
}
} }
} }
prevRef = currentMessageRef;
} }
//------------------------------------------------------------------
export default function useMessages() { export default function useMessages() {
const addMessage = (m: RenderMessage) => { // Control the scrolling.
updateScrollRef() // must update before we add new elements. const { updateScrollRef, adjustScroll } = useScroll("messenger");
// check for message limit before setting a new message. // Add a new message to the view.
if (messages.value.size >= sizeLimit) deleteOldest(); const addMessage = (message: RenderMessage) => {
updateScrollRef()
messages.value.set(m.uid, m); if (messages.value.size >= sizeLimit) {
deleteOldest();
}
setTimeout(adjustScroll, 10); messages.value.set(message.uid, message);
setTimeout(adjustScroll, 20);
updateGrouping(message.uid)
} }
// Update an existing message in the view.
const updateMessage = (a: Annotation) => { const updateMessage = (a: Annotation) => {
updateScrollRef() updateScrollRef()
@ -70,14 +95,10 @@ export default function useMessages() {
message.context = a.context message.context = a.context
message.content.text = a.text message.content.text = a.text
setTimeout(adjustScroll, 10); setTimeout(adjustScroll, 20);
console.log(`Annotation: ${a.text}`)
console.log(`Annotation: ${a.context}`)
return message
} }
// Used in App.vue on shutdown.
const saveMessages = () => { const saveMessages = () => {
// de-reactivate message data before saving. // de-reactivate message data before saving.
const messageData = Object.fromEntries(messages.value); const messageData = Object.fromEntries(messages.value);

37
src/modules/scroll.ts Normal file
View file

@ -0,0 +1,37 @@
export default function useScroll(element: string) {
let isScrolledToBottom: boolean;
// Update isScrolledToBottom
const updateScrollRef = () => {
const view = document.getElementById(element)
if (view) {
isScrolledToBottom = view.scrollHeight - view.clientHeight <= view.scrollTop + 1
}
}
// Adjust scroll after we add content to the messenger.
const adjustScroll = () => {
const view = document.getElementById(element)
if (view) {
if (isScrolledToBottom) {
view.scrollTo({
top: view.scrollHeight - view.clientHeight,
behavior: 'smooth'
});
}
}
}
return {
updateScrollRef,
adjustScroll
}
}

View file

@ -16,15 +16,22 @@ export interface ClientMessage {
uid: string; uid: string;
} }
// Possible messages from server: export interface Creds {
email: string;
export interface AuthMessage { password: string;
key: string;
} }
// Possible messages from server:
export interface Profile { export interface Profile {
crimata_id: string;
title: string;
first: string; first: string;
middle: string;
last: string; last: string;
suffix: string | number;
nickname: string;
full: string;
} }
export interface Annotation { export interface Annotation {

View file

@ -36,45 +36,46 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, ref } from "vue"; import { defineComponent, ref } from "vue";
import { useAuth } from "@/modules/auth"; import { useAuth } from "@/modules/auth";
import { useIpc } from "@/modules/ipc"; import { useIpc } from "@/modules/ipc";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
interface LoginPayload {
email: string;
password: string;
rememberMe: boolean;
}
export default defineComponent({ export default defineComponent({
name: "Login", name: "Login",
setup() { setup() {
const { setToken } = useAuth(); const { setToken } = useAuth();
const router = useRouter(); const router = useRouter();
const email = ref(""); const email = ref("");
const password = ref(""); const password = ref("");
const rememberMe = ref(true);
const invalid = ref(false); const invalid = ref(false);
const { invoke } = useIpc(); const { invoke } = useIpc();
const submit = async () => { const submit = async () => {
const payload = { const payload = {
request: "login", request: "login",
email: email.value, email: email.value,
password: password.value password: password.value
}; };
try { try {
const res = await invoke('auth-session', payload); const res = await invoke('auth-session', payload);
setToken(res); setToken(res);
invalid.value = false; invalid.value = false;
router.push({ name: "home" }); router.push({ name: "home" });
} catch(e){ }
catch(e) {
invalid.value = true; invalid.value = true;
console.log('Error loging in.'); console.log('Error loging in.');
} }
}; };
const switchView = () => { const switchView = () => {
@ -85,10 +86,10 @@ export default defineComponent({
submit, submit,
email, email,
password, password,
rememberMe,
switchView, switchView,
invalid invalid
}; }
}, },
}); });
</script> </script>

View file

@ -28,55 +28,20 @@ export default defineComponent({
}, },
setup() { setup() {
// Listen for self-messages from inputItem.
const { emitter } = useMitt(); const { emitter } = useMitt();
// Handle messages in view.
const { messages, addMessage, updateMessage } = useMessages(); const { messages, addMessage, updateMessage } = useMessages();
let prevRef: string; // ref to previous message // Alter existing message.
let activeGroup = false; // if active group exists. const onAnnotateMessage = (_event: any, payload: any) => {
updateMessage(payload.message);
}
// When backend has new message. // Render new message.
const onRenderMessage = (_event: any, payload: any) => { const onRenderMessage = (_event: any, payload: any) => {
let message = payload.message; // cleaner addMessage(payload.message);
// Check type and handle accordingly.
if (message.content) {
addMessage(message);
} else {
message = updateMessage(message);
}
// Check for grouping.
if (prevRef) {
const prev = messages.value.get(prevRef)
const current = messages.value.get(message.uid)
console.log(`${message.modifier}, ${prev.modifier}`)
console.log(`${message.context}, ${prev.context}`)
// If last two messages go together...group accordingly.
if (current.time < prev.time + 20000 && current.modifier === prev.modifier && current.context === prev.context) {
if (activeGroup) {
prev.isChild = "middle"
} else {
prev.isChild = "first"
}
// Current always last child.
current.isChild = "last"
activeGroup = true
}
// Else...reset activeGroup.
else {
activeGroup = false
}
}
// Set previous message for next time.
prevRef = message.uid
} }
onMounted(() => { onMounted(() => {
@ -86,11 +51,13 @@ export default defineComponent({
// Back end listener. // Back end listener.
window.ipcRenderer.on("render-message", onRenderMessage); window.ipcRenderer.on("render-message", onRenderMessage);
window.ipcRenderer.on("annotate-message", onAnnotateMessage);
}); });
onUnmounted(() => { onUnmounted(() => {
window.ipcRenderer.removeAllListeners("render-message"); window.ipcRenderer.removeAllListeners("render-message");
window.ipcRenderer.removeAllListeners("annotate-message");
emitter.all.clear(); emitter.all.clear();
}); });