156 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			156 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import { store } from '../_store/store'
 | |
| import { getTimeline } from '../_api/timelines'
 | |
| import { toast } from '../_utils/toast'
 | |
| import { mark, stop } from '../_utils/marks'
 | |
| import { concat, mergeArrays } from '../_utils/arrays'
 | |
| import { byItemIds } from '../_utils/sorting'
 | |
| import isEqual from 'lodash-es/isEqual'
 | |
| import { database } from '../_database/database'
 | |
| import { getStatus, getStatusContext } from '../_api/statuses'
 | |
| import { emit } from '../_utils/eventBus'
 | |
| import { TIMELINE_BATCH_SIZE } from '../_static/timelines'
 | |
| 
 | |
| async function storeFreshTimelineItemsInDatabase (instanceName, timelineName, items) {
 | |
|   await database.insertTimelineItems(instanceName, timelineName, items)
 | |
|   if (timelineName.startsWith('status/')) {
 | |
|     // For status threads, we want to be sure to update the favorite/reblog counts even if
 | |
|     // this is a stale "view" of the status. See 119-status-counts-update.js for
 | |
|     // an example of why we need this.
 | |
|     items.forEach(item => {
 | |
|       emit('statusUpdated', item)
 | |
|     })
 | |
|   }
 | |
| }
 | |
| 
 | |
| async function fetchTimelineItemsFromNetwork (instanceName, accessToken, timelineName, lastTimelineItemId) {
 | |
|   if (timelineName.startsWith('status/')) { // special case - this is a list of descendents and ancestors
 | |
|     let statusId = timelineName.split('/').slice(-1)[0]
 | |
|     let statusRequest = getStatus(instanceName, accessToken, statusId)
 | |
|     let contextRequest = getStatusContext(instanceName, accessToken, statusId)
 | |
|     let [ status, context ] = await Promise.all([statusRequest, contextRequest])
 | |
|     return concat(context.ancestors, status, context.descendants)
 | |
|   } else { // normal timeline
 | |
|     return getTimeline(instanceName, accessToken, timelineName, lastTimelineItemId, null, TIMELINE_BATCH_SIZE)
 | |
|   }
 | |
| }
 | |
| 
 | |
| async function fetchTimelineItems (instanceName, accessToken, timelineName, lastTimelineItemId, online) {
 | |
|   mark('fetchTimelineItems')
 | |
|   let items
 | |
|   let stale = false
 | |
|   if (!online) {
 | |
|     items = await database.getTimeline(instanceName, timelineName, lastTimelineItemId, TIMELINE_BATCH_SIZE)
 | |
|     stale = true
 | |
|   } else {
 | |
|     try {
 | |
|       console.log('fetchTimelineItemsFromNetwork')
 | |
|       items = await fetchTimelineItemsFromNetwork(instanceName, accessToken, timelineName, lastTimelineItemId)
 | |
|       /* no await */ storeFreshTimelineItemsInDatabase(instanceName, timelineName, items)
 | |
|     } catch (e) {
 | |
|       console.error(e)
 | |
|       toast.say('Internet request failed. Showing offline content.')
 | |
|       items = await database.getTimeline(instanceName, timelineName, lastTimelineItemId, TIMELINE_BATCH_SIZE)
 | |
|       stale = true
 | |
|     }
 | |
|   }
 | |
|   stop('fetchTimelineItems')
 | |
|   return { items, stale }
 | |
| }
 | |
| 
 | |
| async function addTimelineItems (instanceName, timelineName, items, stale) {
 | |
|   console.log('addTimelineItems, length:', items.length)
 | |
|   mark('addTimelineItems')
 | |
|   let newIds = items.map(item => item.id)
 | |
|   addTimelineItemIds(instanceName, timelineName, newIds, stale)
 | |
|   stop('addTimelineItems')
 | |
| }
 | |
| 
 | |
| export async function addTimelineItemIds (instanceName, timelineName, newIds, newStale) {
 | |
|   let oldIds = store.getForTimeline(instanceName, timelineName, 'timelineItemIds')
 | |
|   let oldStale = store.getForTimeline(instanceName, timelineName, 'timelineItemIdsAreStale')
 | |
| 
 | |
|   let mergedIds = mergeArrays(oldIds || [], newIds)
 | |
| 
 | |
|   if (!isEqual(oldIds, mergedIds)) {
 | |
|     store.setForTimeline(instanceName, timelineName, { timelineItemIds: mergedIds })
 | |
|   }
 | |
|   if (oldStale !== newStale) {
 | |
|     store.setForTimeline(instanceName, timelineName, { timelineItemIdsAreStale: newStale })
 | |
|   }
 | |
| }
 | |
