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/>
 | 
			
		||||
 | 
			
		||||
{{#if virtual}}
 | 
			
		||||
| 
						 | 
				
			
			@ -19,6 +20,11 @@
 | 
			
		|||
  import { store } from '../_utils/store'
 | 
			
		||||
 | 
			
		||||
	export default {
 | 
			
		||||
	  oncreate() {
 | 
			
		||||
	    this.observe('online', online => {
 | 
			
		||||
	      this.store.set({online: online})
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
		components: {
 | 
			
		||||
		  VirtualListContainer,
 | 
			
		||||
			Nav
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,3 @@
 | 
			
		|||
<:Window bind:online />
 | 
			
		||||
<div class="timeline" role="feed" aria-label="{{label}}">
 | 
			
		||||
  <VirtualList component="{{StatusListItem}}"
 | 
			
		||||
               :makeProps
 | 
			
		||||
| 
						 | 
				
			
			@ -18,41 +17,16 @@
 | 
			
		|||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
  import { store } from '../../_utils/store'
 | 
			
		||||
  import { getTimeline } from '../../_utils/mastodon/timelines'
 | 
			
		||||
  import { getInstanceInfo } from '../../_utils/mastodon/instance'
 | 
			
		||||
  import StatusListItem from './StatusListItem.html'
 | 
			
		||||
  import LoadingFooter from './LoadingFooter.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 { toast } from '../../_utils/toast'
 | 
			
		||||
  import { database } from '../../_utils/database/database'
 | 
			
		||||
  import { StatusStream } from '../../_utils/mastodon/StatusStream'
 | 
			
		||||
 | 
			
		||||
  const FETCH_LIMIT = 20
 | 
			
		||||
  import { initializeTimeline, fetchStatusesOnScrollToBottom, setupTimeline } from '../../_actions/timeline'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    async oncreate() {
 | 
			
		||||
      let timeline = this.get('timeline')
 | 
			
		||||
      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()
 | 
			
		||||
      }
 | 
			
		||||
      setupTimeline()
 | 
			
		||||
    },
 | 
			
		||||
    data: () => ({
 | 
			
		||||
      StatusListItem: StatusListItem,
 | 
			
		||||
| 
						 | 
				
			
			@ -77,69 +51,17 @@
 | 
			
		|||
      VirtualList
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      splice: splice,
 | 
			
		||||
      push: push,
 | 
			
		||||
      initialize() {
 | 
			
		||||
        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.store.setForTimeline(instanceName, timeline, {initialized: true})
 | 
			
		||||
          })
 | 
			
		||||
        })
 | 
			
		||||
        initializeTimeline()
 | 
			
		||||
      },
 | 
			
		||||
      async onScrollToBottom() {
 | 
			
		||||
        if (!this.store.get('initialized')) {
 | 
			
		||||
        if (!this.store.get('initialized') || this.store.get('runningUpdate')) {
 | 
			
		||||
          return
 | 
			
		||||
        }
 | 
			
		||||
        if (this.store.get('runningUpdate')) {
 | 
			
		||||
          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
 | 
			
		||||
        fetchStatusesOnScrollToBottom()
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,6 +52,12 @@ class PinaforeStore extends Store {
 | 
			
		|||
    timelines[instanceName] = timelineData
 | 
			
		||||
    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({
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue