refactor timeline to use actions
This commit is contained in:
parent
c0c7e9fafe
commit
de248a9b1f
94
routes/_actions/timeline.js
Normal file
94
routes/_actions/timeline.js
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import { store } from '../_utils/store'
|
||||||
|
import { database } from '../_utils/database/database'
|
||||||
|
import { getTimeline } from '../_utils/mastodon/timelines'
|
||||||
|
import { toast } from '../_utils/toast'
|
||||||
|
import { StatusStream } from '../_utils/mastodon/StatusStream'
|
||||||
|
import { getInstanceInfo } from '../_utils/mastodon/instance'
|
||||||
|
import { mark, stop } from '../_utils/marks'
|
||||||
|
import { mergeStatuses } from '../_utils/timelines'
|
||||||
|
|
||||||
|
const FETCH_LIMIT = 20
|
||||||
|
|
||||||
|
let statusStream
|
||||||
|
|
||||||
|
async function fetchStatuses(instanceName, accessToken, timelineName, lastStatusId, online) {
|
||||||
|
mark('fetchStatuses')
|
||||||
|
let statuses
|
||||||
|
if (!online) {
|
||||||
|
statuses = await database.getTimeline(instanceName, timelineName, lastStatusId, FETCH_LIMIT)
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
statuses = await getTimeline(instanceName, accessToken, timelineName, lastStatusId, FETCH_LIMIT)
|
||||||
|
/* no await */ database.insertStatuses(instanceName, timelineName, statuses)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
toast.say('Internet request failed. Showing offline content.')
|
||||||
|
statuses = await database.getTimeline(instanceName, timelineName, lastStatusId, FETCH_LIMIT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stop('fetchStatuses')
|
||||||
|
return statuses
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addStatuses(instanceName, timelineName, newStatuses) {
|
||||||
|
mark('addStatuses')
|
||||||
|
let newStatusIds = newStatuses.map(status => status.id)
|
||||||
|
let oldStatusIds = store.getForTimeline(instanceName, timelineName, 'statusIds') || []
|
||||||
|
let merged = mergeStatuses(oldStatusIds, newStatusIds)
|
||||||
|
store.setForTimeline(instanceName, timelineName, { statusIds: merged })
|
||||||
|
stop('addStatuses')
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchStatusesAndPossiblyFallBack() {
|
||||||
|
mark('fetchStatusesAndPossiblyFallBack')
|
||||||
|
let timelineName = store.get('currentTimeline')
|
||||||
|
let instanceName = store.get('currentInstance')
|
||||||
|
let accessToken = store.get('accessToken')
|
||||||
|
let lastStatusId = store.get('lastStatusId')
|
||||||
|
let online = store.get('online')
|
||||||
|
|
||||||
|
let newStatuses = await fetchStatuses(instanceName, accessToken, timelineName, lastStatusId, online)
|
||||||
|
addStatuses(instanceName, timelineName, newStatuses)
|
||||||
|
stop('fetchStatusesAndPossiblyFallBack')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initializeTimeline() {
|
||||||
|
mark('initializeTimeline')
|
||||||
|
let instanceName = store.get('currentInstance')
|
||||||
|
let timeline = store.get('currentTimeline')
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
store.setForTimeline(instanceName, timeline, {initialized: true})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
stop('initializeTimeline')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setupTimeline() {
|
||||||
|
mark('addStatuses')
|
||||||
|
let timelineName = store.get('currentTimeline')
|
||||||
|
let instanceName = store.get('currentInstance')
|
||||||
|
let accessToken = store.get('accessToken')
|
||||||
|
if (!store.get('statusIds').length) {
|
||||||
|
await fetchStatusesAndPossiblyFallBack()
|
||||||
|
}
|
||||||
|
/* no await */ getInstanceInfo(instanceName).then(instanceInfo => database.setInstanceInfo(instanceName, instanceInfo))
|
||||||
|
let instanceInfo = await database.getInstanceInfo(instanceName)
|
||||||
|
if (statusStream) {
|
||||||
|
statusStream.close()
|
||||||
|
}
|
||||||
|
statusStream = new StatusStream(instanceInfo.urls.streaming_api, accessToken, timelineName, {
|
||||||
|
onMessage(message) {
|
||||||
|
console.log('message', message)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
stop('addStatuses')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchStatusesOnScrollToBottom() {
|
||||||
|
let timelineName = store.get('currentTimeline')
|
||||||
|
let instanceName = store.get('currentInstance')
|
||||||
|
store.setForTimeline(instanceName, timelineName, { runningUpdate: true })
|
||||||
|
await fetchStatusesAndPossiblyFallBack()
|
||||||
|
store.setForTimeline(instanceName, timelineName, { runningUpdate: false })
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
<:Window bind:online />
|
||||||
<Nav :page :dynamicPage :dynamicHref :dynamicIcon :dynamicLabel/>
|
<Nav :page :dynamicPage :dynamicHref :dynamicIcon :dynamicLabel/>
|
||||||
|
|
||||||
{{#if virtual}}
|
{{#if virtual}}
|
||||||
|
@ -19,6 +20,11 @@
|
||||||
import { store } from '../_utils/store'
|
import { store } from '../_utils/store'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
oncreate() {
|
||||||
|
this.observe('online', online => {
|
||||||
|
this.store.set({online: online})
|
||||||
|
})
|
||||||
|
},
|
||||||
components: {
|
components: {
|
||||||
VirtualListContainer,
|
VirtualListContainer,
|
||||||
Nav
|
Nav
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
<:Window bind:online />
|
|
||||||
<div class="timeline" role="feed" aria-label="{{label}}">
|
<div class="timeline" role="feed" aria-label="{{label}}">
|
||||||
<VirtualList component="{{StatusListItem}}"
|
<VirtualList component="{{StatusListItem}}"
|
||||||
:makeProps
|
:makeProps
|
||||||
|
@ -18,41 +17,16 @@
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import { store } from '../../_utils/store'
|
import { store } from '../../_utils/store'
|
||||||
import { getTimeline } from '../../_utils/mastodon/timelines'
|
|
||||||
import { getInstanceInfo } from '../../_utils/mastodon/instance'
|
|
||||||
import StatusListItem from './StatusListItem.html'
|
import StatusListItem from './StatusListItem.html'
|
||||||
import LoadingFooter from './LoadingFooter.html'
|
import LoadingFooter from './LoadingFooter.html'
|
||||||
import VirtualList from '../virtualList/VirtualList.html'
|
import VirtualList from '../virtualList/VirtualList.html'
|
||||||
import { splice, push } from 'svelte-extras'
|
|
||||||
import { mergeStatuses } from '../../_utils/statuses'
|
|
||||||
import { mark, stop } from '../../_utils/marks'
|
|
||||||
import { timelines } from '../../_static/timelines'
|
import { timelines } from '../../_static/timelines'
|
||||||
import { toast } from '../../_utils/toast'
|
|
||||||
import { database } from '../../_utils/database/database'
|
import { database } from '../../_utils/database/database'
|
||||||
import { StatusStream } from '../../_utils/mastodon/StatusStream'
|
import { initializeTimeline, fetchStatusesOnScrollToBottom, setupTimeline } from '../../_actions/timeline'
|
||||||
|
|
||||||
const FETCH_LIMIT = 20
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async oncreate() {
|
async oncreate() {
|
||||||
let timeline = this.get('timeline')
|
setupTimeline()
|
||||||
let instanceName = this.store.get('currentInstance')
|
|
||||||
let accessToken = this.store.get('accessToken')
|
|
||||||
if (!this.store.get('statusIds').length) {
|
|
||||||
this.addStatuses(await this.fetchStatusesAndPossiblyFallBack())
|
|
||||||
}
|
|
||||||
/* no await */ getInstanceInfo(instanceName).then(instanceInfo => database.setInstanceInfo(instanceName, instanceInfo))
|
|
||||||
let instanceInfo = await database.getInstanceInfo(instanceName)
|
|
||||||
this._statusStream = new StatusStream(instanceInfo.urls.streaming_api, accessToken, timeline, {
|
|
||||||
onMessage(message) {
|
|
||||||
console.log('message', message)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
ondestroy() {
|
|
||||||
if (this._statusStream) {
|
|
||||||
this._statusStream.close()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
StatusListItem: StatusListItem,
|
StatusListItem: StatusListItem,
|
||||||
|
@ -77,69 +51,17 @@
|
||||||
VirtualList
|
VirtualList
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
splice: splice,
|
|
||||||
push: push,
|
|
||||||
initialize() {
|
initialize() {
|
||||||
if (this.store.get('initialized') || !this.store.get('statusIds') || !this.store.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')
|
initializeTimeline()
|
||||||
let timeline = this.get('timeline')
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
this.store.setForTimeline(instanceName, timeline, {initialized: true})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
async onScrollToBottom() {
|
async onScrollToBottom() {
|
||||||
if (!this.store.get('initialized')) {
|
if (!this.store.get('initialized') || this.store.get('runningUpdate')) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (this.store.get('runningUpdate')) {
|
fetchStatusesOnScrollToBottom()
|
||||||
return
|
|
||||||
}
|
|
||||||
mark('onScrollToBottom')
|
|
||||||
let timeline = this.get('timeline')
|
|
||||||
let instanceName = this.store.get('currentInstance')
|
|
||||||
this.store.setForTimeline(instanceName, timeline, { runningUpdate: true })
|
|
||||||
let newStatuses = await this.fetchStatusesAndPossiblyFallBack()
|
|
||||||
this.store.setForTimeline(instanceName, timeline, { runningUpdate: false })
|
|
||||||
this.addStatuses(newStatuses)
|
|
||||||
stop('onScrollToBottom')
|
|
||||||
},
|
|
||||||
addStatuses(newStatuses) {
|
|
||||||
console.log('addStatuses()')
|
|
||||||
let instanceName = this.store.get('currentInstance')
|
|
||||||
let timeline = this.get('timeline')
|
|
||||||
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.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.store.get('lastStatusId')
|
|
||||||
let statuses
|
|
||||||
if (!online) {
|
|
||||||
statuses = await database.getTimeline(instanceName, timeline, lastStatusId, FETCH_LIMIT)
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
statuses = await getTimeline(instanceName, instanceData.access_token, timeline, lastStatusId, FETCH_LIMIT)
|
|
||||||
/* no await */ database.insertStatuses(instanceName, timeline, statuses)
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e)
|
|
||||||
toast.say('Internet request failed. Showing offline content.')
|
|
||||||
statuses = await database.getTimeline(instanceName, timeline, lastStatusId, FETCH_LIMIT)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return statuses
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,12 @@ class PinaforeStore extends Store {
|
||||||
timelines[instanceName] = timelineData
|
timelines[instanceName] = timelineData
|
||||||
this.set({timelines: timelines})
|
this.set({timelines: timelines})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getForTimeline(instanceName, timelineName, key) {
|
||||||
|
let timelines = this.get('timelines') || {}
|
||||||
|
let timelineData = timelines[instanceName] || {}
|
||||||
|
return (timelineData[timelineName] || {})[key]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const store = new PinaforeStore({
|
const store = new PinaforeStore({
|
||||||
|
|
Loading…
Reference in a new issue