From 252c540829bfb5df61d56f5d32b45cc4637b80fd Mon Sep 17 00:00:00 2001
From: AkiraFukushima
Date: Tue, 14 May 2019 00:25:09 +0900
Subject: [PATCH 1/2] refactor: Move logics to store in new toot
---
.../TimelineSpace/Modals/NewToot.vue | 64 ++++----------
src/renderer/errors/validations/index.js | 7 ++
.../store/TimelineSpace/Modals/NewToot.ts | 87 ++++++++++++++++++-
3 files changed, 105 insertions(+), 53 deletions(-)
create mode 100644 src/renderer/errors/validations/index.js
diff --git a/src/renderer/components/TimelineSpace/Modals/NewToot.vue b/src/renderer/components/TimelineSpace/Modals/NewToot.vue
index a1d3bfee..c5b21e84 100644
--- a/src/renderer/components/TimelineSpace/Modals/NewToot.vue
+++ b/src/renderer/components/TimelineSpace/Modals/NewToot.vue
@@ -22,7 +22,8 @@
maxlength="420"
class="image-description"
:placeholder="$t('modals.new_toot.description')"
- v-model="mediaDescriptions[media.id]"
+ :value="mediaDescriptions[media.id]"
+ @input="updateDescription(media.id, $event.target.value)"
v-shortkey="{ left: ['arrowleft'], right: ['arrowright'] }"
@shortkey="handleDescriptionKey"
role="textbox"
@@ -128,7 +129,6 @@ export default {
data() {
return {
status: '',
- mediaDescriptions: {},
spoiler: '',
showContentWarning: false,
visibilityList: Visibility
@@ -145,6 +145,7 @@ export default {
},
attachedMedias: state => state.attachedMedias,
attachedMediaId: state => state.attachedMediaId,
+ mediaDescriptions: state => state.mediaDescriptions,
blockSubmit: state => state.blockSubmit,
visibility: state => state.visibility,
sensitive: state => state.sensitive,
@@ -210,55 +211,18 @@ export default {
this.$store.dispatch('TimelineSpace/Modals/NewToot/closeModal')
},
async toot() {
- if (!this.newTootModal) {
- return
- }
- if (this.status.length < 1 || this.status.length > this.tootMax) {
- return this.$message({
- message: this.$t('validation.new_toot.toot_length', { min: 1, max: this.tootMax }),
- type: 'error'
- })
- }
- const visibilityKey = Object.keys(Visibility).find(key => {
- return Visibility[key].value === this.visibility
- })
- let form = {
+ const form = {
status: this.status,
- visibility: Visibility[visibilityKey].key,
- sensitive: this.sensitive,
- spoiler_text: this.spoiler
- }
- if (this.replyToId !== null) {
- form = Object.assign(form, {
- in_reply_to_id: this.replyToId
- })
- }
- if (this.attachedMedias.length > 0) {
- if (this.attachedMedias.length > 4) {
- return this.$message({
- message: this.$t('validation.new_toot.attach_length', { max: 4 }),
- type: 'error'
- })
- }
- form = Object.assign(form, {
- media_ids: this.attachedMedias.map(m => {
- return m.id
- })
- })
+ spoiler: this.spoiler
}
- const status = await this.$store
- .dispatch('TimelineSpace/Modals/NewToot/updateMedia', this.mediaDescriptions)
- .then(() => {
- return this.$store.dispatch('TimelineSpace/Modals/NewToot/postToot', form)
- })
- .catch(e => {
- console.error(e)
- this.$message({
- message: this.$t('message.toot_error'),
- type: 'error'
- })
+ await this.$store.dispatch('TimelineSpace/Modals/NewToot/postToot', form).catch(err => {
+ console.error(err)
+ this.$message({
+ message: this.$t('message.toot_error'),
+ type: 'error'
})
+ })
this.$store.dispatch('TimelineSpace/Modals/NewToot/updateHashtags', status.tags)
this.close()
},
@@ -305,8 +269,7 @@ export default {
})
},
removeAttachment(media) {
- this.$store.commit('TimelineSpace/Modals/NewToot/removeMedia', media)
- delete this.mediaDescriptions[media.id]
+ this.$store.dispatch('TimelineSpace/Modals/NewToot/removeMedia', media)
},
changeVisibility(level) {
this.$store.commit('TimelineSpace/Modals/NewToot/changeVisibilityValue', level)
@@ -340,6 +303,9 @@ export default {
default:
return true
}
+ },
+ updateDescription(id, value) {
+ this.$store.commit('TimelineSpace/Modals/NewToot/updateMediaDescription', { id: id, description: value })
}
}
}
diff --git a/src/renderer/errors/validations/index.js b/src/renderer/errors/validations/index.js
new file mode 100644
index 00000000..c45d8014
--- /dev/null
+++ b/src/renderer/errors/validations/index.js
@@ -0,0 +1,7 @@
+export class NewTootModalOpen extends Error {}
+
+export class NewTootTootLength extends Error {}
+
+export class NewTootAttachLength extends Error {}
+
+export class NewTootMediaDescription extends Error {}
diff --git a/src/renderer/store/TimelineSpace/Modals/NewToot.ts b/src/renderer/store/TimelineSpace/Modals/NewToot.ts
index 47aefcdc..a3c6a495 100644
--- a/src/renderer/store/TimelineSpace/Modals/NewToot.ts
+++ b/src/renderer/store/TimelineSpace/Modals/NewToot.ts
@@ -5,6 +5,12 @@ import TootStatus, { StatusState } from './NewToot/Status'
import { Module, MutationTree, ActionTree, GetterTree } from 'vuex'
import { RootState } from '@/store'
import AxiosLoading from '@/utils/axiosLoading'
+import { NewTootModalOpen, NewTootTootLength, NewTootAttachLength, NewTootMediaDescription } from '@/errors/validations'
+
+type MediaDescription = {
+ id: number
+ description: string
+}
export interface NewTootState {
modalOpen: boolean
@@ -13,6 +19,7 @@ export interface NewTootState {
replyToMessage: Status | null
blockSubmit: boolean
attachedMedias: Array
+ mediaDescriptions: { [key: number]: string | null }
visibility: number
sensitive: boolean
attachedMediaId: number
@@ -32,6 +39,7 @@ const state = (): NewTootState => ({
replyToMessage: null,
blockSubmit: false,
attachedMedias: [],
+ mediaDescriptions: {},
visibility: Visibility.Public.value,
sensitive: false,
attachedMediaId: 0,
@@ -49,6 +57,9 @@ export const MUTATION_TYPES = {
APPEND_ATTACHED_MEDIAS: 'appendAttachedMedias',
CLEAR_ATTACHED_MEDIAS: 'clearAttachedMedias',
REMOVE_MEDIA: 'removeMedia',
+ UPDATE_MEDIA_DESCRIPTION: 'updateMediaDescription',
+ CLEAR_MEDIA_DESCRIPTIONS: 'clearMediaDescriptions',
+ REMOVE_MEDIA_DESCRIPTION: 'removeMediaDescription',
CHANGE_VISIBILITY_VALUE: 'changeVisibilityValue',
CHANGE_SENSITIVE: 'changeSensitive',
UPDATE_MEDIA_ID: 'updateMediaId',
@@ -82,6 +93,17 @@ const mutations: MutationTree = {
[MUTATION_TYPES.REMOVE_MEDIA]: (state, media: Attachment) => {
state.attachedMedias = state.attachedMedias.filter(m => m.id !== media.id)
},
+ [MUTATION_TYPES.UPDATE_MEDIA_DESCRIPTION]: (state, value: MediaDescription) => {
+ state.mediaDescriptions[value.id] = value.description
+ },
+ [MUTATION_TYPES.CLEAR_MEDIA_DESCRIPTIONS]: state => {
+ state.mediaDescriptions = {}
+ },
+ [MUTATION_TYPES.REMOVE_MEDIA_DESCRIPTION]: (state, id: number) => {
+ const descriptions = state.mediaDescriptions
+ delete descriptions[id]
+ state.mediaDescriptions = descriptions
+ },
/**
* changeVisibilityValue
* Update visibility using direct value
@@ -118,20 +140,52 @@ const actions: ActionTree = {
commit(MUTATION_TYPES.CHANGE_LOADING, false)
})
},
- updateMedia: async ({ rootState }, media: Attachment) => {
+ updateMedia: async ({ rootState }, mediaDescription: MediaDescription) => {
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 attachments = Object.keys(media).map(async id => {
- return client.put(`/media/${id}`, { description: media[id] })
+ const attachments = Object.keys(mediaDescription).map(async id => {
+ if (mediaDescription[id] !== null) {
+ return client.put(`/media/${id}`, { description: mediaDescription[id] })
+ } else {
+ return Promise.resolve({})
+ }
})
return Promise.all(attachments).catch(err => {
console.error(err)
throw err
})
},
- postToot: async ({ state, commit, rootState }, form) => {
+ postToot: async ({ state, commit, rootState, dispatch }, { status, spoiler }) => {
+ if (!state.modalOpen) {
+ throw new NewTootModalOpen()
+ }
+
+ if (status.length < 1 || status.length > rootState.TimelineSpace.tootMax) {
+ throw new NewTootTootLength()
+ }
+
+ const visibilityKey: string | undefined = Object.keys(Visibility).find(key => {
+ return Visibility[key].value === state.visibility
+ })
+ let specifiedVisibility: string = Visibility.Public.key
+ if (visibilityKey !== undefined) {
+ specifiedVisibility = Visibility[visibilityKey].key
+ }
+ let form = {
+ status: status,
+ visibility: specifiedVisibility,
+ sensitive: state.sensitive,
+ spoiler_text: spoiler
+ }
+
+ if (state.replyToMessage !== null) {
+ form = Object.assign(form, {
+ in_reply_to_id: state.replyToMessage.id
+ })
+ }
+
if (rootState.TimelineSpace.account.accessToken === undefined || rootState.TimelineSpace.account.accessToken === null) {
throw new AuthenticationError()
}
@@ -139,6 +193,22 @@ const actions: ActionTree = {
return
}
commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, true)
+
+ if (state.attachedMedias.length > 0) {
+ if (state.attachedMedias.length > 4) {
+ throw new NewTootAttachLength()
+ }
+ form = Object.assign(form, {
+ media_ids: state.attachedMedias.map(m => {
+ return m.id
+ })
+ })
+ // Update media descriptions
+ await dispatch('updateMedia', state.mediaDescriptions).catch(_ => {
+ throw new NewTootMediaDescription()
+ })
+ }
+
const client = new Mastodon(rootState.TimelineSpace.account.accessToken, rootState.TimelineSpace.account.baseURL + '/api/v1')
return client
.post('/statuses', form)
@@ -182,6 +252,7 @@ const actions: ActionTree = {
commit(MUTATION_TYPES.SET_REPLY_TO, null)
commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, false)
commit(MUTATION_TYPES.CLEAR_ATTACHED_MEDIAS)
+ commit(MUTATION_TYPES.CLEAR_MEDIA_DESCRIPTIONS)
commit(MUTATION_TYPES.CHANGE_SENSITIVE, false)
commit(MUTATION_TYPES.CHANGE_VISIBILITY_VALUE, Visibility.Public.value)
},
@@ -210,9 +281,17 @@ const actions: ActionTree = {
incrementMediaId: ({ commit, state }) => {
commit(MUTATION_TYPES.UPDATE_MEDIA_ID, state.attachedMediaId + 1)
},
+ decrementMediaId: ({ commit, state }) => {
+ commit(MUTATION_TYPES.UPDATE_MEDIA_ID, state.attachedMediaId - 1)
+ },
resetMediaId: ({ commit }) => {
commit(MUTATION_TYPES.UPDATE_MEDIA_ID, 0)
},
+ removeMedia: ({ commit, dispatch }, media: Attachment) => {
+ commit(MUTATION_TYPES.REMOVE_MEDIA, media)
+ commit(MUTATION_TYPES.REMOVE_MEDIA_DESCRIPTION, media.id)
+ dispatch('decrementMediaId')
+ },
updateHashtags: ({ commit, state }, tags: Array) => {
if (state.pinedHashtag && tags.length > 0) {
commit(MUTATION_TYPES.UPDATE_HASHTAGS, tags)
From 79bd5bef7f20238533b8a91030825039f1090525 Mon Sep 17 00:00:00 2001
From: AkiraFukushima
Date: Tue, 14 May 2019 23:33:28 +0900
Subject: [PATCH 2/2] refactor: Catch exception and show message when post
toots
---
.../TimelineSpace/Modals/NewToot.vue | 33 ++++++++++++++-----
.../{validations/index.js => validations.js} | 6 ++++
.../store/TimelineSpace/Modals/NewToot.ts | 21 +++++++-----
3 files changed, 44 insertions(+), 16 deletions(-)
rename src/renderer/errors/{validations/index.js => validations.js} (57%)
diff --git a/src/renderer/components/TimelineSpace/Modals/NewToot.vue b/src/renderer/components/TimelineSpace/Modals/NewToot.vue
index c5b21e84..8edc2b4c 100644
--- a/src/renderer/components/TimelineSpace/Modals/NewToot.vue
+++ b/src/renderer/components/TimelineSpace/Modals/NewToot.vue
@@ -120,6 +120,7 @@ import { mapState, mapGetters } from 'vuex'
import { clipboard } from 'electron'
import Visibility from '~/src/constants/visibility'
import Status from './NewToot/Status'
+import { NewTootTootLength, NewTootAttachLength, NewTootModalOpen, NewTootBlockSubmit } from '@/errors/validations'
export default {
name: 'new-toot',
@@ -216,15 +217,31 @@ export default {
spoiler: this.spoiler
}
- await this.$store.dispatch('TimelineSpace/Modals/NewToot/postToot', form).catch(err => {
+ try {
+ await this.$store.dispatch('TimelineSpace/Modals/NewToot/postToot', form)
+ this.$store.dispatch('TimelineSpace/Modals/NewToot/updateHashtags', status.tags)
+ this.close()
+ } catch (err) {
console.error(err)
- this.$message({
- message: this.$t('message.toot_error'),
- type: 'error'
- })
- })
- this.$store.dispatch('TimelineSpace/Modals/NewToot/updateHashtags', status.tags)
- this.close()
+ if (err instanceof NewTootTootLength) {
+ this.$message({
+ message: this.$t('validation.new_toot.toot_length', { min: 1, max: this.tootMax }),
+ type: 'error'
+ })
+ } else if (err instanceof NewTootAttachLength) {
+ this.$message({
+ message: this.$t('validation.new_toot.attach_length', { max: 4 }),
+ type: 'error'
+ })
+ } else if (err instanceof NewTootModalOpen || err instanceof NewTootBlockSubmit) {
+ // Nothing
+ } else {
+ this.$message({
+ message: this.$t('message.toot_error'),
+ type: 'error'
+ })
+ }
+ }
},
selectImage() {
this.$refs.image.click()
diff --git a/src/renderer/errors/validations/index.js b/src/renderer/errors/validations.js
similarity index 57%
rename from src/renderer/errors/validations/index.js
rename to src/renderer/errors/validations.js
index c45d8014..91f22f76 100644
--- a/src/renderer/errors/validations/index.js
+++ b/src/renderer/errors/validations.js
@@ -1,7 +1,13 @@
export class NewTootModalOpen extends Error {}
+export class NewTootBlockSubmit extends Error {}
+
export class NewTootTootLength extends Error {}
export class NewTootAttachLength extends Error {}
export class NewTootMediaDescription extends Error {}
+
+export class NewTootUnknownType extends Error {}
+
+export class AuthenticationError extends Error {}
diff --git a/src/renderer/store/TimelineSpace/Modals/NewToot.ts b/src/renderer/store/TimelineSpace/Modals/NewToot.ts
index a3c6a495..9cc024ff 100644
--- a/src/renderer/store/TimelineSpace/Modals/NewToot.ts
+++ b/src/renderer/store/TimelineSpace/Modals/NewToot.ts
@@ -5,7 +5,15 @@ import TootStatus, { StatusState } from './NewToot/Status'
import { Module, MutationTree, ActionTree, GetterTree } from 'vuex'
import { RootState } from '@/store'
import AxiosLoading from '@/utils/axiosLoading'
-import { NewTootModalOpen, NewTootTootLength, NewTootAttachLength, NewTootMediaDescription } from '@/errors/validations'
+import {
+ NewTootModalOpen,
+ NewTootBlockSubmit,
+ NewTootTootLength,
+ NewTootAttachLength,
+ NewTootMediaDescription,
+ NewTootUnknownType,
+ AuthenticationError
+} from '@/errors/validations'
type MediaDescription = {
id: number
@@ -157,7 +165,7 @@ const actions: ActionTree = {
throw err
})
},
- postToot: async ({ state, commit, rootState, dispatch }, { status, spoiler }) => {
+ postToot: async ({ state, commit, rootState, dispatch }, { status, spoiler }): Promise => {
if (!state.modalOpen) {
throw new NewTootModalOpen()
}
@@ -190,9 +198,8 @@ const actions: ActionTree = {
throw new AuthenticationError()
}
if (state.blockSubmit) {
- return
+ throw new NewTootBlockSubmit()
}
- commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, true)
if (state.attachedMedias.length > 0) {
if (state.attachedMedias.length > 4) {
@@ -209,6 +216,7 @@ const actions: ActionTree = {
})
}
+ 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)
@@ -268,7 +276,7 @@ const actions: ActionTree = {
.post('/media', formData)
.then(res => {
commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, false)
- if (res.data.type === 'unknown') throw new UnknownTypeError()
+ if (res.data.type === 'unknown') throw new NewTootUnknownType()
commit(MUTATION_TYPES.APPEND_ATTACHED_MEDIAS, res.data)
return res.data
})
@@ -329,6 +337,3 @@ const NewToot: Module = {
}
export default NewToot
-
-class AuthenticationError {}
-class UnknownTypeError {}