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