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 } }