| 
 | |
| async function fetchTimelineItemsAndPossiblyFallBack () {
 | |
|   mark('fetchTimelineItemsAndPossiblyFallBack')
 | |
|   let {
 | |
|     currentTimeline,
 | |
|     currentInstance,
 | |
|     accessToken,
 | |
|     lastTimelineItemId,
 | |
|     online
 | |
|   } = store.get()
 | |
| 
 | |
|   let { items, stale } = await fetchTimelineItems(currentInstance, accessToken, currentTimeline, lastTimelineItemId, online)
 | |
|   addTimelineItems(currentInstance, currentTimeline, items, stale)
 | |
|   stop('fetchTimelineItemsAndPossiblyFallBack')
 | |
| }
 | |
| 
 | |
| export async function setupTimeline () {
 | |
|   mark('setupTimeline')
 | |
|   // If we don't have any item ids, or if the current item ids are stale
 | |
|   // (i.e. via offline mode), then we need to re-fetch
 | |
|   // Also do this if it's a thread, because threads change pretty frequently and
 | |
|   // we don't have a good way to update them.
 | |
|   let {
 | |
|     timelineItemIds,
 | |
|     timelineItemIdsAreStale,
 | |
|     currentTimeline
 | |
|   } = store.get()
 | |
|   if (!timelineItemIds ||
 | |
|       timelineItemIdsAreStale ||
 | |
|       currentTimeline.startsWith('status/')) {
 | |
|     await fetchTimelineItemsAndPossiblyFallBack()
 | |
|   }
 | |
|   stop('setupTimeline')
 | |
| }
 | |
| 
 | |
| export async function fetchTimelineItemsOnScrollToBottom (instanceName, timelineName) {
 | |
|   console.log('setting runningUpdate: true')
 | |
|   store.setForTimeline(instanceName, timelineName, { runningUpdate: true })
 | |
|   await fetchTimelineItemsAndPossiblyFallBack()
 | |
|   console.log('setting runningUpdate: false')
 | |
|   store.setForTimeline(instanceName, timelineName, { runningUpdate: false })
 | |
| }
 | |
| 
 | |
| export async function showMoreItemsForTimeline (instanceName, timelineName) {
 | |
|   mark('showMoreItemsForTimeline')
 | |
|   let itemIdsToAdd = store.getForTimeline(instanceName, timelineName, 'itemIdsToAdd')
 | |
|   itemIdsToAdd = itemIdsToAdd.sort(byItemIds).reverse()
 | |
|   addTimelineItemIds(instanceName, timelineName, itemIdsToAdd, false)
 | |
|   store.setForTimeline(instanceName, timelineName, {
 | |
|     itemIdsToAdd: [],
 | |
|     shouldShowHeader: false,
 | |
|     showHeader: false
 | |
|   })
 | |
|   stop('showMoreItemsForTimeline')
 | |
| }
 | |
| 
 | |
| export async function showMoreItemsForCurrentTimeline () {
 | |
|   let { currentInstance, currentTimeline } = store.get()
 | |
|   return showMoreItemsForTimeline(
 | |
|     currentInstance,
 | |
|     currentTimeline
 | |
|   )
 | |
| }
 | |
| 
 | |
| export async function showMoreItemsForThread (instanceName, timelineName) {
 | |
|   mark('showMoreItemsForThread')
 | |
|   let itemIdsToAdd = store.getForTimeline(instanceName, timelineName, 'itemIdsToAdd')
 | |
|   let timelineItemIds = store.getForTimeline(instanceName, timelineName, 'timelineItemIds')
 | |
|   // TODO: update database and do the thread merge correctly
 | |
|   timelineItemIds = timelineItemIds.concat(itemIdsToAdd)
 | |
|   store.setForTimeline(instanceName, timelineName, {
 | |
|     itemIdsToAdd: [],
 | |
|     timelineItemIds: timelineItemIds
 | |
|   })
 | |
|   stop('showMoreItemsForThread')
 | |
| }
 |