From 7260525eec1fdc54884b06f05040072f863df172 Mon Sep 17 00:00:00 2001 From: hippoz <10706925-hippoz@users.noreply.gitlab.com> Date: Wed, 20 Apr 2022 03:14:28 +0300 Subject: [PATCH] frontend: message loading This command finalizes support for dynamic message loading. The behavior is as follows: When a user selects a channel for the first time, an "initial load" of messages will happen. When the user is scrolled all the way to the bottom of the message view, the store will continuously remove old messages to save memory. Scrolling all the way to the top loads more messages. --- .../components/pages/main/ChannelView.svelte | 2 +- .../src/components/pages/main/Messages.svelte | 16 +++++++++----- frontend/src/main.js | 11 +++++++++- frontend/src/request.js | 1 + frontend/src/stores.js | 7 +++--- test.rest | 22 +++++++++---------- 6 files changed, 38 insertions(+), 21 deletions(-) diff --git a/frontend/src/components/pages/main/ChannelView.svelte b/frontend/src/components/pages/main/ChannelView.svelte index cab88f7..f5824d2 100644 --- a/frontend/src/components/pages/main/ChannelView.svelte +++ b/frontend/src/components/pages/main/ChannelView.svelte @@ -49,7 +49,7 @@ import Messages from "./Messages.svelte"; { channel.name } - +
diff --git a/frontend/src/components/pages/main/Messages.svelte b/frontend/src/components/pages/main/Messages.svelte index d2a2ded..788df5a 100644 --- a/frontend/src/components/pages/main/Messages.svelte +++ b/frontend/src/components/pages/main/Messages.svelte @@ -3,16 +3,22 @@ export let channelId; - const messages = messagesStoreProvider.getStore(channelId); - if (!messages.didInitialLoad) - messages.doInitialLoad(); + $: messages = messagesStoreProvider.getStore(channelId); + $: { + if (!messages.didDoInitialLoad) { + messages.doInitialLoad(); + } + } const onScroll = (e) => { const { scrollTop, offsetHeight, scrollHeight } = e.target; + if (scrollTop === 0) { + messages.loadOlderMessages(); + } if ((scrollTop + offsetHeight) >= scrollHeight) { - setIsCollectingOldMessages(true); + messages.setIsCollectingOldMessages(true); } else { - setIsCollectingOldMessages(false); + messages.setIsCollectingOldMessages(false); } }; diff --git a/frontend/src/main.js b/frontend/src/main.js index 5f0c8a7..d695566 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -1,6 +1,7 @@ import App from './components/App.svelte'; import gateway from './gateway'; -import { initStorageDefaults } from './storage'; +import request from './request'; +import { apiRoute, initStorageDefaults } from './storage'; initStorageDefaults(); gateway.init(); @@ -11,6 +12,14 @@ if (loadingElement) { loadingElement.parentElement.removeChild(loadingElement); } +window.__testing = async () => { + for (let i = 0; i < 100; i++) { + await request("POST", apiRoute("channels/6/messages"), true, { + content: `test ${i}` + }); + } +}; + const app = new App({ target: document.body }); diff --git a/frontend/src/request.js b/frontend/src/request.js index e1ac6d5..9b15169 100644 --- a/frontend/src/request.js +++ b/frontend/src/request.js @@ -6,6 +6,7 @@ export default async function(method, endpoint, auth=true, body=null) { }; if (body) { + options.body = JSON.stringify(body); options.headers = { ...options.headers || {}, "Content-Type": "application/json" diff --git a/frontend/src/stores.js b/frontend/src/stores.js index 647ce1c..8e11a7d 100644 --- a/frontend/src/stores.js +++ b/frontend/src/stores.js @@ -141,6 +141,7 @@ class MessageStore extends Store { const endpoint = oldestMessage ? `channels/${this.channelId}/messages/?before=${oldestMessage.id}` : `channels/${this.channelId}/messages`; const res = await request("GET", apiRoute(endpoint), true, null); if (res.success && res.ok && res.json && res.json.length > 0) { + res.json.reverse(); this.value = res.json.concat(this.value); this.updated(); } @@ -168,10 +169,10 @@ class MessagesStoreProvider { } getStore(channelId) { - if (!this.storeByChannel[channelId]) { - this.storeByChannel[channelId] = new MessageStore(channelId); + if (!this.storeByChannel.get(channelId)) { + this.storeByChannel.set(channelId, new MessageStore(channelId)); } - return this.storeByChannel[channelId]; + return this.storeByChannel.get(channelId); } } diff --git a/test.rest b/test.rest index 2c263be..7830699 100644 --- a/test.rest +++ b/test.rest @@ -19,13 +19,13 @@ content-type: application/json ### GET http://localhost:3000/api/v1/users/self HTTP/1.1 -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwMzg2NjcyLCJleHAiOjE2NTA1NTk0NzJ9.qoBPvIwm9uFf5ZhEjlo87FUgm3qsCHq-AbcZ_WDrtWY +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwNDA4NTQ1LCJleHAiOjE2NTA1ODEzNDV9.DCt_IpukPaihSGl1N8a5ve5pd75N4aePxR4YKzw98Ss ### POST http://localhost:3000/api/v1/channels HTTP/1.1 content-type: application/json -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwMzg2NjcyLCJleHAiOjE2NTA1NTk0NzJ9.qoBPvIwm9uFf5ZhEjlo87FUgm3qsCHq-AbcZ_WDrtWY +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwNDA4NTQ1LCJleHAiOjE2NTA1ODEzNDV9.DCt_IpukPaihSGl1N8a5ve5pd75N4aePxR4YKzw98Ss { "name": "channel 4" @@ -35,7 +35,7 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6M PUT http://localhost:3000/api/v1/channels/7 HTTP/1.1 content-type: application/json -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwMzg2NjcyLCJleHAiOjE2NTA1NTk0NzJ9.qoBPvIwm9uFf5ZhEjlo87FUgm3qsCHq-AbcZ_WDrtWY +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwNDA4NTQ1LCJleHAiOjE2NTA1ODEzNDV9.DCt_IpukPaihSGl1N8a5ve5pd75N4aePxR4YKzw98Ss #Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjQ5MjU5NDUwLCJleHAiOjE2NDk0MzIyNTB9.JmF9NujFZnln7A-ynNpeyayGBqmR5poAyACYV6RnSQY { @@ -45,24 +45,24 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6M ### DELETE http://localhost:3000/api/v1/channels/9 HTTP/1.1 -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwMzg2NjcyLCJleHAiOjE2NTA1NTk0NzJ9.qoBPvIwm9uFf5ZhEjlo87FUgm3qsCHq-AbcZ_WDrtWY +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwNDA4NTQ1LCJleHAiOjE2NTA1ODEzNDV9.DCt_IpukPaihSGl1N8a5ve5pd75N4aePxR4YKzw98Ss #Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjQ5MjU5NDUwLCJleHAiOjE2NDk0MzIyNTB9.JmF9NujFZnln7A-ynNpeyayGBqmR5poAyACYV6RnSQY ### GET http://localhost:3000/api/v1/channels/1 HTTP/1.1 -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwMzg2NjcyLCJleHAiOjE2NTA1NTk0NzJ9.qoBPvIwm9uFf5ZhEjlo87FUgm3qsCHq-AbcZ_WDrtWY +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwNDA4NTQ1LCJleHAiOjE2NTA1ODEzNDV9.DCt_IpukPaihSGl1N8a5ve5pd75N4aePxR4YKzw98Ss ### GET http://localhost:3000/api/v1/channels HTTP/1.1 -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwMzg2NjcyLCJleHAiOjE2NTA1NTk0NzJ9.qoBPvIwm9uFf5ZhEjlo87FUgm3qsCHq-AbcZ_WDrtWY +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwNDA4NTQ1LCJleHAiOjE2NTA1ODEzNDV9.DCt_IpukPaihSGl1N8a5ve5pd75N4aePxR4YKzw98Ss ### POST http://localhost:3000/api/v1/channels/1/messages HTTP/1.1 content-type: application/json -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwMzg2NjcyLCJleHAiOjE2NTA1NTk0NzJ9.qoBPvIwm9uFf5ZhEjlo87FUgm3qsCHq-AbcZ_WDrtWY +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwNDA4NTQ1LCJleHAiOjE2NTA1ODEzNDV9.DCt_IpukPaihSGl1N8a5ve5pd75N4aePxR4YKzw98Ss { "content": "i love cheese" @@ -71,13 +71,13 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6M ### GET http://localhost:3000/api/v1/channels/5/messages HTTP/1.1 -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwMzg2NjcyLCJleHAiOjE2NTA1NTk0NzJ9.qoBPvIwm9uFf5ZhEjlo87FUgm3qsCHq-AbcZ_WDrtWY +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwNDA4NTQ1LCJleHAiOjE2NTA1ODEzNDV9.DCt_IpukPaihSGl1N8a5ve5pd75N4aePxR4YKzw98Ss ### PUT http://localhost:3000/api/v1/messages/3 HTTP/1.1 content-type: application/json -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwMzg2NjcyLCJleHAiOjE2NTA1NTk0NzJ9.qoBPvIwm9uFf5ZhEjlo87FUgm3qsCHq-AbcZ_WDrtWY +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwNDA4NTQ1LCJleHAiOjE2NTA1ODEzNDV9.DCt_IpukPaihSGl1N8a5ve5pd75N4aePxR4YKzw98Ss { "content": "hello again!" @@ -86,9 +86,9 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6M ### GET http://localhost:3000/api/v1/messages/3 -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwMzg2NjcyLCJleHAiOjE2NTA1NTk0NzJ9.qoBPvIwm9uFf5ZhEjlo87FUgm3qsCHq-AbcZ_WDrtWY +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwNDA4NTQ1LCJleHAiOjE2NTA1ODEzNDV9.DCt_IpukPaihSGl1N8a5ve5pd75N4aePxR4YKzw98Ss ### DELETE http://localhost:3000/api/v1/messages/2 HTTP/1.1 -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwMzg2NjcyLCJleHAiOjE2NTA1NTk0NzJ9.qoBPvIwm9uFf5ZhEjlo87FUgm3qsCHq-AbcZ_WDrtWY +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidHlwZSI6MSwiaWF0IjoxNjUwNDA4NTQ1LCJleHAiOjE2NTA1ODEzNDV9.DCt_IpukPaihSGl1N8a5ve5pd75N4aePxR4YKzw98Ss