Merge pull request #875 from h3poteto/iss-850

refs #850 Replace SideBar with typescript
This commit is contained in:
AkiraFukushima 2019-04-12 23:32:24 +09:00 committed by GitHub
commit c0df6001fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 620 additions and 504 deletions

View File

@ -4,7 +4,7 @@ import Mastodon, { Account, Emoji, Instance, Status, Notification as Notificatio
import SideMenu, { SideMenuState } from './TimelineSpace/SideMenu'
import HeaderMenu, { HeaderMenuState } from './TimelineSpace/HeaderMenu'
import Modals, { ModalsModuleState } from './TimelineSpace/Modals'
import Contents from './TimelineSpace/Contents'
import Contents, { ContentsModuleState } from './TimelineSpace/Contents'
import router from '@/router'
import unreadSettings from '~/src/constants/unreadNotification'
import { Module, MutationTree, ActionTree } from 'vuex'
@ -419,8 +419,8 @@ const actions: ActionTree<TimelineSpaceState, any> = {
export interface TimelineSpaceModuleState extends TimelineSpaceState {
SideMenu: SideMenuState,
HeaderMenu: HeaderMenuState,
Modals: ModalsModuleState
// TODO: Contents: ContentsState
Modals: ModalsModuleState,
Contents: ContentsModuleState
}
const TimelineSpace: Module<TimelineSpaceState, any> = {

View File

@ -1,4 +1,4 @@
import SideBar from './Contents/SideBar'
import SideBar, { SideBarModuleState } from './Contents/SideBar'
import Home from './Contents/Home'
import Notifications from './Contents/Notifications'
import Favourites from './Contents/Favourites'
@ -9,9 +9,20 @@ import Lists from './Contents/Lists'
import Hashtag from './Contents/Hashtag'
import DirectMessages from './Contents/DirectMessages'
import Mentions from './Contents/Mentions'
import { Module } from 'vuex'
import { RootState } from '@/store'
const Contents = {
export interface ContentsState {}
export interface ContentsModuleState extends ContentsState {
SideBar: SideBarModuleState
}
const state = (): ContentsState => ({})
const Contents: Module<ContentsState, RootState> = {
namespaced: true,
state: state,
modules: {
SideBar,
Home,

View File

@ -1,40 +0,0 @@
import AccountProfile from './SideBar/AccountProfile'
import TootDetail from './SideBar/TootDetail'
const SideBar = {
namespaced: true,
modules: {
AccountProfile,
TootDetail
},
state: {
openSideBar: false,
// 0: blank
// 1: account-profile
// 2: toot-detail
component: 0
},
mutations: {
changeOpenSideBar (state, value) {
state.openSideBar = value
},
changeComponent (state, value) {
state.component = value
}
},
actions: {
close ({ dispatch, commit }) {
dispatch('TimelineSpace/Contents/SideBar/AccountProfile/close', {}, { root: true })
commit('changeOpenSideBar', false)
commit('changeComponent', 0)
},
openAccountComponent ({ commit }) {
commit('changeComponent', 1)
},
openTootComponent ({ commit }) {
commit('changeComponent', 2)
}
}
}
export default SideBar

View File

@ -0,0 +1,63 @@
import AccountProfile, { AccountProfileModuleState } from './SideBar/AccountProfile'
import TootDetail, { TootDetailState } from './SideBar/TootDetail'
import { Module, MutationTree, ActionTree } from 'vuex'
import { RootState } from '@/store'
export interface SideBarState {
openSideBar: boolean,
// 0: blank
// 1: account-profile
// 2: toot-detail
component: number
}
export interface SideBarModuleState extends SideBarState {
TootDetail: TootDetailState,
AccountProfile: AccountProfileModuleState
}
const state = (): SideBarState => ({
openSideBar: false,
component: 0
})
export const MUTATION_TYPES = {
CHANGE_OPEN_SIDEBAR: 'changeOpenSideBar',
CHANGE_COMPONENT: 'changeComponent'
}
const mutations: MutationTree<SideBarState> = {
[MUTATION_TYPES.CHANGE_OPEN_SIDEBAR]: (state, value: boolean) => {
state.openSideBar = value
},
[MUTATION_TYPES.CHANGE_COMPONENT]: (state, value: number) => {
state.component = value
}
}
const actions: ActionTree<SideBarState, RootState> = {
close: ({ dispatch, commit }) => {
dispatch('TimelineSpace/Contents/SideBar/AccountProfile/close', {}, { root: true })
commit(MUTATION_TYPES.CHANGE_OPEN_SIDEBAR, false)
commit(MUTATION_TYPES.CHANGE_COMPONENT, 0)
},
openAccountComponent: ({ commit }) => {
commit(MUTATION_TYPES.CHANGE_COMPONENT, 1)
},
openTootComponent: ({ commit }) => {
commit(MUTATION_TYPES.CHANGE_COMPONENT, 2)
}
}
const SideBar: Module<SideBarState, RootState> = {
namespaced: true,
modules: {
AccountProfile,
TootDetail
},
state: state,
mutations: mutations,
actions: actions
}
export default SideBar

View File

@ -1,140 +0,0 @@
import Mastodon from 'megalodon'
import Timeline from './AccountProfile/Timeline'
import Follows from './AccountProfile/Follows'
import Followers from './AccountProfile/Followers'
const AccountProfile = {
namespaced: true,
modules: {
Timeline,
Follows,
Followers
},
state: {
account: null,
relationship: null,
loading: false
},
mutations: {
changeAccount (state, account) {
state.account = account
},
changeRelationship (state, relationship) {
state.relationship = relationship
},
changeLoading (state, value) {
state.loading = value
}
},
actions: {
fetchAccount ({ rootState }, accountID) {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.get(`/accounts/${accountID}`)
.then(res => res.data)
},
searchAccount ({ rootState }, parsedAccount) {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.get('/search', { q: parsedAccount.url, resolve: true })
.then(res => {
if (res.data.accounts.length <= 0) throw new AccountNotFound('empty result')
const account = res.data.accounts.find(a => `@${a.acct}` === parsedAccount.acct)
if (account) return account
const pleromaUser = res.data.accounts.find(a => a.acct === parsedAccount.acct)
if (pleromaUser) return pleromaUser
const localUser = res.data.accounts.find(a => `@${a.username}@${rootState.TimelineSpace.account.domain}` === parsedAccount.acct)
if (localUser) return localUser
const user = res.data.accounts.find(a => a.url === parsedAccount.url)
if (!user) throw new AccountNotFound('not found')
return user
})
},
changeAccount ({ commit, dispatch }, account) {
dispatch('fetchRelationship', account)
commit('changeAccount', account)
},
fetchRelationship ({ commit, rootState }, account) {
commit('changeRelationship', null)
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.get('/accounts/relationships', { id: [account.id] })
.then(res => {
commit('changeRelationship', res.data[0])
return res.data
})
},
follow ({ commit, rootState }, account) {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.post(`/accounts/${account.id}/follow`)
.then(res => {
commit('changeRelationship', res.data)
return res.data
})
},
unfollow ({ commit, rootState }, account) {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.post(`/accounts/${account.id}/unfollow`)
.then(res => {
commit('changeRelationship', res.data)
return res.data
})
},
close ({ commit }) {
commit('changeAccount', null)
},
unmute ({ rootState, commit }, account) {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.post(`/accounts/${account.id}/unmute`)
.then(res => {
commit('changeRelationship', res.data)
return res.data
})
},
block ({ rootState, commit }, account) {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.post(`/accounts/${account.id}/block`)
.then(res => {
commit('changeRelationship', res.data)
return res.data
})
},
unblock ({ rootState, commit }, account) {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.post(`/accounts/${account.id}/unblock`)
.then(res => {
commit('changeRelationship', res.data)
return res.data
})
}
}
}
class AccountNotFound {
constructor (msg) {
this.msg = msg
}
}
export default AccountProfile

View File

@ -0,0 +1,148 @@
import Mastodon, { Account, Relationship, Response, Results } from 'megalodon'
import Timeline, { TimelineState } from './AccountProfile/Timeline'
import Follows, { FollowsState } from './AccountProfile/Follows'
import Followers, { FollowersState } from './AccountProfile/Followers'
import { Module, MutationTree, ActionTree } from 'vuex'
import { RootState } from '@/store'
export interface AccountProfileState {
account: Account | null,
relationship: Relationship | null,
loading: boolean
}
export interface AccountProfileModuleState extends AccountProfileState {
Followers: FollowersState,
Follows: FollowsState,
Timeline: TimelineState
}
const state = (): AccountProfileState => ({
account: null,
relationship: null,
loading: false
})
export const MUTATION_TYPES = {
CHANGE_ACCOUNT: 'changeAccount',
CHANGE_RELATIONSHIP: 'changeRelationship',
CHANGE_LOADING: 'changeLoading'
}
const mutations: MutationTree<AccountProfileState> = {
[MUTATION_TYPES.CHANGE_ACCOUNT]: (state, account: Account | null) => {
state.account = account
},
[MUTATION_TYPES.CHANGE_RELATIONSHIP]: (state, relationship: Relationship | null) => {
state.relationship = relationship
},
[MUTATION_TYPES.CHANGE_LOADING]: (state, value: boolean) => {
state.loading = value
}
}
const actions: ActionTree<AccountProfileState, RootState> = {
fetchAccount: async ({ rootState }, accountID: number): Promise<Account> => {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Account> = await client.get<Account>(`/accounts/${accountID}`)
return res.data
},
searchAccount: async ({ rootState }, parsedAccount): Promise<Account> => {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Results> = await client.get<Results>('/search', { q: parsedAccount.url, resolve: true })
if (res.data.accounts.length <= 0) throw new AccountNotFound('empty result')
const account = res.data.accounts.find(a => `@${a.acct}` === parsedAccount.acct)
if (account) return account
const pleromaUser = res.data.accounts.find(a => a.acct === parsedAccount.acct)
if (pleromaUser) return pleromaUser
const localUser = res.data.accounts.find(a => `@${a.username}@${rootState.TimelineSpace.account.domain}` === parsedAccount.acct)
if (localUser) return localUser
const user = res.data.accounts.find(a => a.url === parsedAccount.url)
if (!user) throw new AccountNotFound('not found')
return user
},
changeAccount: ({ commit, dispatch }, account: Account) => {
dispatch('fetchRelationship', account)
commit(MUTATION_TYPES.CHANGE_ACCOUNT, account)
},
fetchRelationship: async ({ commit, rootState }, account: Account): Promise<Relationship> => {
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, null)
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Relationship> = await client.get<Relationship>('/accounts/relationships', { id: [account.id] })
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, res.data[0])
return res.data
},
follow: async ({ commit, rootState }, account: Account) => {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Relationship> = await client.post<Relationship>(`/accounts/${account.id}/follow`)
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, res.data)
return res.data
},
unfollow: async ({ commit, rootState }, account: Account) => {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Relationship> = await client.post<Relationship>(`/accounts/${account.id}/unfollow`)
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, res.data)
return res.data
},
close: ({ commit }) => {
commit(MUTATION_TYPES.CHANGE_ACCOUNT, null)
},
unmute: async ({ rootState, commit }, account: Account) => {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Relationship> = await client.post<Relationship>(`/accounts/${account.id}/unmute`)
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, res.data)
return res.data
},
block: async ({ rootState, commit }, account: Account) => {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Relationship> = await client.post<Relationship>(`/accounts/${account.id}/block`)
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, res.data)
return res.data
},
unblock: async ({ rootState, commit }, account: Account) => {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Relationship> = await client.post<Relationship>(`/accounts/${account.id}/unblock`)
commit(MUTATION_TYPES.CHANGE_RELATIONSHIP, res.data)
return res.data
}
}
const AccountProfile: Module<AccountProfileState, RootState> = {
namespaced: true,
modules: {
Timeline,
Follows,
Followers
},
state: state,
mutations: mutations,
actions: actions
}
class AccountNotFound extends Error {}
export default AccountProfile

View File

@ -1,46 +0,0 @@
import Mastodon from 'megalodon'
const Followers = {
namespaced: true,
state: {
followers: [],
relationships: []
},
mutations: {
updateFollowers (state, users) {
state.followers = users
},
updateRelationships (state, relations) {
state.relationships = relations
}
},
actions: {
fetchFollowers ({ commit, rootState }, account) {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.get(`/accounts/${account.id}/followers`, { limit: 80 })
.then(res => {
commit('updateFollowers', res.data)
return res.data
})
},
fetchRelationships ({ commit, rootState }, accounts) {
const ids = accounts.map(a => a.id)
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.get(`/accounts/relationships`, {
id: ids
})
.then(res => {
commit('updateRelationships', res.data)
return res.data
})
}
}
}
export default Followers

View File

@ -0,0 +1,60 @@
import Mastodon, { Account, Relationship, Response } from 'megalodon'
import { Module, MutationTree, ActionTree } from 'vuex'
import { RootState } from '@/store'
export interface FollowersState {
followers: Array<Account>,
relationships: Array<Relationship>
}
const state = (): FollowersState => ({
followers: [],
relationships: []
})
export const MUTATION_TYPES = {
UPDATE_FOLLOWERS: 'updateFollowers',
UPDATE_RELATIONSHIPS: 'updateRelationships'
}
const mutations: MutationTree<FollowersState> = {
[MUTATION_TYPES.UPDATE_FOLLOWERS]: (state, users: Array<Account>) => {
state.followers = users
},
[MUTATION_TYPES.UPDATE_RELATIONSHIPS]: (state, relations: Array<Relationship>) => {
state.relationships = relations
}
}
const actions: ActionTree<FollowersState, RootState> = {
fetchFollowers: async ({ commit, rootState }, account: Account) => {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Array<Account>> = await client.get<Array<Account>>(`/accounts/${account.id}/followers`, { limit: 80 })
commit(MUTATION_TYPES.UPDATE_FOLLOWERS, res.data)
return res.data
},
fetchRelationships: async ({ commit, rootState }, accounts: Array<Account>) => {
const ids = accounts.map(a => a.id)
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Array<Relationship>> = await client.get<Array<Relationship>>(`/accounts/relationships`, {
id: ids
})
commit(MUTATION_TYPES.UPDATE_RELATIONSHIPS, res.data)
return res.data
}
}
const Followers: Module<FollowersState, RootState> = {
namespaced: true,
state: state,
mutations: mutations,
actions: actions
}
export default Followers

View File

@ -1,46 +0,0 @@
import Mastodon from 'megalodon'
const Follows = {
namespaced: true,
state: {
follows: [],
relationships: []
},
mutations: {
updateFollows (state, users) {
state.follows = users
},
updateRelationships (state, relations) {
state.relationships = relations
}
},
actions: {
fetchFollows ({ commit, rootState }, account) {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.get(`/accounts/${account.id}/following`, { limit: 80 })
.then(res => {
commit('updateFollows', res.data)
return res.data
})
},
fetchRelationships ({ commit, rootState }, accounts) {
const ids = accounts.map(a => a.id)
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.get(`/accounts/relationships`, {
id: ids
})
.then(res => {
commit('updateRelationships', res.data)
return res.data
})
}
}
}
export default Follows

View File

@ -0,0 +1,60 @@
import Mastodon, { Account, Relationship, Response } from 'megalodon'
import { Module, MutationTree, ActionTree } from 'vuex'
import { RootState } from '@/store'
export interface FollowsState {
follows: Array<Account>,
relationships: Array<Relationship>
}
const state = (): FollowsState => ({
follows: [],
relationships: []
})
export const MUTATION_TYPES = {
UPDATE_FOLLOWS: 'updateFollows',
UPDATE_RELATIONSHIPS: 'updateRelationships'
}
const mutations: MutationTree<FollowsState> = {
[MUTATION_TYPES.UPDATE_FOLLOWS]: (state, users: Array<Account>) => {
state.follows = users
},
[MUTATION_TYPES.UPDATE_RELATIONSHIPS]: (state, relations: Array<Relationship>) => {
state.relationships = relations
}
}
const actions: ActionTree<FollowsState, RootState> = {
fetchFollows: async ({ commit, rootState }, account: Account) => {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Array<Account>> = await client.get<Array<Account>>(`/accounts/${account.id}/following`, { limit: 80 })
commit(MUTATION_TYPES.UPDATE_FOLLOWS, res.data)
return res.data
},
fetchRelationships: async ({ commit, rootState }, accounts: Array<Account>) => {
const ids = accounts.map(a => a.id)
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Array<Relationship>> = await client.get<Array<Relationship>>(`/accounts/relationships`, {
id: ids
})
commit(MUTATION_TYPES.UPDATE_RELATIONSHIPS, res.data)
return res.data
}
}
const Follows: Module<FollowsState, RootState> = {
namespaced: true,
state: state,
mutations: mutations,
actions: actions
}
export default Follows

View File

@ -1,116 +0,0 @@
import Mastodon from 'megalodon'
const Timeline = {
namespaced: true,
state: {
timeline: [],
pinnedToots: [],
lazyLoading: false
},
mutations: {
updateTimeline (state, timeline) {
state.timeline = timeline
},
insertTimeline (state, messages) {
state.timeline = state.timeline.concat(messages)
},
updatePinnedToots (state, messages) {
state.pinnedToots = messages
},
changeLazyLoading (state, value) {
state.lazyLoading = value
},
updatePinnedToot (state, message) {
state.pinnedToots = state.pinnedToots.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
}
})
},
updateToot (state, message) {
// Replace target message in timeline
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
}
})
}
},
actions: {
fetchTimeline ({ commit, rootState }, account) {
commit('TimelineSpace/Contents/SideBar/AccountProfile/changeLoading', true, { root: true })
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.get(`/accounts/${account.id}/statuses`, { limit: 10, pinned: true })
.then(res => {
commit('updatePinnedToots', res.data)
})
.then(() => {
return client.get(`/accounts/${account.id}/statuses`, { limit: 40 })
})
.then(res => {
commit('TimelineSpace/Contents/SideBar/AccountProfile/changeLoading', false, { root: true })
commit('updateTimeline', res.data)
return res.data
})
},
lazyFetchTimeline ({ state, commit, rootState }, info) {
const last = info.last
if (last === undefined || last === null) {
return Promise.resolve(null)
}
if (state.lazyLoading) {
return Promise.resolve(null)
}
commit('changeLazyLoading', true)
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.get(`/accounts/${info.account.id}/statuses`, { max_id: last.id, limit: 40 })
.then(res => {
commit('changeLazyLoading', false)
commit('insertTimeline', res.data)
return res.data
})
.catch(err => {
commit('changeLazyLoading', false)
throw err
})
},
clearTimeline ({ commit }) {
commit('updateTimeline', [])
}
}
}
export default Timeline

View File

@ -0,0 +1,131 @@
import Mastodon, { Status, Response } from 'megalodon'
import { Module, MutationTree, ActionTree } from 'vuex'
import { RootState } from '@/store'
export interface TimelineState {
timeline: Array<Status>,
pinnedToots: Array<Status>,
lazyLoading: boolean
}
const state = (): TimelineState => ({
timeline: [],
pinnedToots: [],
lazyLoading: false
})
export const MUTATION_TYPES = {
UPDATE_TIMELINE: 'updateTimeline',
INSERT_TIMELINE: 'insertTimeline',
UPDATE_PINNED_TOOTS: 'updatePinnedToots',
CHANGE_LAZY_LOADING: 'changeLazyLoading',
UPDATE_PINNED_TOOT: 'updatePinnedToot',
UPDATE_TOOT: 'updateToot',
DELETE_TOOT: 'deleteToot'
}
const mutations: MutationTree<TimelineState> = {
[MUTATION_TYPES.UPDATE_TIMELINE]: (state, timeline: Array<Status>) => {
state.timeline = timeline
},
[MUTATION_TYPES.INSERT_TIMELINE]: (state, messages: Array<Status>) => {
state.timeline = state.timeline.concat(messages)
},
[MUTATION_TYPES.UPDATE_PINNED_TOOTS]: (state, messages: Array<Status>) => {
state.pinnedToots = messages
},
[MUTATION_TYPES.CHANGE_LAZY_LOADING]: (state, value: boolean) => {
state.lazyLoading = value
},
[MUTATION_TYPES.UPDATE_PINNED_TOOT]: (state, message: Status) => {
state.pinnedToots = state.pinnedToots.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
}
})
},
[MUTATION_TYPES.UPDATE_TOOT]: (state, message: Status) => {
// Replace target message in timeline
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
}
})
},
[MUTATION_TYPES.DELETE_TOOT]: (state, message: Status) => {
state.timeline = state.timeline.filter((toot) => {
if (toot.reblog !== null && toot.reblog.id === message.id) {
return false
} else {
return toot.id !== message.id
}
})
}
}
const actions: ActionTree<TimelineState, RootState> = {
fetchTimeline: async ({ commit, rootState }, account: Account) => {
commit('TimelineSpace/Contents/SideBar/AccountProfile/changeLoading', true, { root: true })
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const pinned: Response<Array<Status>> = await client.get<Array<Status>>(`/accounts/${account.id}/statuses`, { limit: 10, pinned: true })
commit(MUTATION_TYPES.UPDATE_PINNED_TOOTS, pinned.data)
const res: Response<Array<Status>> = await client.get<Array<Status>>(`/accounts/${account.id}/statuses`, { limit: 40 })
commit('TimelineSpace/Contents/SideBar/AccountProfile/changeLoading', false, { root: true })
commit(MUTATION_TYPES.UPDATE_TIMELINE, res.data)
return res.data
},
lazyFetchTimeline: async ({ state, commit, rootState }, info: any): Promise<null> => {
const last = info.last
if (last === undefined || last === null) {
return Promise.resolve(null)
}
if (state.lazyLoading) {
return Promise.resolve(null)
}
commit(MUTATION_TYPES.CHANGE_LAZY_LOADING, true)
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
try {
const res: Response<Array<Status>> = await client.get<Array<Status>>(`/accounts/${info.account.id}/statuses`, { max_id: last.id, limit: 40 })
commit(MUTATION_TYPES.INSERT_TIMELINE, res.data)
} finally {
commit(MUTATION_TYPES.CHANGE_LAZY_LOADING, false)
}
return null
},
clearTimeline: ({ commit }) => {
commit(MUTATION_TYPES.UPDATE_TIMELINE, [])
}
}
const Timeline: Module<TimelineState, RootState> = {
namespaced: true,
state: state,
mutations: mutations,
actions: actions
}
export default Timeline

View File

@ -1,111 +0,0 @@
import Mastodon from 'megalodon'
const TootDetail = {
namespaced: true,
state: {
message: null,
ancestors: [],
descendants: []
},
mutations: {
changeToot (state, message) {
state.message = message
},
updateAncestors (state, ancestors) {
state.ancestors = ancestors
},
updateDescendants (state, descendants) {
state.descendants = descendants
},
updateAncestorsToot (state, message) {
// Replace target message in ancestors
state.ancestors = state.ancestors.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
}
})
},
deleteAncestorsToot (state, message) {
state.ancestors = state.ancestors.filter((toot) => {
if (toot.reblog !== null && toot.reblog.id === message.id) {
return false
} else {
return toot.id !== message.id
}
})
},
updateToot (state, message) {
if (state.message.id === message.id) {
state.message = message
} else if (state.message.reblog !== null && state.message.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
}
state.message = Object.assign({}, state.message, reblog)
}
},
deleteToot (state, message) {
if (state.message.id === message.id) {
state.message = null
}
},
updateDescendantsToot (state, message) {
// Replace target message in descendants
state.descendants = state.descendants.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
}
})
},
deleteDescendantsToot (state, message) {
state.descendants = state.descendants.filter((toot) => {
if (toot.reblog !== null && toot.reblog.id === message.id) {
return false
} else {
return toot.id !== message.id
}
})
}
},
actions: {
changeToot ({ commit }, message) {
commit('updateAncestors', [])
commit('updateDescendants', [])
commit('changeToot', message)
},
fetchToot ({ commit, rootState }, message) {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.get(`/statuses/${message.id}/context`, { limit: 40 })
.then(res => {
commit('updateAncestors', res.data.ancestors)
commit('updateDescendants', res.data.descendants)
return res.data
})
}
}
}
export default TootDetail

View File

@ -0,0 +1,142 @@
import Mastodon, { Status, Context, Response } from 'megalodon'
import { Module, MutationTree, ActionTree } from 'vuex'
import { RootState } from '@/store'
export interface TootDetailState {
message: Status | null,
ancestors: Array<Status>,
descendants: Array<Status>
}
const state = (): TootDetailState => ({
message: null,
ancestors: [],
descendants: []
})
export const MUTATION_TYPES = {
CHANGE_TOOT: 'changeToot',
UPDATE_ANCESTORS: 'updateAncestors',
UPDATE_DESCENDANTS: 'updateDescendants',
UPDATE_ANCESTORS_TOOT: 'updateAncestorsToot',
DELETE_ANCESTORS_TOOT: 'deleteAncestorsToot',
UPDATE_TOOT: 'updateToot',
DELETE_TOOT: 'deleteToot',
UPDATE_DESCENDANTS_TOOT: 'updateDescendantsToot',
DELETE_DESCENDANTS_TOOT: 'deleteDescendantsToot'
}
const mutations: MutationTree<TootDetailState> = {
[MUTATION_TYPES.CHANGE_TOOT]: (state, message: Status) => {
state.message = message
},
[MUTATION_TYPES.UPDATE_ANCESTORS]: (state, ancestors: Array<Status>) => {
state.ancestors = ancestors
},
[MUTATION_TYPES.UPDATE_DESCENDANTS]: (state, descendants: Array<Status>) => {
state.descendants = descendants
},
[MUTATION_TYPES.UPDATE_ANCESTORS_TOOT]: (state, message: Status) => {
// Replace target message in ancestors
state.ancestors = state.ancestors.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
}
})
},
[MUTATION_TYPES.DELETE_ANCESTORS_TOOT]: (state, message: Status) => {
state.ancestors = state.ancestors.filter((toot) => {
if (toot.reblog !== null && toot.reblog.id === message.id) {
return false
} else {
return toot.id !== message.id
}
})
},
[MUTATION_TYPES.UPDATE_TOOT]: (state, message: Status) => {
if (state.message === null) {
return
}
if (state.message.id === message.id) {
state.message = message
} else if (state.message.reblog !== null && state.message.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
}
state.message = Object.assign({}, state.message, reblog)
}
},
[MUTATION_TYPES.DELETE_TOOT]: (state, message: Status) => {
if (state.message === null) {
return
}
if (state.message.id === message.id) {
state.message = null
}
},
[MUTATION_TYPES.UPDATE_DESCENDANTS_TOOT]: (state, message: Status) => {
// Replace target message in descendants
state.descendants = state.descendants.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
}
})
},
[MUTATION_TYPES.DELETE_DESCENDANTS_TOOT]: (state, message: Status) => {
state.descendants = state.descendants.filter((toot) => {
if (toot.reblog !== null && toot.reblog.id === message.id) {
return false
} else {
return toot.id !== message.id
}
})
}
}
const actions: ActionTree<TootDetailState, RootState> = {
changeToot: ({ commit }, message: Status) => {
commit(MUTATION_TYPES.UPDATE_ANCESTORS, [])
commit(MUTATION_TYPES.UPDATE_DESCENDANTS, [])
commit(MUTATION_TYPES.CHANGE_TOOT, message)
},
fetchToot: async ({ commit, rootState }, message: Status) => {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Context> = await client.get<Context>(`/statuses/${message.id}/context`, { limit: 40 })
commit(MUTATION_TYPES.UPDATE_ANCESTORS, res.data.ancestors)
commit(MUTATION_TYPES.UPDATE_DESCENDANTS, res.data.descendants)
return res.data
}
}
const TootDetail: Module<TootDetailState, RootState> = {
namespaced: true,
state: state,
mutations: mutations,
actions: actions
}
export default TootDetail