124 lines
		
	
	
		
			No EOL
		
	
	
		
			4.3 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			124 lines
		
	
	
		
			No EOL
		
	
	
		
			4.3 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<:Window bind:online />
 | 
						|
<div class="timeline" role="feed" aria-label="{{label}}" on:initialized>
 | 
						|
  <VirtualList component="{{StatusListItem}}"
 | 
						|
               :makeProps
 | 
						|
               items="{{statusIds}}"
 | 
						|
               on:scrollToBottom="onScrollToBottom()"
 | 
						|
               shown="{{initialized}}"
 | 
						|
               footerComponent="{{LoadingFooter}}"
 | 
						|
               showFooter="{{initialized && runningUpdate}}"
 | 
						|
  />
 | 
						|
</div>
 | 
						|
<style>
 | 
						|
  .timeline {
 | 
						|
    min-height: 60vh;
 | 
						|
  }
 | 
						|
</style>
 | 
						|
<script>
 | 
						|
  import { store } from '../_utils/store'
 | 
						|
  import { getTimeline } from '../_utils/mastodon/timelines'
 | 
						|
  import StatusListItem from './StatusListItem.html'
 | 
						|
  import LoadingFooter from './LoadingFooter.html'
 | 
						|
  import VirtualList from './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'
 | 
						|
 | 
						|
  const FETCH_LIMIT = 20
 | 
						|
 | 
						|
  export default {
 | 
						|
    async oncreate() {
 | 
						|
      let statuses = await this.fetchStatusesAndPossiblyFallBack()
 | 
						|
      this.addStatuses(statuses)
 | 
						|
      requestAnimationFrame(() => {
 | 
						|
        requestAnimationFrame((() => {
 | 
						|
          this.set({initialized: true})
 | 
						|
          this.fire('initialized')
 | 
						|
        }))
 | 
						|
      })
 | 
						|
    },
 | 
						|
    data: () => ({
 | 
						|
      StatusListItem: StatusListItem,
 | 
						|
      LoadingFooter: LoadingFooter,
 | 
						|
      statusIds: [],
 | 
						|
      runningUpdate: false,
 | 
						|
      initialized: false
 | 
						|
    }),
 | 
						|
    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}`
 | 
						|
        } else if (timeline.startsWith('tag/')) {
 | 
						|
          let tag = timeline.split('/').slice(-1)[0]
 | 
						|
          return `#${tag} timeline for ${$currentInstance}`
 | 
						|
        } else if (timeline.startsWith('account/')) {
 | 
						|
          let account = timeline.split('/').slice(-1)[0]
 | 
						|
          return `Account #${account} on ${$currentInstance}`
 | 
						|
        }
 | 
						|
      }
 | 
						|
    },
 | 
						|
    store: () => store,
 | 
						|
    components: {
 | 
						|
      VirtualList
 | 
						|
    },
 | 
						|
    methods: {
 | 
						|
      splice: splice,
 | 
						|
      push: push,
 | 
						|
      async onScrollToBottom() {
 | 
						|
        if (!this.get('initialized')) {
 | 
						|
          return
 | 
						|
        }
 | 
						|
        if (this.get('runningUpdate')) {
 | 
						|
          return
 | 
						|
        }
 | 
						|
        mark('onScrollToBottom')
 | 
						|
        this.set({ runningUpdate: true })
 | 
						|
        let newStatuses = await this.fetchStatusesAndPossiblyFallBack()
 | 
						|
        this.set({ runningUpdate: false })
 | 
						|
        this.addStatuses(newStatuses)
 | 
						|
        stop('onScrollToBottom')
 | 
						|
      },
 | 
						|
      addStatuses(newStatuses) {
 | 
						|
        if (process.env.NODE_ENV !== 'production') {
 | 
						|
          console.log('addStatuses()')
 | 
						|
        }
 | 
						|
        let instanceName = this.store.get('instanceName')
 | 
						|
        let timeline = this.get('timeline')
 | 
						|
        /* no await */ database.insertStatuses(instanceName, timeline, newStatuses)
 | 
						|
        let statusIds = this.get('statusIds')
 | 
						|
        if (!statusIds) {
 | 
						|
          return
 | 
						|
        }
 | 
						|
        let newStatusIds = newStatuses.map(status => status.id)
 | 
						|
        let merged = mergeStatuses(statusIds, newStatusIds)
 | 
						|
        this.set({ 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 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
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
</script> |