move all timeline data to centralized store
This commit is contained in:
parent
9782cb400f
commit
5f627bf9f1
|
@ -1,7 +1,7 @@
|
||||||
<Nav :page :dynamicPage :dynamicHref :dynamicIcon :dynamicLabel/>
|
<Nav :page :dynamicPage :dynamicHref :dynamicIcon :dynamicLabel/>
|
||||||
|
|
||||||
{{#if virtual}}
|
{{#if virtual}}
|
||||||
<VirtualListContainer realm="{{virtualRealm}}">
|
<VirtualListContainer realm="{{$currentInstance + '/' + virtualRealm}}">
|
||||||
<main>
|
<main>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</main>
|
</main>
|
||||||
|
@ -16,11 +16,13 @@
|
||||||
<script>
|
<script>
|
||||||
import Nav from './Nav.html';
|
import Nav from './Nav.html';
|
||||||
import VirtualListContainer from './virtualList/VirtualListContainer.html'
|
import VirtualListContainer from './virtualList/VirtualListContainer.html'
|
||||||
|
import { store } from '../_utils/store'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
VirtualListContainer,
|
VirtualListContainer,
|
||||||
Nav
|
Nav
|
||||||
}
|
},
|
||||||
|
store: () => store
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="lazy-timeline">
|
<div class="lazy-timeline">
|
||||||
{{#if loading}}
|
{{#if !$initialized}}
|
||||||
<div transition:fade>
|
<div transition:fade>
|
||||||
<div class="loading-page">
|
<div class="loading-page">
|
||||||
<LoadingSpinner />
|
<LoadingSpinner />
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#await promise}}
|
{{#await promise}}
|
||||||
{{then constructor}}
|
{{then constructor}}
|
||||||
<:Component {constructor} :timeline on:initialized="set({'loading': false})"/>
|
<:Component {constructor} :timeline />
|
||||||
{{catch error}}
|
{{catch error}}
|
||||||
<div>Component failed to load. Please try refreshing! {{error}}</div>
|
<div>Component failed to load. Please try refreshing! {{error}}</div>
|
||||||
{{/await}}
|
{{/await}}
|
||||||
|
@ -34,11 +34,18 @@
|
||||||
import { importTimeline } from '../_utils/asyncModules'
|
import { importTimeline } from '../_utils/asyncModules'
|
||||||
import LoadingSpinner from './LoadingSpinner.html'
|
import LoadingSpinner from './LoadingSpinner.html'
|
||||||
import { fade } from 'svelte-transitions'
|
import { fade } from 'svelte-transitions'
|
||||||
|
import { store } from '../_utils/store'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
oncreate() {
|
||||||
|
let instanceName = this.store.get('currentInstance')
|
||||||
|
let timeline = this.get('timeline')
|
||||||
|
this.store.set({currentTimeline: timeline})
|
||||||
|
this.store.setForTimeline(instanceName, timeline, {runningUpdate: false})
|
||||||
|
},
|
||||||
|
store: () => store,
|
||||||
data: () => ({
|
data: () => ({
|
||||||
promise: importTimeline(),
|
promise: importTimeline()
|
||||||
loading: true
|
|
||||||
}),
|
}),
|
||||||
components: {
|
components: {
|
||||||
LoadingSpinner
|
LoadingSpinner
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<:Window bind:online />
|
<:Window bind:online />
|
||||||
<div class="timeline" role="feed" aria-label="{{label}}" on:initialized>
|
<div class="timeline" role="feed" aria-label="{{label}}">
|
||||||
<VirtualList component="{{StatusListItem}}"
|
<VirtualList component="{{StatusListItem}}"
|
||||||
:makeProps
|
:makeProps
|
||||||
items="{{statusIds}}"
|
items="{{$statusIds}}"
|
||||||
on:scrollToBottom="onScrollToBottom()"
|
on:scrollToBottom="onScrollToBottom()"
|
||||||
shown="{{initialized}}"
|
shown="{{$initialized}}"
|
||||||
footerComponent="{{LoadingFooter}}"
|
footerComponent="{{LoadingFooter}}"
|
||||||
showFooter="{{initialized && runningUpdate}}"
|
showFooter="{{$initialized && $runningUpdate}}"
|
||||||
realm="{{timeline}}"
|
realm="{{$currentInstance + '/' + timeline}}"
|
||||||
on:initializedVisibleItems="initialize()"
|
on:initializedVisibleItems="initialize()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -31,12 +31,6 @@
|
||||||
import { database } from '../_utils/database/database'
|
import { database } from '../_utils/database/database'
|
||||||
import { StatusStream } from '../_utils/mastodon/StatusStream'
|
import { StatusStream } from '../_utils/mastodon/StatusStream'
|
||||||
|
|
||||||
const cachedTimelines = {}
|
|
||||||
|
|
||||||
if (process.browser && process.env.NODE_ENV !== 'production') {
|
|
||||||
window.cachedTimelines = cachedTimelines
|
|
||||||
}
|
|
||||||
|
|
||||||
const FETCH_LIMIT = 20
|
const FETCH_LIMIT = 20
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -44,10 +38,7 @@
|
||||||
let timeline = this.get('timeline')
|
let timeline = this.get('timeline')
|
||||||
let instanceName = this.store.get('currentInstance')
|
let instanceName = this.store.get('currentInstance')
|
||||||
let accessToken = this.store.get('accessToken')
|
let accessToken = this.store.get('accessToken')
|
||||||
let cachedStatusIds = cachedTimelines[timeline]
|
if (!this.store.get('statusIds').length) {
|
||||||
if (cachedStatusIds) {
|
|
||||||
this.set({statusIds: cachedStatusIds})
|
|
||||||
} else {
|
|
||||||
this.addStatuses(await this.fetchStatusesAndPossiblyFallBack())
|
this.addStatuses(await this.fetchStatusesAndPossiblyFallBack())
|
||||||
}
|
}
|
||||||
/* no await */ getInstanceInfo(instanceName).then(instanceInfo => database.setInstanceInfo(instanceName, instanceInfo))
|
/* no await */ getInstanceInfo(instanceName).then(instanceInfo => database.setInstanceInfo(instanceName, instanceInfo))
|
||||||
|
@ -62,18 +53,13 @@
|
||||||
if (this._statusStream) {
|
if (this._statusStream) {
|
||||||
this._statusStream.close()
|
this._statusStream.close()
|
||||||
}
|
}
|
||||||
cachedTimelines[this.get('timeline')] = this.get('statusIds')
|
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
StatusListItem: StatusListItem,
|
StatusListItem: StatusListItem,
|
||||||
LoadingFooter: LoadingFooter,
|
LoadingFooter: LoadingFooter
|
||||||
statusIds: [],
|
|
||||||
runningUpdate: false,
|
|
||||||
initialized: false
|
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
makeProps: ($currentInstance) => (statusId) => database.getStatus($currentInstance, statusId),
|
makeProps: ($currentInstance) => (statusId) => database.getStatus($currentInstance, statusId),
|
||||||
lastStatusId: (statusIds) => statusIds.length && statusIds[statusIds.length - 1],
|
|
||||||
label: (timeline, $currentInstance) => {
|
label: (timeline, $currentInstance) => {
|
||||||
if (timelines[timeline]) {
|
if (timelines[timeline]) {
|
||||||
`${timelines[timeline].label} timeline for ${$currentInstance}`
|
`${timelines[timeline].label} timeline for ${$currentInstance}`
|
||||||
|
@ -94,27 +80,30 @@
|
||||||
splice: splice,
|
splice: splice,
|
||||||
push: push,
|
push: push,
|
||||||
initialize() {
|
initialize() {
|
||||||
if (this.get('initialized') || !this.get('statusIds') || !this.get('statusIds').length) {
|
if (this.store.get('initialized') || !this.store.get('statusIds') || !this.store.get('statusIds').length) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
let instanceName = this.store.get('currentInstance')
|
||||||
|
let timeline = this.get('timeline')
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
this.set({initialized: true})
|
this.store.setForTimeline(instanceName, timeline, {initialized: true})
|
||||||
this.fire('initialized')
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
async onScrollToBottom() {
|
async onScrollToBottom() {
|
||||||
if (!this.get('initialized')) {
|
if (!this.store.get('initialized')) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (this.get('runningUpdate')) {
|
if (this.store.get('runningUpdate')) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mark('onScrollToBottom')
|
mark('onScrollToBottom')
|
||||||
this.set({ runningUpdate: true })
|
let timeline = this.get('timeline')
|
||||||
|
let instanceName = this.store.get('currentInstance')
|
||||||
|
this.store.setForTimeline(instanceName, timeline, { runningUpdate: true })
|
||||||
let newStatuses = await this.fetchStatusesAndPossiblyFallBack()
|
let newStatuses = await this.fetchStatusesAndPossiblyFallBack()
|
||||||
this.set({ runningUpdate: false })
|
this.store.setForTimeline(instanceName, timeline, { runningUpdate: false })
|
||||||
this.addStatuses(newStatuses)
|
this.addStatuses(newStatuses)
|
||||||
stop('onScrollToBottom')
|
stop('onScrollToBottom')
|
||||||
},
|
},
|
||||||
|
@ -122,21 +111,21 @@
|
||||||
console.log('addStatuses()')
|
console.log('addStatuses()')
|
||||||
let instanceName = this.store.get('currentInstance')
|
let instanceName = this.store.get('currentInstance')
|
||||||
let timeline = this.get('timeline')
|
let timeline = this.get('timeline')
|
||||||
let statusIds = this.get('statusIds')
|
let statusIds = this.store.get('statusIds')
|
||||||
if (!statusIds) {
|
if (!statusIds) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
/* no await */ database.insertStatuses(instanceName, timeline, newStatuses)
|
/* no await */ database.insertStatuses(instanceName, timeline, newStatuses)
|
||||||
let newStatusIds = newStatuses.map(status => status.id)
|
let newStatusIds = newStatuses.map(status => status.id)
|
||||||
let merged = mergeStatuses(statusIds, newStatusIds)
|
let merged = mergeStatuses(statusIds, newStatusIds)
|
||||||
this.set({ statusIds: merged })
|
this.store.setForTimeline(instanceName, timeline, { statusIds: merged })
|
||||||
},
|
},
|
||||||
async fetchStatusesAndPossiblyFallBack() {
|
async fetchStatusesAndPossiblyFallBack() {
|
||||||
let online = this.get('online')
|
let online = this.get('online')
|
||||||
let instanceName = this.store.get('currentInstance')
|
let instanceName = this.store.get('currentInstance')
|
||||||
let instanceData = this.store.get('currentInstanceData')
|
let instanceData = this.store.get('currentInstanceData')
|
||||||
let timeline = this.get('timeline')
|
let timeline = this.get('timeline')
|
||||||
let lastStatusId = this.get('lastStatusId')
|
let lastStatusId = this.store.get('lastStatusId')
|
||||||
let statuses
|
let statuses
|
||||||
if (!online) {
|
if (!online) {
|
||||||
statuses = await database.getTimeline(instanceName, timeline, lastStatusId, FETCH_LIMIT)
|
statuses = await database.getTimeline(instanceName, timeline, lastStatusId, FETCH_LIMIT)
|
||||||
|
|
|
@ -14,6 +14,9 @@ class AsyncLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(key, node, callback) {
|
observe(key, node, callback) {
|
||||||
|
if (!node) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (this._intersectionObserver) {
|
if (this._intersectionObserver) {
|
||||||
this._onIntersectionCallbacks[key] = (entry) => {
|
this._onIntersectionCallbacks[key] = (entry) => {
|
||||||
callback(getRectFromEntry(entry))
|
callback(getRectFromEntry(entry))
|
||||||
|
@ -27,6 +30,9 @@ class AsyncLayout {
|
||||||
if (key in this._onIntersectionCallbacks) {
|
if (key in this._onIntersectionCallbacks) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (!node) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (this._intersectionObserver) {
|
if (this._intersectionObserver) {
|
||||||
this._intersectionObserver.unobserve(node)
|
this._intersectionObserver.unobserve(node)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ const LOCAL_STORAGE_KEYS = new Set([
|
||||||
])
|
])
|
||||||
|
|
||||||
const LS = process.browser && localStorage
|
const LS = process.browser && localStorage
|
||||||
class LocalStorageStore extends Store {
|
class PinaforeStore extends Store {
|
||||||
|
|
||||||
constructor(state) {
|
constructor(state) {
|
||||||
super(state)
|
super(state)
|
||||||
|
@ -44,9 +44,18 @@ class LocalStorageStore extends Store {
|
||||||
this.keysToStore = {}
|
this.keysToStore = {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setForTimeline(instanceName, timelineName, obj) {
|
||||||
|
console.log('setForTimeline')
|
||||||
|
let timelines = this.get('timelines') || {}
|
||||||
|
let timelineData = timelines[instanceName] || {}
|
||||||
|
timelineData[timelineName] = Object.assign(timelineData[timelineName] || {}, obj)
|
||||||
|
timelines[instanceName] = timelineData
|
||||||
|
this.set({timelines: timelines})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const store = new LocalStorageStore({
|
const store = new PinaforeStore({
|
||||||
instanceNameInSearch: '',
|
instanceNameInSearch: '',
|
||||||
currentRegisteredInstance: null,
|
currentRegisteredInstance: null,
|
||||||
currentRegisteredInstanceName: '',
|
currentRegisteredInstanceName: '',
|
||||||
|
@ -98,6 +107,16 @@ store.compute(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
store.compute('currentTimelineData', ['currentInstance', 'currentTimeline', 'timelines'],
|
||||||
|
(currentInstance, currentTimeline, timelines) => {
|
||||||
|
return ((timelines && timelines[currentInstance]) || {})[currentTimeline] || {}
|
||||||
|
})
|
||||||
|
|
||||||
|
store.compute('statusIds', ['currentTimelineData'], (currentTimelineData) => currentTimelineData.statusIds || [])
|
||||||
|
store.compute('runningUpdate', ['currentTimelineData'], (currentTimelineData) => currentTimelineData.runningUpdate)
|
||||||
|
store.compute('initialized', ['currentTimelineData'], (currentTimelineData) => currentTimelineData.initialized)
|
||||||
|
store.compute('lastStatusId', ['statusIds'], (statusIds) => statusIds.length && statusIds[statusIds.length - 1])
|
||||||
|
|
||||||
if (process.browser && process.env.NODE_ENV !== 'production') {
|
if (process.browser && process.env.NODE_ENV !== 'production') {
|
||||||
window.store = store // for debugging
|
window.store = store // for debugging
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue