From e449b0c8974e8e813eb28f489e17e2cee1f12011 Mon Sep 17 00:00:00 2001 From: tea Date: Fri, 8 Dec 2023 01:03:02 +0100 Subject: [PATCH] add support for repeat with visibility This requires backend changes to work properly. Currently Akkoma maps: * public and unlisted (and local?) to public * private to private --- .../retweet_button/retweet_button.js | 14 +- .../retweet_button/retweet_button.vue | 172 ++++++++++++------ src/modules/statuses.js | 2 +- src/services/api/api.service.js | 26 ++- 4 files changed, 151 insertions(+), 63 deletions(-) diff --git a/src/components/retweet_button/retweet_button.js b/src/components/retweet_button/retweet_button.js index 15542a11..f57bd2ac 100644 --- a/src/components/retweet_button/retweet_button.js +++ b/src/components/retweet_button/retweet_button.js @@ -1,12 +1,14 @@ +import Popover from '../popover/popover.vue' import ConfirmModal from '../confirm_modal/confirm_modal.vue' import { library } from '@fortawesome/fontawesome-svg-core' -import { faRetweet } from '@fortawesome/free-solid-svg-icons' +import { faRetweet, faTrash } from '@fortawesome/free-solid-svg-icons' -library.add(faRetweet) +library.add(faRetweet, faTrash) const RetweetButton = { props: ['status', 'loggedIn', 'visibility'], components: { + Popover, ConfirmModal }, data () { @@ -16,16 +18,16 @@ const RetweetButton = { } }, methods: { - retweet () { + retweet (visibility) { if (!this.status.repeated && this.shouldConfirmRepeat) { this.showConfirmDialog() } else { - this.doRetweet() + this.doRetweet(visibility) } }, - doRetweet () { + doRetweet (visibility) { if (!this.status.repeated) { - this.$store.dispatch('retweet', { id: this.status.id }) + this.$store.dispatch('retweet', { id: this.status.id, visibility: visibility }) } else { this.$store.dispatch('unretweet', { id: this.status.id }) } diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue index 6dac2637..440a88b1 100644 --- a/src/components/retweet_button/retweet_button.vue +++ b/src/components/retweet_button/retweet_button.vue @@ -1,57 +1,124 @@ @@ -72,7 +139,7 @@ user-select: none; } - .interactive { + .popover-trigger { .svg-inline--fa { @media (prefers-reduced-motion: reduce) { animation: unset; @@ -80,6 +147,7 @@ animation-duration: 0.6s; } + /* TODO: don't turn green on hover because it keeps being focused on mobile when the popover is open. Instead make it while(?) like in extra_buttons and only green once it's been repeated. */ &:hover .svg-inline--fa, &.-repeated .svg-inline--fa { color: $fallback--cGreen; diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 200718e3..c6cf20a5 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -666,7 +666,7 @@ const statuses = { retweet ({ rootState, commit }, status) { // Optimistic retweeting... commit('setRetweeted', { status, value: true }) - rootState.api.backendInteractor.retweet({ id: status.id }) + rootState.api.backendInteractor.retweet({ id: status.id, visibility: status.visibility }) .then(status => commit('setRetweetedConfirm', { status: status.retweeted_status, user: rootState.users.currentUser })) }, unretweet ({ rootState, commit }, status) { diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index de21ef3b..b5a6b2c9 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -125,21 +125,31 @@ let fetch = (url, options) => { } const promisedRequest = ({ method, url, params, payload, credentials, headers = {} }) => { + const payloadIsFormData = payload instanceof FormData + const options = { method, headers: { 'Accept': 'application/json', - 'Content-Type': 'application/json', ...headers } } + if (!payloadIsFormData) { + // only set content type if payload is not form data + // if it is unset the content type will be automatically set to multipart/form-data + options.headers['Content-Type'] = 'application/json' + } if (params) { url += '?' + Object.entries(params) .map(([key, value]) => encodeURIComponent(key) + '=' + encodeURIComponent(value)) .join('&') } if (payload) { - options.body = JSON.stringify(payload) + if (payloadIsFormData) { + options.body = payload + } else { + options.body = JSON.stringify(payload) + } } if (credentials) { options.headers = { @@ -822,8 +832,16 @@ const unfavorite = ({ id, credentials }) => { .then((data) => parseStatus(data)) } -const retweet = ({ id, credentials }) => { - return promisedRequest({ url: MASTODON_RETWEET_URL(id), method: 'POST', credentials }) +const retweet = ({ id, credentials, visibility }) => { + const form = new FormData() + if (visibility) form.append('visibility', visibility) + + return promisedRequest({ + url: MASTODON_RETWEET_URL(id), + payload: form, + method: 'POST', + credentials + }) .then((data) => parseStatus(data)) }