diff --git a/src/main/index.js b/src/main/index.js index 766585f2..159019af 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -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) diff --git a/src/renderer/components/TimelineSpace/Contents/Hashtag/Tag.vue b/src/renderer/components/TimelineSpace/Contents/Hashtag/Tag.vue index 8a8dd392..b384e79d 100644 --- a/src/renderer/components/TimelineSpace/Contents/Hashtag/Tag.vue +++ b/src/renderer/components/TimelineSpace/Contents/Hashtag/Tag.vue @@ -1,11 +1,13 @@ - - - - - - - + + {{ unread.length > 0 ? unread.length : '' }} + + + + + + + diff --git a/src/renderer/store/TimelineSpace/Contents/Hashtag/Tag.js b/src/renderer/store/TimelineSpace/Contents/Hashtag/Tag.js index 73e96f45..9b1cd580 100644 --- a/src/renderer/store/TimelineSpace/Contents/Hashtag/Tag.js +++ b/src/renderer/store/TimelineSpace/Contents/Hashtag/Tag.js @@ -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) + }) + }) } } }