mime-chat/src/modules/messages.ts

125 lines
No EOL
3.3 KiB
TypeScript

import { ref } from 'vue';
import useScroll from "@/modules/scroll";
import { RenderMessage, Annotation } from "@/types";
const messages = ref(new Map());
const addMessage = (message: RenderMessage) => {
messages.value.set(message.uid, message)
}
const updateMessage = (annotation: Annotation) => {
const message = messages.value.get(annotation.uid)
message.context = annotation.context
message.content.text = annotation.text
}
const loadSavedMessages = () => {
const rawData = window.localStorage.getItem("crimata_messages");
if (rawData) {
const messageData = JSON.parse(rawData)
messages.value = new Map(Object.entries(messageData));
}
}
const saveMessages = () => {
const messageData = Object.fromEntries(messages.value);
window.localStorage.setItem("crimata_messages", JSON.stringify(messageData));
}
const isSimmilar = (messageA: RenderMessage, messageB: RenderMessage) => {
if ((Math.abs(messageA.time - messageB.time) < 20000) && (messageA.modifier == messageB.modifier) && (messageA.context == messageB.context)) {
return true
}
return false
}
const updateGrouping = () => {
console.log("updating grouping")
const refs = Array.from(messages.value.keys())
// Get the last three messages.
const first = messages.value.get(refs[refs.length - 1])
const second = messages.value.get(refs[refs.length - 2])
const third = messages.value.get(refs[refs.length - 3])
// If messages are simmilar, update the classes.
if ((first) && (second)) {
if (isSimmilar(first, second)) {
first.isChild = "last" // i.e. last in group.
second.isChild = "first"
if (third) {
if ((third.isChild == "first") || (third.isChild == "middle")) {
second.isChild = "middle"
}
}
}
}
}
export default function useMessages() {
// Scroll controller.
const { setScroll, updateScrollRef, adjustScroll } = useScroll("messenger");
// Main function for updating the message view.
const updateMessageView = (message: RenderMessage | Annotation) => {
// Step 1: See if user is scrolled down.
updateScrollRef()
// Step 2: Add the new content to the view.
if ("content" in message) {
addMessage(message)
} else {
updateMessage(message)
}
// Step 3: Pop off oldest message (if > 200).
if (messages.value.size >= 200) {
const oldest = Array.from(messages.value.keys()).shift();
messages.value.delete(oldest);
}
// Step 4: Update grouping.
updateGrouping()
// Setp 5: Scroll the view (if scrolled down).
setTimeout(adjustScroll, 20);
// Step 6: Save the view data.
saveMessages()
}
// Seed message view with message history.
const prepMessageView = (newMessages: RenderMessage[]) => {
console.log("MSGR:Prepping messenger view.")
// Load and render saved messages and immediately scroll to bottom.
loadSavedMessages()
setTimeout(setScroll.bind(false), 10);
// Render new messages, then wait 1s to scroll.
if (newMessages.length) {
console.log("MSGR:Adding new messages")
newMessages.forEach(message => {
message.newMessage = true;
addMessage(message)
})
setTimeout(setScroll.bind(true), 1000);
}
}
return {
messages,
prepMessageView,
updateMessageView
}
}