forked from cybrespace/pinafore
		
	refactor timeline to use actions
This commit is contained in:
		
							parent
							
								
									c0c7e9fafe
								
							
						
					
					
						commit
						de248a9b1f
					
				
					 5 changed files with 111 additions and 83 deletions
				
			
		
							
								
								
									
										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…
	
	Add table
		
		Reference in a new issue