refs #355 Update tag timeline with stream and lazy fetch past timeline
This commit is contained in:
parent
ad1f0aa662
commit
59e2fde554
|
@ -514,6 +514,46 @@ ipcMain.on('start-list-streaming', (event, obj) => {
|
|||
})
|
||||
})
|
||||
|
||||
ipcMain.on('stop-list-streaming', (event, _) => {
|
||||
listStreaming.stop()
|
||||
listStreaming = null
|
||||
})
|
||||
|
||||
let tagStreaming = null
|
||||
|
||||
ipcMain.on('start-tag-streaming', (event, obj) => {
|
||||
const account = new Account(accountDB)
|
||||
account.getAccount(obj.account._id)
|
||||
.catch((err) => {
|
||||
log.error(err)
|
||||
event.sender.send('error-start-tag-streaming', err)
|
||||
})
|
||||
.then((account) => {
|
||||
// Stop old tag streaming
|
||||
if (tagStreaming !== null) {
|
||||
tagStreaming.stop()
|
||||
tagStreaming = null
|
||||
}
|
||||
|
||||
tagStreaming = new Streaming(account)
|
||||
tagStreaming.start(
|
||||
`/streaming/hashtag?tag=${obj.tag}`,
|
||||
(update) => {
|
||||
event.sender.send('update-start-tag-streaming', update)
|
||||
},
|
||||
(err) => {
|
||||
log.error(err)
|
||||
event.sender.send('error-start-tag-streaming', err)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('stop-list-streaming', (event, _) => {
|
||||
listStreaming.stop()
|
||||
listStreaming = null
|
||||
})
|
||||
|
||||
// sounds
|
||||
ipcMain.on('fav-rt-action-sound', (event, _) => {
|
||||
const preferences = new Preferences(preferencesDBPath)
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
<template>
|
||||
<div id="tag">
|
||||
<transition-group name="timeline" tag="div">
|
||||
<div class="tag-timeline" v-for="message in timeline" v-bind:key="message.id">
|
||||
<toot :message="message" v-on:update="updateToot" v-on:delete="deleteToot"></toot>
|
||||
</div>
|
||||
</transition-group>
|
||||
</div>
|
||||
<div name="tag">
|
||||
<div class="unread">{{ unread.length > 0 ? unread.length : '' }}</div>
|
||||
<transition-group name="timeline" tag="div">
|
||||
<div class="tag-timeline" v-for="message in timeline" v-bind:key="message.id">
|
||||
<toot :message="message" v-on:update="updateToot" v-on:delete="deleteToot"></toot>
|
||||
</div>
|
||||
</transition-group>
|
||||
<div class="loading-card" v-loading="lazyLoading" :element-loading-background="backgroundColor"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -17,29 +19,125 @@ export default {
|
|||
components: { Toot },
|
||||
computed: {
|
||||
...mapState({
|
||||
timeline: state => state.TimelineSpace.Contents.Hashtag.Tag.timeline
|
||||
timeline: state => state.TimelineSpace.Contents.Hashtag.Tag.timeline,
|
||||
lazyLoading: state => state.TimelineSpace.Contents.Hashtag.Tag.lazyLoading,
|
||||
backgroundColor: state => state.App.theme.background_color,
|
||||
heading: state => state.TimelineSpace.Contents.Hashtag.Tag.heading,
|
||||
unread: state => state.TimelineSpace.Contents.Hashtag.Tag.unreadTimeline
|
||||
})
|
||||
},
|
||||
mounted () {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: 'Loading',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.load(this.$route.params.tag)
|
||||
.then(() => {
|
||||
loading.close()
|
||||
})
|
||||
.catch(() => {
|
||||
loading.close()
|
||||
})
|
||||
document.getElementById('scrollable').addEventListener('scroll', this.onScroll)
|
||||
},
|
||||
watch: {
|
||||
'$route': function () {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: 'Loading',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.reset()
|
||||
this.load(this.$route.params.tag)
|
||||
.then(() => {
|
||||
loading.close()
|
||||
})
|
||||
.catch(() => {
|
||||
loading.close()
|
||||
})
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$store.dispatch('TimelineSpace/Contents/Hashtag/Tag/stopStreaming')
|
||||
this.reset()
|
||||
},
|
||||
methods: {
|
||||
load (tag) {
|
||||
this.$store.dispatch('TimelineSpace/Contents/Hashtag/Tag/fetch', tag)
|
||||
async load (tag) {
|
||||
await this.$store.dispatch('TimelineSpace/Contents/Hashtag/Tag/fetch', tag)
|
||||
.catch(() => {
|
||||
this.$message({
|
||||
message: 'Could not fetch timeline',
|
||||
type: 'error'
|
||||
})
|
||||
})
|
||||
this.$store.dispatch('TimelineSpace/Contents/Hashtag/Tag/startStreaming', tag)
|
||||
.catch(() => {
|
||||
this.$message({
|
||||
message: 'Could not start streaming',
|
||||
type: 'error'
|
||||
})
|
||||
})
|
||||
return true
|
||||
},
|
||||
updateToot (messag) {
|
||||
reset () {
|
||||
this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/changeHeading', true)
|
||||
this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/mergeTimeline')
|
||||
this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/archiveTimeline')
|
||||
this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/clearTimeline')
|
||||
if (document.getElementById('scrollable') !== undefined && document.getElementById('scrollable') !== null) {
|
||||
document.getElementById('scrollable').removeEventListener('scroll', this.onScroll)
|
||||
document.getElementById('scrollable').scrollTop = 0
|
||||
}
|
||||
},
|
||||
deleteToot (message) {
|
||||
updateToot (toot) {
|
||||
this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/updateToot', toot)
|
||||
},
|
||||
deleteToot (toot) {
|
||||
this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/deleteToot', toot)
|
||||
},
|
||||
onScroll (event) {
|
||||
if (((event.target.clientHeight + event.target.scrollTop) >= document.getElementsByName('tag')[0].clientHeight - 10) && !this.lazyloading) {
|
||||
this.$store.dispatch('TimelineSpace/Contents/Hashtag/Tag/lazyFetchTimeline', {
|
||||
tag: this.$route.params.tag,
|
||||
last: this.timeline[this.timeline.length - 1]
|
||||
})
|
||||
}
|
||||
// for unread control
|
||||
if ((event.target.scrollTop > 10) && this.heading) {
|
||||
this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/changeHeading', false)
|
||||
} else if ((event.target.scrollTop <= 10) && !this.heading) {
|
||||
this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/changeHeading', true)
|
||||
this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/mergeTimeline')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.unread {
|
||||
position: fixed;
|
||||
right: 24px;
|
||||
top: 48px;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
color: #ffffff;
|
||||
padding: 4px 8px;
|
||||
border-radius: 0 0 2px 2px;
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-card {
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.loading-card:empty {
|
||||
height: 0;
|
||||
}
|
||||
</style>
|
||||
<style src="@/assets/timeline-transition.scss"></style>
|
||||
|
|
|
@ -1,13 +1,69 @@
|
|||
import { ipcRenderer } from 'electron'
|
||||
import Mastodon from 'mastodon-api'
|
||||
|
||||
const Tag = {
|
||||
namespaced: true,
|
||||
state: {
|
||||
timeline: []
|
||||
timeline: [],
|
||||
unreadTimeline: [],
|
||||
lazyLoading: false,
|
||||
heading: true
|
||||
},
|
||||
mutations: {
|
||||
changeHeading (state, value) {
|
||||
state.heading = value
|
||||
},
|
||||
appendTimeline (state, update) {
|
||||
if (state.heading) {
|
||||
state.timeline = [update].concat(state.timeline)
|
||||
} else {
|
||||
state.unreadTimeline = [update].concat(state.unreadTimeline)
|
||||
}
|
||||
},
|
||||
updateTimeline (state, timeline) {
|
||||
state.timeline = timeline
|
||||
},
|
||||
mergeTimeline (state) {
|
||||
state.timeline = state.unreadTimeline.concat(state.timeline)
|
||||
state.unreadTimeline = []
|
||||
},
|
||||
insertTimeline (state, messages) {
|
||||
state.timeline = state.timeline.concat(messages)
|
||||
},
|
||||
archiveTimeline (state) {
|
||||
state.timeline = state.timeline.slice(0, 40)
|
||||
},
|
||||
clearTimeline (state) {
|
||||
state.timeline = []
|
||||
state.unreadTimeline = []
|
||||
},
|
||||
updateToot (state, message) {
|
||||
state.timeline = state.timeline.map((toot) => {
|
||||
if (toot.id === message.id) {
|
||||
return message
|
||||
} else if (toot.reblog !== null && toot.reblog.id === message.id) {
|
||||
// When user reblog/favourite a reblogged toot, target message is a original toot.
|
||||
// So, a message which is received now is original toot.
|
||||
const reblog = {
|
||||
reblog: message
|
||||
}
|
||||
return Object.assign(toot, reblog)
|
||||
} else {
|
||||
return toot
|
||||
}
|
||||
})
|
||||
},
|
||||
deleteToot (state, message) {
|
||||
state.timeline = state.timeline.filter((toot) => {
|
||||
if (toot.reblog !== null && toot.reblog.id === message.id) {
|
||||
return false
|
||||
} else {
|
||||
return toot.id !== message.id
|
||||
}
|
||||
})
|
||||
},
|
||||
changeLazyLoading (state, value) {
|
||||
state.lazyLoading = value
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
|
@ -25,6 +81,49 @@ const Tag = {
|
|||
resolve(res)
|
||||
})
|
||||
})
|
||||
},
|
||||
startStreaming ({ state, commit, rootState }, tag) {
|
||||
ipcRenderer.on('update-start-tag-streaming', (event, update) => {
|
||||
commit('appendTimeline', update)
|
||||
if (state.heading && Math.random() > 0.8) {
|
||||
commit('archiveTimeline')
|
||||
}
|
||||
})
|
||||
return new Promise((resolve, reject) => {
|
||||
ipcRenderer.send('start-tag-streaming', {
|
||||
tag: tag,
|
||||
account: rootState.TimelineSpace.account
|
||||
})
|
||||
ipcRenderer.once('error-start-tag-streaming', (event, err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
stopStreaming ({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
ipcRenderer.removeAllListeners('error-start-tag-streaming')
|
||||
ipcRenderer.removeAllListeners('update-start-tag-streaming')
|
||||
ipcRenderer.send('stop-tag-streaming')
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
lazyFetchTimeline ({ state, commit, rootState }, obj) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (state.lazyLoading) {
|
||||
return resolve()
|
||||
}
|
||||
commit('changeLazyLoading', true)
|
||||
const client = new Mastodon(
|
||||
{
|
||||
access_token: rootState.TimelineSpace.account.accessToken,
|
||||
api_url: rootState.TimelineSpace.account.baseURL + '/api/v1'
|
||||
})
|
||||
client.get(`/timelines/tag/${obj.tag}`, { max_id: obj.last.id, limit: 40 }, (err, data, res) => {
|
||||
if (err) return reject(err)
|
||||
commit('insertTimeline', data)
|
||||
commit('changeLazyLoading', false)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue