From 94e3f57065898cefaff14bdc3782e765307b4a90 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Tue, 9 Apr 2019 22:49:20 +0900 Subject: [PATCH 01/11] refs #850 Replace Contents and Modals with typescript --- .../{Contents.js => Contents.ts} | 0 src/renderer/store/TimelineSpace/Modals.js | 37 --------------- src/renderer/store/TimelineSpace/Modals.ts | 46 +++++++++++++++++++ 3 files changed, 46 insertions(+), 37 deletions(-) rename src/renderer/store/TimelineSpace/{Contents.js => Contents.ts} (100%) delete mode 100644 src/renderer/store/TimelineSpace/Modals.js create mode 100644 src/renderer/store/TimelineSpace/Modals.ts diff --git a/src/renderer/store/TimelineSpace/Contents.js b/src/renderer/store/TimelineSpace/Contents.ts similarity index 100% rename from src/renderer/store/TimelineSpace/Contents.js rename to src/renderer/store/TimelineSpace/Contents.ts diff --git a/src/renderer/store/TimelineSpace/Modals.js b/src/renderer/store/TimelineSpace/Modals.js deleted file mode 100644 index 9afe0d2e..00000000 --- a/src/renderer/store/TimelineSpace/Modals.js +++ /dev/null @@ -1,37 +0,0 @@ -import NewToot from './Modals/NewToot' -import ImageViewer from './Modals/ImageViewer' -import Jump from './Modals/Jump' -import ListMembership from './Modals/ListMembership' -import AddListMember from './Modals/AddListMember' -import MuteConfirm from './Modals/MuteConfirm' -import Shortcut from './Modals/Shortcut' -import Report from './Modals/Report' - -const Modals = { - namespaced: true, - modules: { - ImageViewer, - NewToot, - Jump, - ListMembership, - AddListMember, - MuteConfirm, - Shortcut, - Report - }, - getters: { - modalOpened: (state, getters, rootState) => { - const imageViewer = rootState.TimelineSpace.Modals.ImageViewer.modalOpen - const newToot = rootState.TimelineSpace.Modals.NewToot.modalOpen - const jump = rootState.TimelineSpace.Modals.Jump.modalOpen - const listMembership = rootState.TimelineSpace.Modals.ListMembership.modalOpen - const addListMember = rootState.TimelineSpace.Modals.AddListMember.modalOpen - const shortcut = rootState.TimelineSpace.Modals.Shortcut.modalOpen - const muteConfirm = rootState.TimelineSpace.Modals.MuteConfirm.modalOpen - const report = rootState.TimelineSpace.Modals.Report.modalOpen - return imageViewer || newToot || jump || listMembership || addListMember || shortcut || muteConfirm || report - } - } -} - -export default Modals diff --git a/src/renderer/store/TimelineSpace/Modals.ts b/src/renderer/store/TimelineSpace/Modals.ts new file mode 100644 index 00000000..6bfb4685 --- /dev/null +++ b/src/renderer/store/TimelineSpace/Modals.ts @@ -0,0 +1,46 @@ +import NewToot from './Modals/NewToot' +import ImageViewer from './Modals/ImageViewer' +import Jump from './Modals/Jump' +import ListMembership from './Modals/ListMembership' +import AddListMember from './Modals/AddListMember' +import MuteConfirm from './Modals/MuteConfirm' +import Shortcut from './Modals/Shortcut' +import Report from './Modals/Report' +import { Module, GetterTree } from 'vuex' + +export interface ModalsState {} + +const state = (): ModalsState => ({}) + +// TODO: use type of rootState +const getters: GetterTree = { + modalOpened: (_state, _getters, rootState) => { + const imageViewer = rootState.TimelineSpace.Modals.ImageViewer.modalOpen + const newToot = rootState.TimelineSpace.Modals.NewToot.modalOpen + const jump = rootState.TimelineSpace.Modals.Jump.modalOpen + const listMembership = rootState.TimelineSpace.Modals.ListMembership.modalOpen + const addListMember = rootState.TimelineSpace.Modals.AddListMember.modalOpen + const shortcut = rootState.TimelineSpace.Modals.Shortcut.modalOpen + const muteConfirm = rootState.TimelineSpace.Modals.MuteConfirm.modalOpen + const report = rootState.TimelineSpace.Modals.Report.modalOpen + return imageViewer || newToot || jump || listMembership || addListMember || shortcut || muteConfirm || report + } +} + +const Modals: Module = { + namespaced: true, + modules: { + ImageViewer, + NewToot, + Jump, + ListMembership, + AddListMember, + MuteConfirm, + Shortcut, + Report + }, + state: state, + getters: getters +} + +export default Modals From 1bb938e0a6936497c3fcb3a8e85851d608bdf760 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Tue, 9 Apr 2019 23:15:15 +0900 Subject: [PATCH 02/11] refs #850 Replace Jump with typescript --- .../store/TimelineSpace/Modals/Jump.spec.ts | 9 +- .../store/TimelineSpace/Modals/Jump.spec.ts | 92 ++++++------ .../store/TimelineSpace/Modals/Jump.js | 99 ------------- .../store/TimelineSpace/Modals/Jump.ts | 133 ++++++++++++++++++ 4 files changed, 183 insertions(+), 150 deletions(-) delete mode 100644 src/renderer/store/TimelineSpace/Modals/Jump.js create mode 100644 src/renderer/store/TimelineSpace/Modals/Jump.ts diff --git a/spec/renderer/integration/store/TimelineSpace/Modals/Jump.spec.ts b/spec/renderer/integration/store/TimelineSpace/Modals/Jump.spec.ts index 37974cfd..6b5497f1 100644 --- a/spec/renderer/integration/store/TimelineSpace/Modals/Jump.spec.ts +++ b/spec/renderer/integration/store/TimelineSpace/Modals/Jump.spec.ts @@ -2,9 +2,9 @@ import { createLocalVue } from '@vue/test-utils' import Vuex from 'vuex' import i18n from '~/src/config/i18n' import router from '@/router' -import Jump from '~/src/renderer/store/TimelineSpace/Modals/Jump' +import Jump, { JumpState, Channel } from '~/src/renderer/store/TimelineSpace/Modals/Jump' -const state = () => { +const state = (): JumpState => { return { modalOpen: true, channel: '', @@ -93,10 +93,11 @@ describe('Jump', () => { describe('jump', () => { it('should be changed', () => { - store.dispatch('Jump/jump', { + const channel: Channel = { name: 'public', path: 'public' - }) + } + store.dispatch('Jump/jump', channel) expect(store.state.Jump.modalOpen).toEqual(false) expect(router.push).toHaveBeenCalledWith({ path: '/0/public' }) }) diff --git a/spec/renderer/unit/store/TimelineSpace/Modals/Jump.spec.ts b/spec/renderer/unit/store/TimelineSpace/Modals/Jump.spec.ts index 17b4a87b..54418239 100644 --- a/spec/renderer/unit/store/TimelineSpace/Modals/Jump.spec.ts +++ b/spec/renderer/unit/store/TimelineSpace/Modals/Jump.spec.ts @@ -1,9 +1,11 @@ import i18n from '~/src/config/i18n' -import Jump from '@/store/TimelineSpace/Modals/Jump' +import Jump, { JumpState, MUTATION_TYPES, Channel } from '@/store/TimelineSpace/Modals/Jump' +import Hashtag from '~/src/types/hashtag' +import { List } from 'megalodon' describe('TimelineSpace/Modals/Jump', () => { describe('mutations', () => { - let state + let state: JumpState beforeEach(() => { state = { modalOpen: true, @@ -53,59 +55,55 @@ describe('TimelineSpace/Modals/Jump', () => { describe('updateListChannel', () => { it('should be updated', () => { - const channelList = [ - { - id: '0', + const admin: List = { + id: 0, title: 'admin' - }, - { - id: '1', + } + const engineer: List = { + id: 1, title: 'engineer' - }, - { - id: '2', + } + const designer: List = { + id: 2, title: 'designer' - } - ] - Jump.mutations.updateListChannel(state, channelList) - expect(state.listChannelList).toEqual([ - { - path: 'lists/0', - name: '#admin' - }, - { - path: 'lists/1', - name: '#engineer' - }, - { - path: 'lists/2', - name: '#designer' - } - ]) + } + const channelList = [admin, engineer, designer] + Jump.mutations![MUTATION_TYPES.UPDATE_LIST_CHANNEL](state, channelList) + const adminChannel: Channel = { + path: 'lists/0', + name: '#admin' + } + const engineerChannel: Channel = { + path: 'lists/1', + name: '#engineer' + } + const designerChannel: Channel = { + path: 'lists/2', + name: '#designer' + } + expect(state.listChannelList).toEqual([adminChannel, engineerChannel, designerChannel]) }) }) describe('updateTagChannel', () => { it('should be updated', () => { - const channelList = [ - { - tagName: 'whalebird' - }, - { - tagName: 'tqrk' - } - ] - Jump.mutations.updateTagChannel(state, channelList) - expect(state.tagChannelList).toEqual([ - { - name: '#whalebird', - path: 'hashtag/whalebird' - }, - { - name: '#tqrk', - path: 'hashtag/tqrk' - } - ]) + const whalebird: Hashtag = { + tagName: 'whalebird' + } + const tqrk: Hashtag = { + tagName: 'tqrk' + } + const channelList = [whalebird, tqrk] + Jump.mutations![MUTATION_TYPES.UPDATE_TAG_CHANNEL](state, channelList) + const whalebirdChannel: Channel = { + name: '#whalebird', + path: 'hashtag/whalebird' + } + const tqrkChannel: Channel = { + name: '#tqrk', + path: 'hashtag/tqrk' + } + expect(state.tagChannelList).toEqual([whalebirdChannel, tqrkChannel]) }) }) }) diff --git a/src/renderer/store/TimelineSpace/Modals/Jump.js b/src/renderer/store/TimelineSpace/Modals/Jump.js deleted file mode 100644 index 586e03f0..00000000 --- a/src/renderer/store/TimelineSpace/Modals/Jump.js +++ /dev/null @@ -1,99 +0,0 @@ -import router from '@/router' -import i18n from '~/src/config/i18n' - -const Jump = { - namespaced: true, - state: { - modalOpen: false, - channel: '', - defaultChannelList: [ - { - name: i18n.t('side_menu.home'), - path: 'home' - }, - { - name: i18n.t('side_menu.notification'), - path: 'notifications' - }, - { - name: i18n.t('side_menu.mention'), - path: 'mentions' - }, - { - name: i18n.t('side_menu.favourite'), - path: 'favourites' - }, - { - name: i18n.t('side_menu.local'), - path: 'local' - }, - { - name: i18n.t('side_menu.public'), - path: 'public' - }, - { - name: i18n.t('side_menu.hashtag'), - path: 'hashtag' - }, - { - name: i18n.t('side_menu.search'), - path: 'search' - }, - { - name: i18n.t('side_menu.direct'), - path: 'direct-messages' - } - ], - listChannelList: [], - tagChannelList: [], - selectedChannel: { - name: i18n.t('side_menu.home'), - path: 'home' - } - }, - mutations: { - changeModal (state, value) { - state.modalOpen = value - }, - updateChannel (state, value) { - state.channel = value - }, - changeSelected (state, value) { - state.selectedChannel = value - }, - updateListChannel (state, list) { - state.listChannelList = list.map((l) => { - return { - name: `#${l.title}`, - path: `lists/${l.id}` - } - }) - }, - updateTagChannel (state, tags) { - state.tagChannelList = tags.map(t => { - return { - name: `#${t.tagName}`, - path: `hashtag/${t.tagName}` - } - }) - } - }, - actions: { - jumpCurrentSelected ({ state, commit, rootState }) { - commit('changeModal', false) - router.push({ path: `/${rootState.TimelineSpace.account._id}/${state.selectedChannel.path}` }) - }, - jump ({ commit, rootState }, channel) { - commit('changeModal', false) - router.push({ path: `/${rootState.TimelineSpace.account._id}/${channel.path}` }) - }, - syncListChannel ({ commit, rootState }) { - commit('updateListChannel', rootState.TimelineSpace.SideMenu.lists) - }, - syncTagChannel ({ commit, rootState }) { - commit('updateTagChannel', rootState.TimelineSpace.SideMenu.tags) - } - } -} - -export default Jump diff --git a/src/renderer/store/TimelineSpace/Modals/Jump.ts b/src/renderer/store/TimelineSpace/Modals/Jump.ts new file mode 100644 index 00000000..c4aef049 --- /dev/null +++ b/src/renderer/store/TimelineSpace/Modals/Jump.ts @@ -0,0 +1,133 @@ +import router from '@/router' +import i18n from '~/src/config/i18n' +import { Module, MutationTree, ActionTree } from 'vuex' +import { List } from 'megalodon' +import Hashtag from '~/src/types/hashtag' + +export interface Channel { + name: string, + path: string +} + +export interface JumpState { + modalOpen: boolean, + channel: string, + defaultChannelList: Array, + listChannelList: Array, + tagChannelList: Array, + selectedChannel: Channel +} + +const state = (): JumpState => ({ + modalOpen: false, + channel: '', + defaultChannelList: [ + { + name: i18n.t('side_menu.home'), + path: 'home' + }, + { + name: i18n.t('side_menu.notification'), + path: 'notifications' + }, + { + name: i18n.t('side_menu.mention'), + path: 'mentions' + }, + { + name: i18n.t('side_menu.favourite'), + path: 'favourites' + }, + { + name: i18n.t('side_menu.local'), + path: 'local' + }, + { + name: i18n.t('side_menu.public'), + path: 'public' + }, + { + name: i18n.t('side_menu.hashtag'), + path: 'hashtag' + }, + { + name: i18n.t('side_menu.search'), + path: 'search' + }, + { + name: i18n.t('side_menu.direct'), + path: 'direct-messages' + } + ], + listChannelList: [], + tagChannelList: [], + selectedChannel: { + name: i18n.t('side_menu.home'), + path: 'home' + } +}) + +export const MUTATION_TYPES = { + CHANGE_MODAL: 'changeModal', + UPDATE_CHANNEL: 'updateChannel', + CHANGE_SELECTED: 'changeSelected', + UPDATE_LIST_CHANNEL: 'updateListChannel', + UPDATE_TAG_CHANNEL: 'updateTagChannel' +} + +const mutations: MutationTree = { + [MUTATION_TYPES.CHANGE_MODAL]: (state, value: boolean) => { + state.modalOpen = value + }, + [MUTATION_TYPES.UPDATE_CHANNEL]: (state, channel: string) => { + state.channel = channel + }, + [MUTATION_TYPES.CHANGE_SELECTED]: (state, channel: Channel) => { + state.selectedChannel = channel + }, + [MUTATION_TYPES.UPDATE_LIST_CHANNEL]: (state, lists: Array) => { + state.listChannelList = lists.map((l) => { + const channel: Channel = { + name: `#${l.title}`, + path: `lists/${l.id}` + } + return channel + }) + }, + [MUTATION_TYPES.UPDATE_TAG_CHANNEL]: (state, tags: Array) => { + state.tagChannelList = tags.map(t => { + const channel: Channel = { + name: `#${t.tagName}`, + path: `hashtag/${t.tagName}` + } + return channel + }) + } +} + +// TODO: use type of rootState +const actions: ActionTree = { + jumpCurrentSelected: ({ state, commit, rootState }) => { + commit(MUTATION_TYPES.CHANGE_MODAL, false) + router.push({ path: `/${rootState.TimelineSpace.account._id}/${state.selectedChannel.path}` }) + }, + jump: ({ commit, rootState }, channel: Channel) => { + commit(MUTATION_TYPES.CHANGE_MODAL, false) + router.push({ path: `/${rootState.TimelineSpace.account._id}/${channel.path}` }) + }, + syncListChannel: ({ commit, rootState }) => { + commit(MUTATION_TYPES.UPDATE_LIST_CHANNEL, rootState.TimelineSpace.SideMenu.lists) + }, + syncTagChannel: ({ commit, rootState }) => { + commit(MUTATION_TYPES.UPDATE_TAG_CHANNEL, rootState.TimelineSpace.SideMenu.tags) + } +} + +const Jump: Module = { + namespaced: true, + state: state, + mutations: mutations, + actions: actions +} + +export default Jump From 9670ee1dc8ef8d606cb0402f5e0dea1893bd79da Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Wed, 10 Apr 2019 20:58:11 +0900 Subject: [PATCH 03/11] refs #850 Replace AddListMember with typescript --- .../store/TimelineSpace/Modals/Jump.spec.ts | 12 ++-- src/renderer/store/Preferences.ts | 18 +++-- src/renderer/store/Settings.ts | 9 ++- src/renderer/store/TimelineSpace.ts | 13 +++- src/renderer/store/TimelineSpace/Modals.ts | 16 +++-- .../TimelineSpace/Modals/AddListMember.js | 49 ------------- .../TimelineSpace/Modals/AddListMember.ts | 70 +++++++++++++++++++ src/renderer/store/index.ts | 27 ++++--- src/renderer/store/molecules.ts | 3 + 9 files changed, 139 insertions(+), 78 deletions(-) delete mode 100644 src/renderer/store/TimelineSpace/Modals/AddListMember.js create mode 100644 src/renderer/store/TimelineSpace/Modals/AddListMember.ts diff --git a/spec/renderer/unit/store/TimelineSpace/Modals/Jump.spec.ts b/spec/renderer/unit/store/TimelineSpace/Modals/Jump.spec.ts index 54418239..a33349d0 100644 --- a/spec/renderer/unit/store/TimelineSpace/Modals/Jump.spec.ts +++ b/spec/renderer/unit/store/TimelineSpace/Modals/Jump.spec.ts @@ -56,16 +56,16 @@ describe('TimelineSpace/Modals/Jump', () => { describe('updateListChannel', () => { it('should be updated', () => { const admin: List = { - id: 0, - title: 'admin' + id: 0, + title: 'admin' } const engineer: List = { - id: 1, - title: 'engineer' + id: 1, + title: 'engineer' } const designer: List = { - id: 2, - title: 'designer' + id: 2, + title: 'designer' } const channelList = [admin, engineer, designer] Jump.mutations![MUTATION_TYPES.UPDATE_LIST_CHANNEL](state, channelList) diff --git a/src/renderer/store/Preferences.ts b/src/renderer/store/Preferences.ts index db7fa6b3..20e497eb 100644 --- a/src/renderer/store/Preferences.ts +++ b/src/renderer/store/Preferences.ts @@ -1,14 +1,22 @@ -import General from './Preferences/General' -import Account from './Preferences/Account' -import Language from './Preferences/Language' -import Notification from './Preferences/Notification' -import Appearance from './Preferences/Appearance' +import General, { GeneralState } from './Preferences/General' +import Account, { AccountState } from './Preferences/Account' +import Language, { LanguageState } from './Preferences/Language' +import Appearance, { AppearanceState } from './Preferences/Appearance' +import Notification, { NotificationState } from './Preferences/Notification' import { Module } from 'vuex' export interface PreferencesState {} const state = (): PreferencesState => ({}) +export interface PreferencesModuleState extends PreferencesState { + General: GeneralState, + Account: AccountState, + Language: LanguageState, + Notification: NotificationState, + Appearance: AppearanceState +} + // TODO: use type of rootState const Preferences: Module = { namespaced: true, diff --git a/src/renderer/store/Settings.ts b/src/renderer/store/Settings.ts index 6eb8d2b7..902e8566 100644 --- a/src/renderer/store/Settings.ts +++ b/src/renderer/store/Settings.ts @@ -1,5 +1,5 @@ -import General from './Settings/General' -import Timeline from './Settings/Timeline' +import General, { GeneralState } from './Settings/General' +import Timeline, { TimelineState } from './Settings/Timeline' import { Module, MutationTree } from 'vuex' export interface SettingsState { @@ -20,6 +20,11 @@ const mutations: MutationTree = { } } +export interface SettingsModuleState extends SettingsState { + General: GeneralState, + Timeline: TimelineState, +} + // TODO: use type of rootState const Settings: Module = { namespaced: true, diff --git a/src/renderer/store/TimelineSpace.ts b/src/renderer/store/TimelineSpace.ts index d8fbae10..409fcf2f 100644 --- a/src/renderer/store/TimelineSpace.ts +++ b/src/renderer/store/TimelineSpace.ts @@ -1,9 +1,9 @@ import sanitizeHtml from 'sanitize-html' import { ipcRenderer } from 'electron' import Mastodon, { Account, Emoji, Instance, Status, Notification as NotificationType } from 'megalodon' -import SideMenu from './TimelineSpace/SideMenu' -import HeaderMenu from './TimelineSpace/HeaderMenu' -import Modals from './TimelineSpace/Modals' +import SideMenu, { SideMenuState } from './TimelineSpace/SideMenu' +import HeaderMenu, { HeaderMenuState } from './TimelineSpace/HeaderMenu' +import Modals, { ModalsModuleState } from './TimelineSpace/Modals' import Contents from './TimelineSpace/Contents' import router from '@/router' import unreadSettings from '~/src/constants/unreadNotification' @@ -416,6 +416,13 @@ const actions: ActionTree = { } } +export interface TimelineSpaceModuleState extends TimelineSpaceState { + SideMenu: SideMenuState, + HeaderMenu: HeaderMenuState, + Modals: ModalsModuleState + // TODO: Contents: ContentsState +} + const TimelineSpace: Module = { namespaced: true, modules: { diff --git a/src/renderer/store/TimelineSpace/Modals.ts b/src/renderer/store/TimelineSpace/Modals.ts index 6bfb4685..65ae9d9e 100644 --- a/src/renderer/store/TimelineSpace/Modals.ts +++ b/src/renderer/store/TimelineSpace/Modals.ts @@ -1,19 +1,25 @@ import NewToot from './Modals/NewToot' import ImageViewer from './Modals/ImageViewer' -import Jump from './Modals/Jump' +import Jump, { JumpState } from './Modals/Jump' import ListMembership from './Modals/ListMembership' -import AddListMember from './Modals/AddListMember' +import AddListMember, { AddListMemberState } from './Modals/AddListMember' import MuteConfirm from './Modals/MuteConfirm' import Shortcut from './Modals/Shortcut' import Report from './Modals/Report' import { Module, GetterTree } from 'vuex' +import { RootState } from '@/store/index' export interface ModalsState {} +export interface ModalsModuleState extends ModalsState { + Jump: JumpState, + AddListMember: AddListMemberState +} + const state = (): ModalsState => ({}) -// TODO: use type of rootState -const getters: GetterTree = { + +const getters: GetterTree = { modalOpened: (_state, _getters, rootState) => { const imageViewer = rootState.TimelineSpace.Modals.ImageViewer.modalOpen const newToot = rootState.TimelineSpace.Modals.NewToot.modalOpen @@ -27,7 +33,7 @@ const getters: GetterTree = { } } -const Modals: Module = { +const Modals: Module = { namespaced: true, modules: { ImageViewer, diff --git a/src/renderer/store/TimelineSpace/Modals/AddListMember.js b/src/renderer/store/TimelineSpace/Modals/AddListMember.js deleted file mode 100644 index b0368fdb..00000000 --- a/src/renderer/store/TimelineSpace/Modals/AddListMember.js +++ /dev/null @@ -1,49 +0,0 @@ -import Mastodon from 'megalodon' - -export default { - namespaced: true, - state: { - modalOpen: false, - accounts: [], - targetListId: null - }, - mutations: { - changeModal (state, value) { - state.modalOpen = value - }, - updateAccounts (state, accounts) { - state.accounts = accounts - }, - setListId (state, id) { - state.targetListId = id - } - }, - actions: { - changeModal ({ commit }, value) { - commit('changeModal', value) - }, - search ({ commit, rootState }, name) { - const client = new Mastodon( - rootState.TimelineSpace.account.accessToken, - rootState.TimelineSpace.account.baseURL + '/api/v1' - ) - return client.get('/accounts/search', { - q: name, - following: true - }) - .then(res => { - commit('updateAccounts', res.data) - return res.data - }) - }, - add ({ state, rootState }, account) { - const client = new Mastodon( - rootState.TimelineSpace.account.accessToken, - rootState.TimelineSpace.account.baseURL + '/api/v1' - ) - return client.post(`/lists/${state.targetListId}/accounts`, { - account_ids: [account.id] - }) - } - } -} diff --git a/src/renderer/store/TimelineSpace/Modals/AddListMember.ts b/src/renderer/store/TimelineSpace/Modals/AddListMember.ts new file mode 100644 index 00000000..84ccad6a --- /dev/null +++ b/src/renderer/store/TimelineSpace/Modals/AddListMember.ts @@ -0,0 +1,70 @@ +import Mastodon, { Account, Response } from 'megalodon' +import { Module, MutationTree, ActionTree } from 'vuex' + +export interface AddListMemberState { + modalOpen: boolean, + accounts: Array, + targetListId: number | null +} + +const state = (): AddListMemberState => ({ + modalOpen: false, + accounts: [], + targetListId: null +}) + +export const MUTATION_TYPES = { + CHANGE_MODAL: 'changeModal', + UPDATE_ACCOUNTS: 'updateAccounts', + SET_LIST_ID: 'setListId' +} + +const mutations: MutationTree = { + [MUTATION_TYPES.CHANGE_MODAL]: (state, value: boolean) => { + state.modalOpen = value + }, + [MUTATION_TYPES.UPDATE_ACCOUNTS]: (state, accounts: Array) => { + state.accounts = accounts + }, + [MUTATION_TYPES.SET_LIST_ID]: (state, id: number) => { + state.targetListId = id + } +} + +// TODO: use type of rootState +const actions: ActionTree = { + changeModal: ({ commit }, value: boolean) => { + commit(MUTATION_TYPES.CHANGE_MODAL, value) + }, + search: async ({ commit, rootState }, name: string): Promise> => { + const client = new Mastodon( + rootState.TimelineSpace.account.accessToken, + rootState.TimelineSpace.account.baseURL + '/api/v1' + ) + const res: Response> = await client.get>('/accounts/search', { + q: name, + following: true + }) + commit(MUTATION_TYPES.UPDATE_ACCOUNTS, res.data) + return res.data + }, + add: async ({ state, rootState }, account: Account): Promise<{}> => { + const client = new Mastodon( + rootState.TimelineSpace.account.accessToken, + rootState.TimelineSpace.account.baseURL + '/api/v1' + ) + const res: Response<{}> = await client.post<{}>(`/lists/${state.targetListId}/accounts`, { + account_ids: [account.id] + }) + return res.data + } +} + +const AddListMember: Module = { + namespaced: true, + state: state, + mutations: mutations, + actions: actions +} + +export default AddListMember diff --git a/src/renderer/store/index.ts b/src/renderer/store/index.ts index 4e0e0f29..dd830f07 100644 --- a/src/renderer/store/index.ts +++ b/src/renderer/store/index.ts @@ -2,17 +2,28 @@ import Vue from 'vue' import Vuex from 'vuex' import createLogger from 'vuex/dist/logger' -import App from './App' -import GlobalHeader from './GlobalHeader' -import Login from './Login' -import Authorize from './Authorize' -import TimelineSpace from './TimelineSpace' -import Preferences from './Preferences' -import Settings from './Settings' -import molecules from './molecules' +import App, { AppState } from './App' +import GlobalHeader, { GlobalHeaderState } from './GlobalHeader' +import Login, { LoginState } from './Login' +import Authorize, { AuthorizeState } from './Authorize' +import TimelineSpace, { TimelineSpaceModuleState } from './TimelineSpace' +import Preferences, { PreferencesModuleState } from './Preferences' +import Settings, { SettingsModuleState } from './Settings' +import molecules, { MoleculesModuleState } from './molecules' Vue.use(Vuex) +export interface RootState { + App: AppState, + GlobalHeader: GlobalHeaderState, + Login: LoginState, + Authorize: AuthorizeState, + TimelineSpace: TimelineSpaceModuleState, + Preferences: PreferencesModuleState, + Settings: SettingsModuleState, + molecules: MoleculesModuleState +} + export default new Vuex.Store({ strict: process.env.NODE_ENV !== 'production', plugins: process.env.NODE_ENV !== 'production' diff --git a/src/renderer/store/molecules.ts b/src/renderer/store/molecules.ts index f0ee7f2a..82fbdfe9 100644 --- a/src/renderer/store/molecules.ts +++ b/src/renderer/store/molecules.ts @@ -1,5 +1,8 @@ import Toot from './molecules/Toot' +export interface MoleculesModuleState { +} + export default { namespaced: true, modules: { From 7c01aa877a3647aa6283626740267e62f9fa2d68 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Wed, 10 Apr 2019 21:18:22 +0900 Subject: [PATCH 04/11] refs #850 Replace ImageViewer with typescript --- src/renderer/store/TimelineSpace/Modals.ts | 5 +- .../store/TimelineSpace/Modals/ImageViewer.js | 78 ------------- .../store/TimelineSpace/Modals/ImageViewer.ts | 108 ++++++++++++++++++ 3 files changed, 111 insertions(+), 80 deletions(-) delete mode 100644 src/renderer/store/TimelineSpace/Modals/ImageViewer.js create mode 100644 src/renderer/store/TimelineSpace/Modals/ImageViewer.ts diff --git a/src/renderer/store/TimelineSpace/Modals.ts b/src/renderer/store/TimelineSpace/Modals.ts index 65ae9d9e..4fc079de 100644 --- a/src/renderer/store/TimelineSpace/Modals.ts +++ b/src/renderer/store/TimelineSpace/Modals.ts @@ -1,5 +1,5 @@ import NewToot from './Modals/NewToot' -import ImageViewer from './Modals/ImageViewer' +import ImageViewer, { ImageViewerState } from './Modals/ImageViewer' import Jump, { JumpState } from './Modals/Jump' import ListMembership from './Modals/ListMembership' import AddListMember, { AddListMemberState } from './Modals/AddListMember' @@ -13,7 +13,8 @@ export interface ModalsState {} export interface ModalsModuleState extends ModalsState { Jump: JumpState, - AddListMember: AddListMemberState + AddListMember: AddListMemberState, + ImageViewer: ImageViewerState } const state = (): ModalsState => ({}) diff --git a/src/renderer/store/TimelineSpace/Modals/ImageViewer.js b/src/renderer/store/TimelineSpace/Modals/ImageViewer.js deleted file mode 100644 index d0cd2d7b..00000000 --- a/src/renderer/store/TimelineSpace/Modals/ImageViewer.js +++ /dev/null @@ -1,78 +0,0 @@ -const ImageViewer = { - namespaced: true, - state: { - modalOpen: false, - currentIndex: -1, - mediaList: [], - loading: false - }, - mutations: { - changeModal (state, value) { - state.modalOpen = value - }, - changeCurrentIndex (state, currentIndex) { - state.currentIndex = currentIndex - }, - changeMedliaList (state, mediaList) { - state.mediaList = mediaList - }, - incrementIndex (state) { - state.currentIndex++ - }, - decrementIndex (state) { - state.currentIndex-- - }, - loading (state, value) { - state.loading = value - } - }, - actions: { - openModal ({ commit }, { currentIndex, mediaList }) { - commit('changeModal', true) - commit('changeCurrentIndex', currentIndex) - commit('changeMedliaList', mediaList) - commit('loading', true) - }, - closeModal ({ commit }) { - commit('changeModal', false) - commit('changeCurrentIndex', -1) - commit('changeMedliaList', []) - commit('loading', false) - }, - incrementIndex ({ commit }) { - commit('incrementIndex') - commit('loading', true) - }, - decrementIndex ({ commit }) { - commit('decrementIndex') - commit('loading', true) - }, - async loaded ({ commit }) { - commit('loading', false) - } - }, - getters: { - imageURL (state) { - if (state.currentIndex >= 0) { - return state.mediaList[state.currentIndex].url - } - }, - imageType (state) { - if (state.currentIndex >= 0) { - return state.mediaList[state.currentIndex].type - } - }, - showLeft (state) { - const notFirst = (state.currentIndex > 0) - const isManyItem = (state.mediaList.length > 1) - return (notFirst && isManyItem) - }, - showRight (state) { - const notLast = (state.currentIndex < (state.mediaList.length - 1)) - const isManyItem = (state.mediaList.length > 1) - return (notLast && isManyItem) - } - } -} - -export default ImageViewer diff --git a/src/renderer/store/TimelineSpace/Modals/ImageViewer.ts b/src/renderer/store/TimelineSpace/Modals/ImageViewer.ts new file mode 100644 index 00000000..8fd7270b --- /dev/null +++ b/src/renderer/store/TimelineSpace/Modals/ImageViewer.ts @@ -0,0 +1,108 @@ +import { Module, MutationTree, ActionTree, GetterTree } from 'vuex' +import { Attachment } from 'megalodon' +import { RootState } from '@/store'; + +export interface ImageViewerState { + modalOpen: boolean, + currentIndex: number, + mediaList: Array, + loading: boolean +} + +const state = (): ImageViewerState => ({ + modalOpen: false, + currentIndex: -1, + mediaList: [], + loading: false +}) + +export const MUTATION_TYPES = { + CHANGE_MODAL: 'changeModal', + CHANGE_CURRENT_INDEX: 'changeCurrentIndex', + CHANGE_MEDIA_LIST: 'changeMediaList', + INCREMENT_INDEX: 'incrementIndex', + DECREMENT_INDEX: 'decrementIndex', + CHANGE_LOADING: 'changeLoading' +} + +const mutations: MutationTree = { + [MUTATION_TYPES.CHANGE_MODAL]: (state, value: boolean) => { + state.modalOpen = value + }, + [MUTATION_TYPES.CHANGE_CURRENT_INDEX]: (state, currentIndex: number) => { + state.currentIndex = currentIndex + }, + [MUTATION_TYPES.CHANGE_MEDIA_LIST]: (state, mediaList: Array) => { + state.mediaList = mediaList + }, + [MUTATION_TYPES.INCREMENT_INDEX]: (state) => { + state.currentIndex++ + }, + [MUTATION_TYPES.DECREMENT_INDEX]: (state) => { + state.currentIndex-- + }, + [MUTATION_TYPES.CHANGE_LOADING]: (state, value: boolean) => { + state.loading = value + } +} + +const actions: ActionTree = { + openModal: ({ commit }, { currentIndex, mediaList }) => { + commit(MUTATION_TYPES.CHANGE_MODAL, true) + commit(MUTATION_TYPES.CHANGE_CURRENT_INDEX, currentIndex as number) + commit(MUTATION_TYPES.CHANGE_MEDIA_LIST, mediaList as Array) + commit(MUTATION_TYPES.CHANGE_LOADING, true) + }, + closeModal: ({ commit }) => { + commit(MUTATION_TYPES.CHANGE_MODAL, false) + commit(MUTATION_TYPES.CHANGE_CURRENT_INDEX, -1) + commit(MUTATION_TYPES.CHANGE_MEDIA_LIST, []) + commit(MUTATION_TYPES.CHANGE_LOADING, false) + }, + incrementIndex: ({ commit }) => { + commit(MUTATION_TYPES.INCREMENT_INDEX) + commit(MUTATION_TYPES.CHANGE_LOADING, true) + }, + decrementIndex: ({ commit }) => { + commit(MUTATION_TYPES.DECREMENT_INDEX) + commit(MUTATION_TYPES.CHANGE_LOADING, true) + }, + loaded: ({ commit }) => { + commit(MUTATION_TYPES.CHANGE_LOADING, false) + } +} + +const getters: GetterTree = { + imageURL: (state): string | null => { + if (state.currentIndex >= 0) { + return state.mediaList[state.currentIndex].url + } + return null + }, + imageType: (state): string | null => { + if (state.currentIndex >= 0) { + return state.mediaList[state.currentIndex].type + } + return null + }, + showLeft: (state): boolean => { + const notFirst = (state.currentIndex > 0) + const isManyItem = (state.mediaList.length > 1) + return (notFirst && isManyItem) + }, + showRight: (state): boolean => { + const notLast = (state.currentIndex < (state.mediaList.length - 1)) + const isManyItem = (state.mediaList.length > 1) + return (notLast && isManyItem) + } +} + +const ImageViewer: Module = { + namespaced: true, + state: state, + mutations: mutations, + actions: actions, + getters: getters +} + +export default ImageViewer From 921d3f07e334f90883932d823164539224ca1e60 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Wed, 10 Apr 2019 21:57:37 +0900 Subject: [PATCH 05/11] refs #850 Replace ListMembership with typescript --- package-lock.json | 12 ++- package.json | 3 +- src/renderer/store/TimelineSpace/Modals.ts | 1 - .../store/TimelineSpace/Modals/ImageViewer.ts | 2 +- .../TimelineSpace/Modals/ListMembership.js | 80 --------------- .../TimelineSpace/Modals/ListMembership.ts | 98 +++++++++++++++++++ 6 files changed, 110 insertions(+), 86 deletions(-) delete mode 100644 src/renderer/store/TimelineSpace/Modals/ListMembership.js create mode 100644 src/renderer/store/TimelineSpace/Modals/ListMembership.ts diff --git a/package-lock.json b/package-lock.json index e513cfe6..6dab7ad2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2003,6 +2003,12 @@ "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", "dev": true }, + "@types/lodash": { + "version": "4.14.123", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.123.tgz", + "integrity": "sha512-pQvPkc4Nltyx7G1Ww45OjVqUsJP4UsZm+GWJpigXgkikZqJgRm4c48g027o6tdgubWHwFRF15iFd+Y4Pmqv6+Q==", + "dev": true + }, "@types/node": { "version": "11.11.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.4.tgz", @@ -13466,9 +13472,9 @@ "dev": true }, "megalodon": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/megalodon/-/megalodon-0.6.2.tgz", - "integrity": "sha512-EmNs0M6e2AiX9hutoiXo0FUkghZ1HdyLpS8mVkrMMN8btBR2x1hVrAF/8WAFePeJQrEMYjRyQSEJfykJ/4rwaQ==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/megalodon/-/megalodon-0.6.3.tgz", + "integrity": "sha512-rxh9Kbbwm9Hnn/e8xdzH2Fw5kD/TamgyGFEzOcsnKCqF4iI2qHuojCBm7KeWohgRlwJ9oq7QYVReEVTipqI8kQ==", "requires": { "@types/oauth": "0.9.1", "@types/request": "2.48.1", diff --git a/package.json b/package.json index 381b43ec..2865afcc 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "i18next-sync-fs-backend": "^1.1.0", "is-empty": "^1.2.0", "lodash": "^4.17.11", - "megalodon": "0.6.2", + "megalodon": "0.6.3", "moment": "^2.21.0", "mousetrap": "^1.6.2", "nedb": "^1.8.0", @@ -173,6 +173,7 @@ "@mapbox/stylelint-processor-arbitrary-tags": "^0.2.0", "@types/i18next": "^12.1.0", "@types/jest": "^24.0.11", + "@types/lodash": "^4.14.123", "@types/node": "^11.11.4", "@typescript-eslint/eslint-plugin": "^1.5.0", "@typescript-eslint/parser": "^1.5.0", diff --git a/src/renderer/store/TimelineSpace/Modals.ts b/src/renderer/store/TimelineSpace/Modals.ts index 4fc079de..f72b2027 100644 --- a/src/renderer/store/TimelineSpace/Modals.ts +++ b/src/renderer/store/TimelineSpace/Modals.ts @@ -19,7 +19,6 @@ export interface ModalsModuleState extends ModalsState { const state = (): ModalsState => ({}) - const getters: GetterTree = { modalOpened: (_state, _getters, rootState) => { const imageViewer = rootState.TimelineSpace.Modals.ImageViewer.modalOpen diff --git a/src/renderer/store/TimelineSpace/Modals/ImageViewer.ts b/src/renderer/store/TimelineSpace/Modals/ImageViewer.ts index 8fd7270b..498cb2ae 100644 --- a/src/renderer/store/TimelineSpace/Modals/ImageViewer.ts +++ b/src/renderer/store/TimelineSpace/Modals/ImageViewer.ts @@ -1,6 +1,6 @@ import { Module, MutationTree, ActionTree, GetterTree } from 'vuex' import { Attachment } from 'megalodon' -import { RootState } from '@/store'; +import { RootState } from '@/store' export interface ImageViewerState { modalOpen: boolean, diff --git a/src/renderer/store/TimelineSpace/Modals/ListMembership.js b/src/renderer/store/TimelineSpace/Modals/ListMembership.js deleted file mode 100644 index 9d2249cb..00000000 --- a/src/renderer/store/TimelineSpace/Modals/ListMembership.js +++ /dev/null @@ -1,80 +0,0 @@ -import Mastodon from 'megalodon' -import _ from 'lodash' - -const ListMembership = { - namespaced: true, - state: { - modalOpen: false, - account: null, - lists: [], - belongToLists: [] - }, - mutations: { - changeModal (state, value) { - state.modalOpen = value - }, - changeAccount (state, account) { - state.account = account - }, - changeBelongToLists (state, lists) { - state.belongToLists = lists - }, - changeLists (state, lists) { - state.lists = lists - } - }, - actions: { - changeModal ({ commit }, value) { - commit('changeModal', value) - }, - setAccount ({ commit }, account) { - commit('changeAccount', account) - }, - fetchListMembership ({ commit, rootState }, account) { - const client = new Mastodon( - rootState.TimelineSpace.account.accessToken, - rootState.TimelineSpace.account.baseURL + '/api/v1' - ) - return client.get(`/accounts/${account.id}/lists`) - .then(res => { - commit('changeBelongToLists', res.data.map(l => l.id)) - return res.data - }) - }, - fetchLists ({ commit, rootState }) { - const client = new Mastodon( - rootState.TimelineSpace.account.accessToken, - rootState.TimelineSpace.account.baseURL + '/api/v1' - ) - return client.get('/lists') - .then(res => { - commit('changeLists', res.data) - return res.data - }) - }, - async changeBelongToLists ({ rootState, commit, state }, belongToLists) { - // Calcurate diff - const removedLists = _.difference(state.belongToLists, belongToLists) - const addedLists = _.difference(belongToLists, state.belongToLists) - commit('changeBelongToLists', belongToLists) - const client = new Mastodon( - rootState.TimelineSpace.account.accessToken, - rootState.TimelineSpace.account.baseURL + '/api/v1' - ) - const removedPromise = removedLists.map(id => { - return client.del(`/lists/${id}/accounts`, { - account_ids: [state.account.id] - }) - }) - const addedPromise = addedLists.map(id => { - return client.post(`/lists/${id}/accounts`, { - account_ids: [state.account.id] - }) - }) - const res = await Promise.all(removedPromise.concat(addedPromise)) - return res - } - } -} - -export default ListMembership diff --git a/src/renderer/store/TimelineSpace/Modals/ListMembership.ts b/src/renderer/store/TimelineSpace/Modals/ListMembership.ts new file mode 100644 index 00000000..68d5e6df --- /dev/null +++ b/src/renderer/store/TimelineSpace/Modals/ListMembership.ts @@ -0,0 +1,98 @@ +import Mastodon, { Account, List, Response } from 'megalodon' +import lodash from 'lodash' +import { Module, MutationTree, ActionTree } from 'vuex' +import { RootState } from '@/store' + +export interface ListMembershipState { + modalOpen: boolean, + account: Account | null, + lists: Array, + belongToLists: Array +} + +const state = (): ListMembershipState => ({ + modalOpen: false, + account: null, + lists: [], + belongToLists: [] +}) + +export const MUTATION_TYPES = { + CHANGE_MODAL: 'changeModal', + CHANGE_ACCOUNT: 'changeAccount', + CHANGE_BELONG_TO_LISTS: 'changeBelongToLists', + CHANGE_LISTS: 'changeLists' +} + +const mutations: MutationTree = { + [MUTATION_TYPES.CHANGE_MODAL]: (state, value: boolean) => { + state.modalOpen = value + }, + [MUTATION_TYPES.CHANGE_ACCOUNT]: (state, account: Account) => { + state.account = account + }, + [MUTATION_TYPES.CHANGE_BELONG_TO_LISTS]: (state, lists: Array) => { + state.belongToLists = lists + }, + [MUTATION_TYPES.CHANGE_LISTS]: (state, lists: Array) => { + state.lists = lists + } +} + +const actions: ActionTree = { + changeModal: ({ commit }, value: boolean) => { + commit(MUTATION_TYPES.CHANGE_MODAL, value) + }, + setAccount: ({ commit }, account: Account) => { + commit(MUTATION_TYPES.CHANGE_ACCOUNT, account) + }, + fetchListMembership: async ({ commit, rootState }, account: Account) => { + const client = new Mastodon( + rootState.TimelineSpace.account.accessToken!, + rootState.TimelineSpace.account.baseURL + '/api/v1' + ) + const res: Response> = await client.get>(`/accounts/${account.id}/lists`) + commit(MUTATION_TYPES.CHANGE_BELONG_TO_LISTS, res.data.map(l => l.id)) + return res.data + }, + fetchLists: async ({ commit, rootState }) => { + const client = new Mastodon( + rootState.TimelineSpace.account.accessToken!, + rootState.TimelineSpace.account.baseURL + '/api/v1' + ) + const res: Response> = await client.get>('/lists') + commit(MUTATION_TYPES.CHANGE_LISTS, res.data) + return res.data + }, + changeBelongToLists: async ({ rootState, commit, state }, belongToLists: Array) => { + // Calcurate diff + const removedLists = lodash.difference(state.belongToLists, belongToLists) + const addedLists = lodash.difference(belongToLists, state.belongToLists) + commit(MUTATION_TYPES.CHANGE_BELONG_TO_LISTS, belongToLists) + const client = new Mastodon( + rootState.TimelineSpace.account.accessToken!, + rootState.TimelineSpace.account.baseURL + '/api/v1' + ) + const removedPromise = removedLists.map(id => { + return client.del<{}>(`/lists/${id}/accounts`, { + account_ids: [state.account!.id] + }) + }) + const addedPromise = addedLists.map(id => { + return client.post<{}>(`/lists/${id}/accounts`, { + account_ids: [state.account!.id] + }) + }) + const res = await Promise.all(removedPromise.concat(addedPromise)) + return res + } +} + +const ListMembership: Module = { + namespaced: true, + state: state, + mutations: mutations, + actions: actions +} + +export default ListMembership From 20f3dcba227bc100877439b5ef6b54b5c429ffad Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Wed, 10 Apr 2019 22:07:02 +0900 Subject: [PATCH 06/11] refs #850 Replace MuteConfirm with typescript --- src/renderer/store/TimelineSpace/Modals.ts | 8 ++- .../store/TimelineSpace/Modals/MuteConfirm.js | 39 ------------- .../store/TimelineSpace/Modals/MuteConfirm.ts | 57 +++++++++++++++++++ 3 files changed, 62 insertions(+), 42 deletions(-) delete mode 100644 src/renderer/store/TimelineSpace/Modals/MuteConfirm.js create mode 100644 src/renderer/store/TimelineSpace/Modals/MuteConfirm.ts diff --git a/src/renderer/store/TimelineSpace/Modals.ts b/src/renderer/store/TimelineSpace/Modals.ts index f72b2027..3baf45a8 100644 --- a/src/renderer/store/TimelineSpace/Modals.ts +++ b/src/renderer/store/TimelineSpace/Modals.ts @@ -1,9 +1,9 @@ import NewToot from './Modals/NewToot' import ImageViewer, { ImageViewerState } from './Modals/ImageViewer' import Jump, { JumpState } from './Modals/Jump' -import ListMembership from './Modals/ListMembership' +import ListMembership, { ListMembershipState } from './Modals/ListMembership' import AddListMember, { AddListMemberState } from './Modals/AddListMember' -import MuteConfirm from './Modals/MuteConfirm' +import MuteConfirm, { MuteConfirmState } from './Modals/MuteConfirm' import Shortcut from './Modals/Shortcut' import Report from './Modals/Report' import { Module, GetterTree } from 'vuex' @@ -14,7 +14,9 @@ export interface ModalsState {} export interface ModalsModuleState extends ModalsState { Jump: JumpState, AddListMember: AddListMemberState, - ImageViewer: ImageViewerState + ImageViewer: ImageViewerState, + ListMembership: ListMembershipState, + MuteConfirm: MuteConfirmState } const state = (): ModalsState => ({}) diff --git a/src/renderer/store/TimelineSpace/Modals/MuteConfirm.js b/src/renderer/store/TimelineSpace/Modals/MuteConfirm.js deleted file mode 100644 index c3934245..00000000 --- a/src/renderer/store/TimelineSpace/Modals/MuteConfirm.js +++ /dev/null @@ -1,39 +0,0 @@ -import Mastodon from 'megalodon' - -export default { - namespaced: true, - state: { - modalOpen: false, - account: {} - }, - mutations: { - changeModal (state, value) { - state.modalOpen = value - }, - changeAccount (state, account) { - state.account = account - } - }, - actions: { - changeModal ({ commit }, value) { - commit('changeModal', value) - }, - changeAccount ({ commit }, account) { - commit('changeAccount', account) - }, - async submit ({ state, rootState, dispatch }, notify) { - const client = new Mastodon( - rootState.TimelineSpace.account.accessToken, - rootState.TimelineSpace.account.baseURL + '/api/v1' - ) - return client.post(`/accounts/${state.account.id}/mute`, { - notifications: notify - }) - .then(res => { - // Reload relationship - dispatch('TimelineSpace/Contents/SideBar/AccountProfile/fetchRelationship', state.account, { root: true }) - return res.data - }) - } - } -} diff --git a/src/renderer/store/TimelineSpace/Modals/MuteConfirm.ts b/src/renderer/store/TimelineSpace/Modals/MuteConfirm.ts new file mode 100644 index 00000000..3ef17944 --- /dev/null +++ b/src/renderer/store/TimelineSpace/Modals/MuteConfirm.ts @@ -0,0 +1,57 @@ +import Mastodon, { Account, Response, Relationship } from 'megalodon' +import { Module, MutationTree, ActionTree } from 'vuex' +import { RootState } from '@/store' + +export interface MuteConfirmState { + modalOpen: boolean, + account: Account | null +} + +const state = (): MuteConfirmState => ({ + modalOpen: false, + account: null +}) + +export const MUTATION_TYPES = { + CHANGE_MODAL: 'changeModal', + CHANGE_ACCOUNT: 'changeAccount' +} + +const mutations: MutationTree = { + [MUTATION_TYPES.CHANGE_MODAL]: (state, value: boolean) => { + state.modalOpen = value + }, + [MUTATION_TYPES.CHANGE_ACCOUNT]: (state, account: Account) => { + state.account = account + } +} + +const actions: ActionTree = { + changeModal: ({ commit }, value: boolean) => { + commit(MUTATION_TYPES.CHANGE_MODAL, value) + }, + changeAccount: ({ commit }, account: Account) => { + commit(MUTATION_TYPES.CHANGE_ACCOUNT, account) + }, + submit: async ({ state, rootState, dispatch }, notify: boolean) => { + const client = new Mastodon( + rootState.TimelineSpace.account.accessToken!, + rootState.TimelineSpace.account.baseURL + '/api/v1' + ) + const res: Response = await client.post(`/accounts/${state.account!.id}/mute`, { + notifications: notify + }) + // Reload relationship + dispatch('TimelineSpace/Contents/SideBar/AccountProfile/fetchRelationship', state.account, { root: true }) + return res.data + } +} + +const MuteConfirm: Module = { + namespaced: true, + state: state, + mutations: mutations, + actions: actions +} + +export default MuteConfirm From 0208e7c22ac6a3236b1bf65198325f091ff3b9bc Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Thu, 11 Apr 2019 00:06:43 +0900 Subject: [PATCH 07/11] refs #850 Replace NewToot and Status with typescript --- src/renderer/store/TimelineSpace/Modals.ts | 5 +- .../store/TimelineSpace/Modals/NewToot.js | 204 -------------- .../store/TimelineSpace/Modals/NewToot.ts | 249 ++++++++++++++++++ .../TimelineSpace/Modals/NewToot/Status.js | 73 ----- .../TimelineSpace/Modals/NewToot/Status.ts | 104 ++++++++ tsconfig.json | 6 +- 6 files changed, 361 insertions(+), 280 deletions(-) delete mode 100644 src/renderer/store/TimelineSpace/Modals/NewToot.js create mode 100644 src/renderer/store/TimelineSpace/Modals/NewToot.ts delete mode 100644 src/renderer/store/TimelineSpace/Modals/NewToot/Status.js create mode 100644 src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts diff --git a/src/renderer/store/TimelineSpace/Modals.ts b/src/renderer/store/TimelineSpace/Modals.ts index 3baf45a8..5c0392ae 100644 --- a/src/renderer/store/TimelineSpace/Modals.ts +++ b/src/renderer/store/TimelineSpace/Modals.ts @@ -1,4 +1,4 @@ -import NewToot from './Modals/NewToot' +import NewToot, { NewTootModuleState } from './Modals/NewToot' import ImageViewer, { ImageViewerState } from './Modals/ImageViewer' import Jump, { JumpState } from './Modals/Jump' import ListMembership, { ListMembershipState } from './Modals/ListMembership' @@ -16,7 +16,8 @@ export interface ModalsModuleState extends ModalsState { AddListMember: AddListMemberState, ImageViewer: ImageViewerState, ListMembership: ListMembershipState, - MuteConfirm: MuteConfirmState + MuteConfirm: MuteConfirmState, + NewToot: NewTootModuleState } const state = (): ModalsState => ({}) diff --git a/src/renderer/store/TimelineSpace/Modals/NewToot.js b/src/renderer/store/TimelineSpace/Modals/NewToot.js deleted file mode 100644 index 4150b724..00000000 --- a/src/renderer/store/TimelineSpace/Modals/NewToot.js +++ /dev/null @@ -1,204 +0,0 @@ -import Mastodon from 'megalodon' -import { ipcRenderer } from 'electron' -import Visibility from '~/src/constants/visibility' -import Status from './NewToot/Status' - -const NewToot = { - namespaced: true, - modules: { - Status - }, - state: { - modalOpen: false, - initialStatus: '', - initialSpoiler: '', - replyToMessage: null, - blockSubmit: false, - attachedMedias: [], - visibility: Visibility.Public.value, - sensitive: false, - attachedMediaId: 0, - pinedHashtag: false, - hashtags: [] - }, - mutations: { - changeModal (state, value) { - state.modalOpen = value - }, - setReplyTo (state, message) { - state.replyToMessage = message - }, - updateInitialStatus (state, status) { - state.initialStatus = status - }, - updateInitialSpoiler (state, cw) { - state.initialSpoiler = cw - }, - changeBlockSubmit (state, value) { - state.blockSubmit = value - }, - appendAttachedMedias (state, media) { - state.attachedMedias = state.attachedMedias.concat([media]) - }, - clearAttachedMedias (state) { - state.attachedMedias = [] - }, - removeMedia (state, media) { - state.attachedMedias = state.attachedMedias.filter(m => m.id !== media.id) - }, - /** - * changeVisibilityValue - * Update visibility using direct value - * @param state vuex state object - * @param value visibility value - */ - changeVisibilityValue (state, value) { - state.visibility = value - }, - changeSensitive (state, value) { - state.sensitive = value - }, - updateMediaId (state, value) { - state.attachedMediaId = value - }, - changePinedHashtag (state, value) { - state.pinedHashtag = value - }, - updateHashtags (state, tags) { - state.hashtags = tags - } - }, - getters: { - hashtagInserting (state) { - return !state.replyToMessage && state.pinedHashtag - } - }, - actions: { - async updateMedia ({ rootState }, media) { - if (rootState.TimelineSpace.account.accessToken === undefined || rootState.TimelineSpace.account.accessToken === null) { - throw new AuthenticationError() - } - const client = new Mastodon( - rootState.TimelineSpace.account.accessToken, - rootState.TimelineSpace.account.baseURL + '/api/v1' - ) - return Promise.all( - Object.keys(media).map(async id => { - return client.put(`/media/${id}`, { description: media[id] }) - } - )).catch(err => { - console.error(err) - throw err - }) - }, - async postToot ({ state, commit, rootState }, form) { - if (rootState.TimelineSpace.account.accessToken === undefined || rootState.TimelineSpace.account.accessToken === null) { - throw new AuthenticationError() - } - if (state.blockSubmit) { - return - } - commit('changeBlockSubmit', true) - const client = new Mastodon( - rootState.TimelineSpace.account.accessToken, - rootState.TimelineSpace.account.baseURL + '/api/v1' - ) - return client.post('/statuses', form) - .then(res => { - ipcRenderer.send('toot-action-sound') - return res.data - }) - .finally(() => { - commit('changeBlockSubmit', false) - }) - }, - openReply ({ commit, rootState }, message) { - commit('setReplyTo', message) - const mentionAccounts = [message.account.acct].concat(message.mentions.map(a => a.acct)) - .filter((a, i, self) => self.indexOf(a) === i) - .filter((a) => a !== rootState.TimelineSpace.account.username) - commit('updateInitialStatus', `${mentionAccounts.map(m => `@${m}`).join(' ')} `) - commit('updateInitialSpoiler', message.spoiler_text) - commit('changeModal', true) - let value = Visibility.Public.value - Object.keys(Visibility).map(key => { - const target = Visibility[key] - if (target.key === message.visibility) { - value = target.value - } - }) - commit('changeVisibilityValue', value) - }, - openModal ({ dispatch, commit, state }) { - if (!state.replyToMessage && state.pinedHashtag) { - commit('updateInitialStatus', state.hashtags.map(t => ` #${t.name}`).join()) - } - commit('changeModal', true) - dispatch('fetchVisibility') - }, - closeModal ({ commit }) { - commit('changeModal', false) - commit('updateInitialStatus', '') - commit('updateInitialSpoiler', '') - commit('setReplyTo', null) - commit('changeBlockSubmit', false) - commit('clearAttachedMedias') - commit('changeSensitive', false) - commit('changeVisibilityValue', Visibility.Public.value) - }, - uploadImage ({ commit, rootState }, image) { - commit('changeBlockSubmit', true) - if (rootState.TimelineSpace.account.accessToken === undefined || rootState.TimelineSpace.account.accessToken === null) { - throw new AuthenticationError() - } - const client = new Mastodon( - rootState.TimelineSpace.account.accessToken, - rootState.TimelineSpace.account.baseURL + '/api/v1' - ) - const formData = new FormData() - formData.append('file', image) - return client.post('/media', formData) - .then(res => { - commit('changeBlockSubmit', false) - if (res.data.type === 'unknown') throw new UnknownTypeError() - commit('appendAttachedMedias', res.data) - return res.data - }) - .catch(err => { - commit('changeBlockSubmit', false) - console.error(err) - throw err - }) - }, - incrementMediaId ({ commit, state }) { - commit('updateMediaId', state.attachedMediaId + 1) - }, - resetMediaId ({ commit }) { - commit('updateMediaId', 0) - }, - updateHashtags ({ commit, state }, tags) { - if (state.pinedHashtag) { - commit('updateHashtags', tags) - } - }, - fetchVisibility ({ commit, rootState }) { - const client = new Mastodon( - rootState.TimelineSpace.account.accessToken, - rootState.TimelineSpace.account.baseURL + '/api/v1' - ) - return client.get('/accounts/verify_credentials') - .then(res => { - const visibility = Object.values(Visibility).find((v) => { - return v.key === res.data.source.privacy - }) - commit('changeVisibilityValue', visibility.value) - return res.data - }) - } - } -} - -export default NewToot - -class AuthenticationError {} -class UnknownTypeError {} diff --git a/src/renderer/store/TimelineSpace/Modals/NewToot.ts b/src/renderer/store/TimelineSpace/Modals/NewToot.ts new file mode 100644 index 00000000..68f16c4e --- /dev/null +++ b/src/renderer/store/TimelineSpace/Modals/NewToot.ts @@ -0,0 +1,249 @@ +import Mastodon, { Status, Attachment, Tag, Response, Account } from 'megalodon' +import { ipcRenderer } from 'electron' +import Visibility from '~/src/constants/visibility' +import TootStatus, { StatusState } from './NewToot/Status' +import { Module, MutationTree, ActionTree, GetterTree } from 'vuex' +import { RootState } from '@/store' +import VisibilityType from '~/src/types/visibility' + +export interface NewTootState { + modalOpen: boolean, + initialStatus: string, + initialSpoiler: string, + replyToMessage: Status | null, + blockSubmit: boolean, + attachedMedias: Array, + visibility: number, + sensitive: boolean, + attachedMediaId: number, + pinedHashtag: boolean, + hashtags: Array +} + +export interface NewTootModuleState extends NewTootState { + Status: StatusState +} + +const state = (): NewTootState => ({ + modalOpen: false, + initialStatus: '', + initialSpoiler: '', + replyToMessage: null, + blockSubmit: false, + attachedMedias: [], + visibility: Visibility.Public.value, + sensitive: false, + attachedMediaId: 0, + pinedHashtag: false, + hashtags: [] +}) + +export const MUTATION_TYPES = { + CHANGE_MODAL: 'changeModal', + SET_REPLY_TO: 'setReplyTo', + UPDATE_INITIAL_STATUS: 'updateInitialStatus', + UPDATE_INITIAL_SPOILER: 'updateInitialSpoiler', + CHANGE_BLOCK_SUBMIT: 'changeBlockSubmit', + APPEND_ATTACHED_MEDIAS: 'appendAttachedMedias', + CLEAR_ATTACHED_MEDIAS: 'clearAttachedMedias', + REMOVE_MEDIA: 'removeMedia', + CHANGE_VISIBILITY_VALUE: 'changeVisibilityValue', + CHANGE_SENSITIVE: 'changeSensitive', + UPDATE_MEDIA_ID: 'updateMediaId', + CHANGE_PINED_HASHTAG: 'changePinedHashtag', + UPDATE_HASHTAGS: 'updateHashtags' +} + +const mutations: MutationTree = { + [MUTATION_TYPES.CHANGE_MODAL]: (state, value: boolean) => { + state.modalOpen = value + }, + [MUTATION_TYPES.SET_REPLY_TO]: (state, message: Status) => { + state.replyToMessage = message + }, + [MUTATION_TYPES.UPDATE_INITIAL_STATUS]: (state, status: string) => { + state.initialStatus = status + }, + [MUTATION_TYPES.UPDATE_INITIAL_SPOILER]: (state, cw: string) => { + state.initialSpoiler = cw + }, + [MUTATION_TYPES.CHANGE_BLOCK_SUBMIT]: (state, value: boolean) => { + state.blockSubmit = value + }, + [MUTATION_TYPES.APPEND_ATTACHED_MEDIAS]: (state, media: Attachment) => { + state.attachedMedias = state.attachedMedias.concat([media]) + }, + [MUTATION_TYPES.CLEAR_ATTACHED_MEDIAS]: (state) => { + state.attachedMedias = [] + }, + [MUTATION_TYPES.REMOVE_MEDIA]: (state, media: Attachment) => { + state.attachedMedias = state.attachedMedias.filter(m => m.id !== media.id) + }, + /** + * changeVisibilityValue + * Update visibility using direct value + * @param state vuex state object + * @param value visibility value + */ + [MUTATION_TYPES.CHANGE_VISIBILITY_VALUE]: (state, value: number) => { + state.visibility = value + }, + [MUTATION_TYPES.CHANGE_SENSITIVE]: (state, value: boolean) => { + state.sensitive = value + }, + [MUTATION_TYPES.UPDATE_MEDIA_ID]: (state, value: number) => { + state.attachedMediaId = value + }, + [MUTATION_TYPES.CHANGE_PINED_HASHTAG]: (state, value: boolean) => { + state.pinedHashtag = value + }, + [MUTATION_TYPES.UPDATE_HASHTAGS]: (state, tags: Array) => { + state.hashtags = tags + } +} + +const actions: ActionTree = { + updateMedia: async ({ rootState }, media: Attachment) => { + if (rootState.TimelineSpace.account.accessToken === undefined || rootState.TimelineSpace.account.accessToken === null) { + throw new AuthenticationError() + } + const client = new Mastodon( + rootState.TimelineSpace.account.accessToken, + rootState.TimelineSpace.account.baseURL + '/api/v1' + ) + return Promise.all( + Object.keys(media).map(async id => { + return client.put(`/media/${id}`, { description: media[id] }) + })).catch(err => { + console.error(err) + throw err + }) + }, + postToot: async ({ state, commit, rootState }, form) => { + if (rootState.TimelineSpace.account.accessToken === undefined || rootState.TimelineSpace.account.accessToken === null) { + throw new AuthenticationError() + } + if (state.blockSubmit) { + return + } + commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, true) + const client = new Mastodon( + rootState.TimelineSpace.account.accessToken, + rootState.TimelineSpace.account.baseURL + '/api/v1' + ) + return client.post('/statuses', form) + .then((res: Response) => { + ipcRenderer.send('toot-action-sound') + return res.data + }) + .finally(() => { + commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, false) + }) + }, + openReply: ({ commit, rootState }, message: Status) => { + commit(MUTATION_TYPES.SET_REPLY_TO, message) + const mentionAccounts = [message.account.acct].concat(message.mentions.map(a => a.acct)) + .filter((a, i, self) => self.indexOf(a) === i) + .filter((a) => a !== rootState.TimelineSpace.account.username) + commit(MUTATION_TYPES.UPDATE_INITIAL_STATUS, `${mentionAccounts.map(m => `@${m}`).join(' ')} `) + commit(MUTATION_TYPES.UPDATE_INITIAL_SPOILER, message.spoiler_text) + commit(MUTATION_TYPES.CHANGE_MODAL, true) + let value: number = Visibility.Public.value + Object.keys(Visibility).map(key => { + const target = Visibility[key] + if (target.key === message.visibility) { + value = target.value + } + }) + commit(MUTATION_TYPES.CHANGE_VISIBILITY_VALUE, value) + }, + openModal: ({ dispatch, commit, state }) => { + if (!state.replyToMessage && state.pinedHashtag) { + commit(MUTATION_TYPES.UPDATE_INITIAL_STATUS, state.hashtags.map(t => ` #${t.name}`).join()) + } + commit(MUTATION_TYPES.CHANGE_MODAL, true) + dispatch('fetchVisibility') + }, + closeModal: ({ commit }) => { + commit(MUTATION_TYPES.CHANGE_MODAL, false) + commit(MUTATION_TYPES.UPDATE_INITIAL_STATUS, '') + commit(MUTATION_TYPES.UPDATE_INITIAL_SPOILER, '') + commit(MUTATION_TYPES.SET_REPLY_TO, null) + commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, false) + commit(MUTATION_TYPES.CLEAR_ATTACHED_MEDIAS) + commit(MUTATION_TYPES.CHANGE_SENSITIVE, false) + commit(MUTATION_TYPES.CHANGE_VISIBILITY_VALUE, Visibility.Public.value) + }, + uploadImage: async ({ commit, rootState }, image: any) => { + commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, true) + if (rootState.TimelineSpace.account.accessToken === undefined || rootState.TimelineSpace.account.accessToken === null) { + throw new AuthenticationError() + } + const client = new Mastodon( + rootState.TimelineSpace.account.accessToken, + rootState.TimelineSpace.account.baseURL + '/api/v1' + ) + const formData = new FormData() + formData.append('file', image) + return client.post('/media', formData) + .then(res => { + commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, false) + if (res.data.type === 'unknown') throw new UnknownTypeError() + commit(MUTATION_TYPES.APPEND_ATTACHED_MEDIAS, res.data) + return res.data + }) + .catch(err => { + commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, false) + console.error(err) + throw err + }) + }, + incrementMediaId: ({ commit, state }) => { + commit(MUTATION_TYPES.UPDATE_MEDIA_ID, state.attachedMediaId + 1) + }, + resetMediaId: ({ commit }) => { + commit(MUTATION_TYPES.UPDATE_MEDIA_ID, 0) + }, + updateHashtags: ({ commit, state }, tags: Array) => { + if (state.pinedHashtag) { + commit(MUTATION_TYPES.UPDATE_HASHTAGS, tags) + } + }, + fetchVisibility: async ({ commit, rootState }) => { + const client = new Mastodon( + rootState.TimelineSpace.account.accessToken!, + rootState.TimelineSpace.account.baseURL + '/api/v1' + ) + const res: Response = await client.get('/accounts/verify_credentials') + const visibility: VisibilityType = Object.values(Visibility as Array).find((v) => { + return v.key === res.data.source!.privacy + }) + if (visibility === undefined) { + throw new Error('Visibility value is invalid') + } + commit(MUTATION_TYPES.CHANGE_VISIBILITY_VALUE, visibility.value) + return res.data + } +} + +const getters: GetterTree = { + hashtagInserting: (state) => { + return !state.replyToMessage && state.pinedHashtag + } +} + +const NewToot: Module = { + namespaced: true, + modules: { + Status: TootStatus + }, + state: state, + mutations: mutations, + getters: getters, + actions: actions +} + +export default NewToot + +class AuthenticationError {} +class UnknownTypeError {} diff --git a/src/renderer/store/TimelineSpace/Modals/NewToot/Status.js b/src/renderer/store/TimelineSpace/Modals/NewToot/Status.js deleted file mode 100644 index 802a7fbe..00000000 --- a/src/renderer/store/TimelineSpace/Modals/NewToot/Status.js +++ /dev/null @@ -1,73 +0,0 @@ -import Mastodon from 'megalodon' - -const Status = { - namespaced: true, - state: { - filteredAccounts: [], - filteredHashtags: [] - }, - mutations: { - updateFilteredAccounts (state, accounts) { - state.filteredAccounts = accounts.map((a) => { - return { - name: `@${a.acct}`, - image: null - } - }) - }, - clearFilteredAccounts (state) { - state.filteredAccounts = [] - }, - updateFilteredHashtags (state, tags) { - state.filteredHashtags = tags.map((t) => { - return { - name: `#${t}`, - image: null - } - }) - }, - clearFilteredHashtags (state) { - state.filteredHashtags = [] - } - }, - actions: { - async searchAccount ({ commit, rootState }, word) { - const client = new Mastodon( - rootState.TimelineSpace.account.accessToken, - rootState.TimelineSpace.account.baseURL + '/api/v1' - ) - const res = await client.get('/search', { q: word, resolve: false }) - commit('updateFilteredAccounts', res.data.accounts) - if (res.data.accounts.length === 0) throw new Error('Empty') - return res.data.accounts - }, - async searchHashtag ({ commit, rootState }, word) { - const client = new Mastodon( - rootState.TimelineSpace.account.accessToken, - rootState.TimelineSpace.account.baseURL + '/api/v1' - ) - const res = await client.get('/search', { q: word }) - commit('updateFilteredHashtags', res.data.hashtags) - if (res.data.hashtags.length === 0) throw new Error('Empty') - return res.data.hashtags - } - }, - getters: { - pickerEmojis: (state, getters, rootState) => { - return rootState.TimelineSpace.emojis.filter((e, i, array) => { - return (array.findIndex(ar => e.name === ar.name) === i) - }).map(e => { - return { - name: e.name, - short_names: [e.name], - text: e.name, - emoticons: [], - keywords: [e.name], - imageUrl: e.image - } - }) - } - } -} - -export default Status diff --git a/src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts b/src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts new file mode 100644 index 00000000..227149a2 --- /dev/null +++ b/src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts @@ -0,0 +1,104 @@ +import Mastodon, { Account, Tag, Response, Results } from 'megalodon' +import { Module, MutationTree, ActionTree, GetterTree } from 'vuex' +import { RootState } from '@/store/index' + +interface Suggest { + name: string, + image: string | null +} + +interface SuggestAccount extends Suggest {} + +interface SuggestHashtag extends Suggest {} + +export interface StatusState { + filteredAccounts: Array, + filteredHashtags: Array +} + +const state = (): StatusState => ({ + filteredAccounts: [], + filteredHashtags: [] +}) + +export const MUTATION_TYPES = { + UPDATE_FILTERED_ACCOUNTS: 'updateFilteredAccounts', + CLEAR_FILTERED_ACCOUNTS: 'clearFilteredAccounts', + UPDATE_FILTERED_HASHTAGS: 'updateFilteredHashtags', + CLAER_FILTERED_HASHTAGS: 'clearFilteredHashtags' +} + +const mutations: MutationTree = { + [MUTATION_TYPES.UPDATE_FILTERED_ACCOUNTS]: (state, accounts: Array) => { + state.filteredAccounts = accounts.map((a) => { + return { + name: `@${a.acct}`, + image: null + } + }) + }, + [MUTATION_TYPES.CLEAR_FILTERED_ACCOUNTS]: (state) => { + state.filteredAccounts = [] + }, + [MUTATION_TYPES.UPDATE_FILTERED_HASHTAGS]: (state, tags: Array) => { + state.filteredHashtags = tags.map((t) => { + return { + name: `#${t}`, + image: null + } + }) + }, + [MUTATION_TYPES.CLEAR_FILTERED_ACCOUNTS]: (state) => { + state.filteredHashtags = [] + } +} + +const actions: ActionTree = { + searchAccount: async ({ commit, rootState }, word: string) => { + const client = new Mastodon( + rootState.TimelineSpace.account.accessToken!, + rootState.TimelineSpace.account.baseURL + '/api/v1' + ) + const res: Response = await client.get('/search', { q: word, resolve: false }) + commit(MUTATION_TYPES.UPDATE_FILTERED_ACCOUNTS, res.data.accounts) + if (res.data.accounts.length === 0) throw new Error('Empty') + return res.data.accounts + }, + searchHashtag: async ({ commit, rootState }, word: string) => { + const client = new Mastodon( + rootState.TimelineSpace.account.accessToken!, + rootState.TimelineSpace.account.baseURL + '/api/v1' + ) + const res: Response = await client.get('/search', { q: word }) + commit(MUTATION_TYPES.UPDATE_FILTERED_HASHTAGS, res.data.hashtags) + if (res.data.hashtags.length === 0) throw new Error('Empty') + return res.data.hashtags + } +} + +const getters: GetterTree = { + pickerEmojis: (_state, _getters, rootState) => { + return rootState.TimelineSpace.emojis.filter((e, i, array) => { + return (array.findIndex(ar => e.name === ar.name) === i) + }).map(e => { + return { + name: e.name, + short_names: [e.name], + text: e.name, + emoticons: [], + keywords: [e.name], + imageUrl: e.image + } + }) + } +} + +const Status: Module = { + namespaced: true, + state: state, + mutations: mutations, + actions: actions, + getters: getters +} + +export default Status diff --git a/tsconfig.json b/tsconfig.json index 821b00f6..0d48eb32 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,11 @@ "compilerOptions": { "target": "es5", "module": "es2015", - "lib": ["es6"], + "lib": [ + "dom", + "dom.iterable", + "es6" + ], "sourceMap": true, "downlevelIteration": true, "strict": true, From ac215112366934a0185877da6bcf94b063bbbe5c Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Thu, 11 Apr 2019 00:15:12 +0900 Subject: [PATCH 08/11] refs #850 Replace Report with typescript --- src/renderer/store/TimelineSpace/Modals.ts | 5 +- .../store/TimelineSpace/Modals/Report.js | 34 ------------ .../store/TimelineSpace/Modals/Report.ts | 52 +++++++++++++++++++ 3 files changed, 55 insertions(+), 36 deletions(-) delete mode 100644 src/renderer/store/TimelineSpace/Modals/Report.js create mode 100644 src/renderer/store/TimelineSpace/Modals/Report.ts diff --git a/src/renderer/store/TimelineSpace/Modals.ts b/src/renderer/store/TimelineSpace/Modals.ts index 5c0392ae..11b31bb9 100644 --- a/src/renderer/store/TimelineSpace/Modals.ts +++ b/src/renderer/store/TimelineSpace/Modals.ts @@ -5,7 +5,7 @@ import ListMembership, { ListMembershipState } from './Modals/ListMembership' import AddListMember, { AddListMemberState } from './Modals/AddListMember' import MuteConfirm, { MuteConfirmState } from './Modals/MuteConfirm' import Shortcut from './Modals/Shortcut' -import Report from './Modals/Report' +import Report, { ReportState } from './Modals/Report' import { Module, GetterTree } from 'vuex' import { RootState } from '@/store/index' @@ -17,7 +17,8 @@ export interface ModalsModuleState extends ModalsState { ImageViewer: ImageViewerState, ListMembership: ListMembershipState, MuteConfirm: MuteConfirmState, - NewToot: NewTootModuleState + NewToot: NewTootModuleState, + Report: ReportState } const state = (): ModalsState => ({}) diff --git a/src/renderer/store/TimelineSpace/Modals/Report.js b/src/renderer/store/TimelineSpace/Modals/Report.js deleted file mode 100644 index 73a526f6..00000000 --- a/src/renderer/store/TimelineSpace/Modals/Report.js +++ /dev/null @@ -1,34 +0,0 @@ -import Mastodon from 'megalodon' - -export default { - namespaced: true, - state: { - modalOpen: false, - message: {} - }, - mutations: { - changeModalOpen (state, value) { - state.modalOpen = value - }, - changeMessage (state, value) { - state.message = value - } - }, - actions: { - openReport ({ commit }, message) { - commit('changeMessage', message) - commit('changeModalOpen', true) - }, - submit ({ rootState }, payload) { - const client = new Mastodon( - rootState.TimelineSpace.account.accessToken, - rootState.TimelineSpace.account.baseURL + '/api/v1' - ) - return client.post(`/reports`, { - account_id: payload.account_id, - status_ids: [payload.status_id], - comment: payload.comment - }) - } - } -} diff --git a/src/renderer/store/TimelineSpace/Modals/Report.ts b/src/renderer/store/TimelineSpace/Modals/Report.ts new file mode 100644 index 00000000..0fa77a50 --- /dev/null +++ b/src/renderer/store/TimelineSpace/Modals/Report.ts @@ -0,0 +1,52 @@ +import Mastodon, { Status } from 'megalodon' +import { Module, MutationTree, ActionTree } from 'vuex' +import { RootState } from '@/store' + +export interface ReportState { + modalOpen: boolean, + message: Status | null +} + +const state = (): ReportState => ({ + modalOpen: false, + message: null +}) + +export const MUTATION_TYPES = { + CHANGE_MODAL_OPEN: 'changeModalOpen', + CHANGE_MESSAGE: 'changeMessage' +} + +const mutations: MutationTree = { + [MUTATION_TYPES.CHANGE_MODAL_OPEN]: (state, value: boolean) => { + state.modalOpen = value + }, + [MUTATION_TYPES.CHANGE_MESSAGE]: (state, message: Status) => { + state.message = message + } +} + +const actions: ActionTree = { + openReport: ({ commit }, message: Status) => { + commit(MUTATION_TYPES.CHANGE_MESSAGE, message) + commit(MUTATION_TYPES.CHANGE_MODAL_OPEN, true) + }, + submit: async ({ rootState }, { account_id, status_id, comment }) => { + const client = new Mastodon( + rootState.TimelineSpace.account.accessToken!, + rootState.TimelineSpace.account.baseURL + '/api/v1' + ) + return client.post<{}>(`/reports`, { + account_id: account_id, + status_ids: [status_id], + comment: comment + }) + } +} + +export default { + namespaced: true, + state: state, + mutations: mutations, + actions: actions +} as Module From b9941e71c345ae1f0c02495b99b1e47da7e3d1e5 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Thu, 11 Apr 2019 00:19:25 +0900 Subject: [PATCH 09/11] refs #850 Replace Shortcut with typescript --- src/renderer/store/TimelineSpace/Modals.ts | 5 ++-- .../store/TimelineSpace/Modals/Shortcut.js | 11 -------- .../store/TimelineSpace/Modals/Shortcut.ts | 26 +++++++++++++++++++ 3 files changed, 29 insertions(+), 13 deletions(-) delete mode 100644 src/renderer/store/TimelineSpace/Modals/Shortcut.js create mode 100644 src/renderer/store/TimelineSpace/Modals/Shortcut.ts diff --git a/src/renderer/store/TimelineSpace/Modals.ts b/src/renderer/store/TimelineSpace/Modals.ts index 11b31bb9..67ca9139 100644 --- a/src/renderer/store/TimelineSpace/Modals.ts +++ b/src/renderer/store/TimelineSpace/Modals.ts @@ -4,7 +4,7 @@ import Jump, { JumpState } from './Modals/Jump' import ListMembership, { ListMembershipState } from './Modals/ListMembership' import AddListMember, { AddListMemberState } from './Modals/AddListMember' import MuteConfirm, { MuteConfirmState } from './Modals/MuteConfirm' -import Shortcut from './Modals/Shortcut' +import Shortcut, { ShortcutState } from './Modals/Shortcut' import Report, { ReportState } from './Modals/Report' import { Module, GetterTree } from 'vuex' import { RootState } from '@/store/index' @@ -18,7 +18,8 @@ export interface ModalsModuleState extends ModalsState { ListMembership: ListMembershipState, MuteConfirm: MuteConfirmState, NewToot: NewTootModuleState, - Report: ReportState + Report: ReportState, + Shortcut: ShortcutState } const state = (): ModalsState => ({}) diff --git a/src/renderer/store/TimelineSpace/Modals/Shortcut.js b/src/renderer/store/TimelineSpace/Modals/Shortcut.js deleted file mode 100644 index 081d3354..00000000 --- a/src/renderer/store/TimelineSpace/Modals/Shortcut.js +++ /dev/null @@ -1,11 +0,0 @@ -export default { - namespaced: true, - state: { - modalOpen: false - }, - mutations: { - changeModal (state, value) { - state.modalOpen = value - } - } -} diff --git a/src/renderer/store/TimelineSpace/Modals/Shortcut.ts b/src/renderer/store/TimelineSpace/Modals/Shortcut.ts new file mode 100644 index 00000000..7d19097f --- /dev/null +++ b/src/renderer/store/TimelineSpace/Modals/Shortcut.ts @@ -0,0 +1,26 @@ +import { Module, MutationTree } from 'vuex' +import { RootState } from '@/store' + +export interface ShortcutState { + modalOpen: boolean +} + +const state = (): ShortcutState => ({ + modalOpen: false +}) + +export const MUTATION_TYPES = { + CHANGE_MODAL: 'changeModal' +} + +const mutations: MutationTree = { + [MUTATION_TYPES.CHANGE_MODAL]: (state, value: boolean) => { + state.modalOpen = value + } +} + +export default { + namespaced: true, + state: state, + mutations: mutations +} as Module From 21605412cf47d3580fc7af7d06feb7ca75b37031 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Thu, 11 Apr 2019 00:24:34 +0900 Subject: [PATCH 10/11] [eslint] refs #850 Fix indent spaces for NewToot --- .../store/TimelineSpace/Modals/NewToot.ts | 9 ++++---- .../TimelineSpace/Modals/NewToot/Status.ts | 22 ++++++++----------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/renderer/store/TimelineSpace/Modals/NewToot.ts b/src/renderer/store/TimelineSpace/Modals/NewToot.ts index 68f16c4e..02ba061b 100644 --- a/src/renderer/store/TimelineSpace/Modals/NewToot.ts +++ b/src/renderer/store/TimelineSpace/Modals/NewToot.ts @@ -111,10 +111,11 @@ const actions: ActionTree = { rootState.TimelineSpace.account.accessToken, rootState.TimelineSpace.account.baseURL + '/api/v1' ) - return Promise.all( - Object.keys(media).map(async id => { - return client.put(`/media/${id}`, { description: media[id] }) - })).catch(err => { + const attachments = Object.keys(media).map(async id => { + return client.put(`/media/${id}`, { description: media[id] }) + }) + return Promise.all(attachments) + .catch(err => { console.error(err) throw err }) diff --git a/src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts b/src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts index 227149a2..697bf16e 100644 --- a/src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts +++ b/src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts @@ -30,23 +30,19 @@ export const MUTATION_TYPES = { const mutations: MutationTree = { [MUTATION_TYPES.UPDATE_FILTERED_ACCOUNTS]: (state, accounts: Array) => { - state.filteredAccounts = accounts.map((a) => { - return { - name: `@${a.acct}`, - image: null - } - }) + state.filteredAccounts = accounts.map(a => ({ + name: `@${a.acct}`, + image: null + })) }, [MUTATION_TYPES.CLEAR_FILTERED_ACCOUNTS]: (state) => { state.filteredAccounts = [] }, [MUTATION_TYPES.UPDATE_FILTERED_HASHTAGS]: (state, tags: Array) => { - state.filteredHashtags = tags.map((t) => { - return { - name: `#${t}`, - image: null - } - }) + state.filteredHashtags = tags.map(t => ({ + name: `#${t}`, + image: null + })) }, [MUTATION_TYPES.CLEAR_FILTERED_ACCOUNTS]: (state) => { state.filteredHashtags = [] @@ -70,7 +66,7 @@ const actions: ActionTree = { rootState.TimelineSpace.account.baseURL + '/api/v1' ) const res: Response = await client.get('/search', { q: word }) - commit(MUTATION_TYPES.UPDATE_FILTERED_HASHTAGS, res.data.hashtags) + commit(MUTATION_TYPES.UPDATE_FILTERED_HASHTAGS, res.data.hashtags) if (res.data.hashtags.length === 0) throw new Error('Empty') return res.data.hashtags } From 2304b98260b07a889b1c4fb2292701950a1724ad Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Thu, 11 Apr 2019 00:30:54 +0900 Subject: [PATCH 11/11] refs #850 Fix spec for Modals --- .../Modals/AddListMember.spec.ts | 6 ++-- .../TimelineSpace/Modals/ImageViewer.spec.ts | 4 +-- .../Modals/ListMembership.spec.ts | 32 +++++++++++++++---- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/spec/renderer/integration/store/TimelineSpace/Modals/AddListMember.spec.ts b/spec/renderer/integration/store/TimelineSpace/Modals/AddListMember.spec.ts index 5f5c1b06..67ae6446 100644 --- a/spec/renderer/integration/store/TimelineSpace/Modals/AddListMember.spec.ts +++ b/spec/renderer/integration/store/TimelineSpace/Modals/AddListMember.spec.ts @@ -2,7 +2,7 @@ import { Response, Account } from 'megalodon' import mockedMegalodon from '~/spec/mock/megalodon' import { createLocalVue } from '@vue/test-utils' import Vuex from 'vuex' -import AddListMember from '~/src/renderer/store/TimelineSpace/Modals/AddListMember' +import AddListMember, { AddListMemberState } from '@/store/TimelineSpace/Modals/AddListMember' jest.mock('megalodon') @@ -28,7 +28,7 @@ const account: Account = { bot: false } -const state = () => { +const state = (): AddListMemberState => { return { modalOpen: false, accounts: [], @@ -121,7 +121,7 @@ describe('AddListMember', () => { mockedMegalodon.mockImplementation(() => mockClient) const result = await store.dispatch('AddListMember/add', 'akira') - expect(result.data).toEqual({}) + expect(result).toEqual({}) }) }) }) diff --git a/spec/renderer/integration/store/TimelineSpace/Modals/ImageViewer.spec.ts b/spec/renderer/integration/store/TimelineSpace/Modals/ImageViewer.spec.ts index 52681ee3..b3a3a21d 100644 --- a/spec/renderer/integration/store/TimelineSpace/Modals/ImageViewer.spec.ts +++ b/spec/renderer/integration/store/TimelineSpace/Modals/ImageViewer.spec.ts @@ -1,8 +1,8 @@ import { createLocalVue } from '@vue/test-utils' import Vuex from 'vuex' -import ImageViewer from '~/src/renderer/store/TimelineSpace/Modals/ImageViewer' +import ImageViewer, { ImageViewerState } from '~/src/renderer/store/TimelineSpace/Modals/ImageViewer' -const state = () => { +const state = (): ImageViewerState => { return { modalOpen: false, currentIndex: -1, diff --git a/spec/renderer/integration/store/TimelineSpace/Modals/ListMembership.spec.ts b/spec/renderer/integration/store/TimelineSpace/Modals/ListMembership.spec.ts index 8e8003d7..843e95c0 100644 --- a/spec/renderer/integration/store/TimelineSpace/Modals/ListMembership.spec.ts +++ b/spec/renderer/integration/store/TimelineSpace/Modals/ListMembership.spec.ts @@ -1,11 +1,33 @@ -import { Response, List } from 'megalodon' +import { Response, List, Account } from 'megalodon' import mockedMegalodon from '~/spec/mock/megalodon' import { createLocalVue } from '@vue/test-utils' import Vuex from 'vuex' -import ListMembership from '~/src/renderer/store/TimelineSpace/Modals/ListMembership' +import ListMembership, { ListMembershipState } from '@/store/TimelineSpace/Modals/ListMembership' jest.mock('megalodon') +const account: Account = { + id: 1, + username: 'h3poteto', + acct: 'h3poteto@pleroma.io', + display_name: 'h3poteto', + locked: false, + created_at: '2019-03-26T21:30:32', + followers_count: 10, + following_count: 10, + statuses_count: 100, + note: 'engineer', + url: 'https://pleroma.io', + avatar: '', + avatar_static: '', + header: '', + header_static: '', + emojis: [], + moved: null, + fields: null, + bot: false +} + const list1: List = { id: 1, title: 'list1' @@ -16,7 +38,7 @@ const list2: List = { title: 'list2' } -let state: any = () => { +let state = (): ListMembershipState => { return { modalOpen: false, account: null, @@ -116,9 +138,7 @@ describe('ListMembership', () => { state = () => { return { modalOpen: false, - account: { - id: 65 - }, + account: account, lists: [], belongToLists: [ list2