diff --git a/src/renderer/components/TimelineSpace/Contents/SideBar/AccountProfile/Followers.vue b/src/renderer/components/TimelineSpace/Contents/SideBar/AccountProfile/Followers.vue index b41d4978..8dfc62b0 100644 --- a/src/renderer/components/TimelineSpace/Contents/SideBar/AccountProfile/Followers.vue +++ b/src/renderer/components/TimelineSpace/Contents/SideBar/AccountProfile/Followers.vue @@ -8,6 +8,7 @@ +
@@ -22,7 +23,11 @@ export default { computed: { ...mapState('TimelineSpace/Contents/SideBar/AccountProfile/Followers', { followers: state => state.followers, - relationships: state => state.relationships + relationships: state => state.relationships, + lazyLoading: state => state.lazyLoading + }), + ...mapState('App', { + backgroundColor: state => state.theme.background_color }) }, created() { @@ -33,6 +38,14 @@ export default { this.load() } }, + mounted() { + document.getElementById('sidebar_scrollable').addEventListener('scroll', this.onScroll) + }, + destroyed() { + if (document.getElementById('sidebar_scrollable') !== undefined && document.getElementById('sidebar_scrollable') !== null) { + document.getElementById('sidebar_scrollable').removeEventListener('scroll', this.onScroll) + } + }, methods: { async load() { this.$store.commit('TimelineSpace/Contents/SideBar/AccountProfile/changeLoading', true) @@ -48,6 +61,21 @@ export default { this.$store.commit('TimelineSpace/Contents/SideBar/AccountProfile/changeLoading', false) } }, + onScroll(event) { + // for lazyLoading + if ( + event.target.clientHeight + event.target.scrollTop >= document.getElementById('account_profile').clientHeight - 10 && + !this.lazyloading + ) { + this.$store.dispatch('TimelineSpace/Contents/SideBar/AccountProfile/Followers/lazyFetchFollowers', this.account).catch(err => { + console.error(err) + this.$message({ + message: this.$t('message.timeline_fetch_error'), + type: 'error' + }) + }) + } + }, targetRelation(id) { return this.relationships.find(r => r.id === id) }, @@ -83,4 +111,12 @@ export default { } - + diff --git a/src/renderer/store/TimelineSpace/Contents/SideBar/AccountProfile/Followers.ts b/src/renderer/store/TimelineSpace/Contents/SideBar/AccountProfile/Followers.ts index 6a0c0afd..c43d4f68 100644 --- a/src/renderer/store/TimelineSpace/Contents/SideBar/AccountProfile/Followers.ts +++ b/src/renderer/store/TimelineSpace/Contents/SideBar/AccountProfile/Followers.ts @@ -1,28 +1,45 @@ import generator, { Entity } from 'megalodon' +import parse from 'parse-link-header' import { Module, MutationTree, ActionTree } from 'vuex' import { RootState } from '@/store' export type FollowersState = { followers: Array relationships: Array + lazyLoading: boolean + maxId: string | null } const state = (): FollowersState => ({ followers: [], - relationships: [] + relationships: [], + lazyLoading: false, + maxId: null }) export const MUTATION_TYPES = { UPDATE_FOLLOWERS: 'updateFollowers', - UPDATE_RELATIONSHIPS: 'updateRelationships' + APPEND_FOLLOWERS: 'appendFollowers', + UPDATE_RELATIONSHIPS: 'updateRelationships', + CHANGE_LAZY_LOADING: 'changeLazyLoading', + CHANGE_MAX_ID: 'changeMaxId' } const mutations: MutationTree = { [MUTATION_TYPES.UPDATE_FOLLOWERS]: (state, users: Array) => { state.followers = users }, + [MUTATION_TYPES.APPEND_FOLLOWERS]: (state, users: Array) => { + state.followers = state.followers.concat(users) + }, [MUTATION_TYPES.UPDATE_RELATIONSHIPS]: (state, relations: Array) => { state.relationships = relations + }, + [MUTATION_TYPES.CHANGE_LAZY_LOADING]: (state, loading: boolean) => { + state.lazyLoading = loading + }, + [MUTATION_TYPES.CHANGE_MAX_ID]: (state, maxId: string | null) => { + state.maxId = maxId } } @@ -36,6 +53,51 @@ const actions: ActionTree = { ) const res = await client.getAccountFollowers(account.id, { limit: 80 }) commit(MUTATION_TYPES.UPDATE_FOLLOWERS, res.data) + // Parse link header + try { + const link = parse(res.headers.link) + if (link !== null) { + commit(MUTATION_TYPES.CHANGE_MAX_ID, link.next.max_id) + } else { + commit(MUTATION_TYPES.CHANGE_MAX_ID, null) + } + } catch (err) { + commit(MUTATION_TYPES.CHANGE_MAX_ID, null) + console.error(err) + } + return res.data + }, + lazyFetchFollowers: async ({ commit, state, rootState }, account: Entity.Account) => { + if (state.lazyLoading) { + return Promise.resolve(null) + } + if (!state.maxId) { + return Promise.resolve(null) + } + commit(MUTATION_TYPES.CHANGE_LAZY_LOADING, true) + const client = generator( + rootState.TimelineSpace.sns, + rootState.TimelineSpace.account.baseURL, + rootState.TimelineSpace.account.accessToken, + rootState.App.userAgent + ) + const res = await client.getAccountFollowers(account.id, { limit: 80, max_id: state.maxId }).finally(() => { + commit(MUTATION_TYPES.CHANGE_LAZY_LOADING, false) + }) + + commit(MUTATION_TYPES.APPEND_FOLLOWERS, res.data) + // Parse link header + try { + const link = parse(res.headers.link) + if (link !== null) { + commit(MUTATION_TYPES.CHANGE_MAX_ID, link.next.max_id) + } else { + commit(MUTATION_TYPES.CHANGE_MAX_ID, null) + } + } catch (err) { + commit(MUTATION_TYPES.CHANGE_MAX_ID, null) + console.error(err) + } return res.data }, fetchRelationships: async ({ commit, rootState }, accounts: Array) => {