dynamic initials
This commit is contained in:
parent
b7f3d6a858
commit
2b61fbac96
10 changed files with 153 additions and 109 deletions
|
|
@ -19,7 +19,9 @@
|
||||||
<router-view/>
|
<router-view/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Splash v-else />
|
<Splash v-else />
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
37
src/modules/scroll.ts
Normal 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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue