Whalebird-desktop-client-ma.../src/renderer/store/TimelineSpace.js

266 lines
8.4 KiB
JavaScript

import { ipcRenderer } from 'electron'
import Mastodon from 'mastodon-api'
import SideMenu from './TimelineSpace/SideMenu'
import HeaderMenu from './TimelineSpace/HeaderMenu'
import Modals from './TimelineSpace/Modals'
import Contents from './TimelineSpace/Contents'
import router from '../router'
const TimelineSpace = {
namespaced: true,
modules: {
SideMenu,
HeaderMenu,
Modals,
Contents
},
state: {
account: {
domain: '',
_id: '',
username: ''
},
homeTimeline: [],
notifications: []
},
mutations: {
updateAccount (state, account) {
state.account = account
},
appendHomeTimeline (state, update) {
state.homeTimeline = [update].concat(state.homeTimeline)
},
appendNotifications (state, notification) {
state.notifications = [notification].concat(state.notifications)
},
updateHomeTimeline (state, messages) {
state.homeTimeline = messages
},
updateNotifications (state, notifications) {
state.notifications = notifications
},
insertHomeTimeline (state, messages) {
state.homeTimeline = state.homeTimeline.concat(messages)
},
insertNotifications (state, notifications) {
state.notifications = state.notifications.concat(notifications)
},
updateToot (state, message) {
// Replace target message in homeTimeline and notifications
state.homeTimeline = state.homeTimeline.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
}
})
state.notifications = state.notifications.map((notification) => {
// I want to update toot only mention.
// Because Toot component don't use status information when other patterns.
if (notification.type === 'mention' && notification.status.id === message.id) {
const status = {
status: message
}
return Object.assign(notification, status)
} else {
return notification
}
})
},
clearTimeline (state) {
state.homeTimeline = []
},
clearNotifications (state) {
state.notifications = []
},
archiveHomeTimeline (state) {
state.homeTimeline = state.homeTimeline.slice(0, 40)
},
archiveNotifications (state) {
state.notifications = state.notifications.slice(0, 40)
}
},
actions: {
localAccount ({ dispatch, commit }, id) {
return new Promise((resolve, reject) => {
ipcRenderer.send('get-local-account', id)
ipcRenderer.once('error-get-local-account', (event, err) => {
ipcRenderer.removeAllListeners('response-get-local-account')
reject(err)
})
ipcRenderer.once('response-get-local-account', (event, account) => {
ipcRenderer.removeAllListeners('error-get-local-account')
if (account.username === undefined || account.username === null || account.username === '') {
dispatch('fetchAccount', account)
.then((acct) => {
commit('updateAccount', acct)
resolve(acct)
})
.catch((err) => {
reject(err)
})
} else {
commit('updateAccount', account)
resolve(account)
}
})
})
},
fetchAccount ({ commit }, account) {
return new Promise((resolve, reject) => {
const client = new Mastodon(
{
access_token: account.accessToken,
api_url: account.baseURL + '/api/v1'
})
client.get('/accounts/verify_credentials', (err, data, res) => {
if (err) return reject(err)
ipcRenderer.send('update-account', Object.assign(account, {
username: data.username,
accountId: data.id
}))
ipcRenderer.once('error-update-account', (event, err) => {
ipcRenderer.removeAllListeners('response-update-account')
reject(err)
})
ipcRenderer.once('response-update-account', (event, account) => {
ipcRenderer.removeAllListeners('error-update-account')
resolve(account)
})
})
})
},
startUserStreaming ({ commit }, account) {
ipcRenderer.on('update-start-user-streaming', (event, update) => {
commit('appendHomeTimeline', update)
commit('TimelineSpace/SideMenu/changeUnreadHomeTimeline', true, { root: true })
})
ipcRenderer.on('notification-start-user-streaming', (event, notification) => {
let notify = buildNotification(notification)
notify.onclick = () => {
router.push(`/${account._id}/notifications`)
}
commit('appendNotifications', notification)
commit('TimelineSpace/SideMenu/changeUnreadNotifications', true, { root: true })
})
return new Promise((resolve, reject) => {
ipcRenderer.send('start-user-streaming', account)
ipcRenderer.once('error-start-user-streaming', (event, err) => {
reject(err)
})
})
},
async stopUserStreaming ({ commit }) {
ipcRenderer.removeAllListeners('update-start-user-streaming')
ipcRenderer.removeAllListeners('notification-start-user-streaming')
ipcRenderer.removeAllListeners('error-start-user-streaming')
ipcRenderer.send('stop-user-streaming')
return 'stopUserStreaming'
},
watchShortcutEvents ({ commit }) {
ipcRenderer.on('CmdOrCtrl+N', () => {
commit('TimelineSpace/Modals/NewToot/changeModal', true, { root: true })
})
ipcRenderer.on('CmdOrCtrl+K', () => {
commit('TimelineSpace/Modals/Jump/changeModal', true, { root: true })
})
},
async removeShortcutEvents () {
ipcRenderer.removeAllListeners('CmdOrCtrl+N')
ipcRenderer.removeAllListeners('CmdOrCtrl+K')
return 'removeShortcutEvents'
},
fetchHomeTimeline ({ commit }, account) {
return new Promise((resolve, reject) => {
const client = new Mastodon(
{
access_token: account.accessToken,
api_url: account.baseURL + '/api/v1'
}
)
client.get('/timelines/home', { limit: 40 }, (err, data, res) => {
if (err) return reject(err)
commit('updateHomeTimeline', data)
resolve(res)
})
})
},
fetchNotifications ({ commit }, account) {
return new Promise((resolve, reject) => {
const client = new Mastodon(
{
access_token: account.accessToken,
api_url: account.baseURL + '/api/v1'
}
)
client.get('/notifications', { limit: 30 }, (err, data, res) => {
if (err) return reject(err)
commit('updateNotifications', data)
resolve(res)
})
})
},
async clearTimeline ({ commit }) {
commit('clearTimeline')
return 'clearTimeline'
},
async clearNotifications ({ commit }) {
commit('clearNotifications')
return 'clearNotifications'
},
async clearAccount ({ commit }) {
commit(
'updateAccount',
{
domain: '',
_id: '',
username: ''
}
)
return 'clearAccount'
}
}
}
export default TimelineSpace
function buildNotification (notification) {
switch (notification.type) {
case 'favourite':
return new Notification('Favourite', {
body: `${username(notification.account)} favourited your status`
})
case 'follow':
return new Notification('Follow', {
body: `${username(notification.account)} is now following you`
})
case 'mention':
// Clean html tags
return new Notification(`${notification.status.account.display_name}`, {
body: `${notification.status.content.replace(/<("[^"]*"|'[^']*'|[^'">])*>/g, '')}`
})
case 'reblog':
return new Notification('Reblog', {
body: `${username(notification.account)} boosted your status`
})
}
}
function username (account) {
if (account.display_name !== '') {
return account.display_name
} else {
return account.username
}
}