Add timed-mute functionality

This commit is contained in:
Tusooa Zhu 2022-04-30 11:08:19 -04:00 committed by tusooa
parent 95c15fca22
commit 228a9afdf5
No known key found for this signature in database
GPG Key ID: 7B467EDE43A08224
7 changed files with 72 additions and 18 deletions

View File

@ -94,19 +94,10 @@ export default {
}, },
convertExpiryToUnit (unit, amount) { convertExpiryToUnit (unit, amount) {
// Note: we want seconds and not milliseconds // Note: we want seconds and not milliseconds
switch (unit) { return DateUtils.secondsToUnit(unit, amount)
case 'minutes': return (1000 * amount) / DateUtils.MINUTE
case 'hours': return (1000 * amount) / DateUtils.HOUR
case 'days': return (1000 * amount) / DateUtils.DAY
}
}, },
convertExpiryFromUnit (unit, amount) { convertExpiryFromUnit (unit, amount) {
// Note: we want seconds and not milliseconds return DateUtils.unitToSeconds(unit, amount)
switch (unit) {
case 'minutes': return 0.001 * amount * DateUtils.MINUTE
case 'hours': return 0.001 * amount * DateUtils.HOUR
case 'days': return 0.001 * amount * DateUtils.DAY
}
}, },
expiryAmountChange () { expiryAmountChange () {
this.expiryAmount = this.expiryAmount =

View File

@ -1,3 +1,4 @@
import { unitToSeconds } from 'src/services/date_utils/date_utils.js'
import UserAvatar from '../user_avatar/user_avatar.vue' import UserAvatar from '../user_avatar/user_avatar.vue'
import RemoteFollow from '../remote_follow/remote_follow.vue' import RemoteFollow from '../remote_follow/remote_follow.vue'
import ProgressButton from '../progress_button/progress_button.vue' import ProgressButton from '../progress_button/progress_button.vue'
@ -48,7 +49,9 @@ export default {
return { return {
followRequestInProgress: false, followRequestInProgress: false,
betterShadow: this.$store.state.interface.browserSupport.cssFilter, betterShadow: this.$store.state.interface.browserSupport.cssFilter,
showingConfirmMute: false showingConfirmMute: false,
muteExpiryAmount: 0,
muteExpiryUnit: 'minutes'
} }
}, },
created () { created () {
@ -142,6 +145,9 @@ export default {
shouldConfirmMute () { shouldConfirmMute () {
return this.mergedConfig.modalOnMute return this.mergedConfig.modalOnMute
}, },
muteExpiryUnits () {
return ['minutes', 'hours', 'days']
},
...mapGetters(['mergedConfig']) ...mapGetters(['mergedConfig'])
}, },
components: { components: {
@ -172,7 +178,10 @@ export default {
} }
}, },
doMuteUser () { doMuteUser () {
this.$store.dispatch('muteUser', this.user.id) this.$store.dispatch('muteUser', {
id: this.user.id,
expiresIn: this.shouldConfirmMute ? unitToSeconds(this.muteExpiryUnit, this.muteExpiryAmount) : 0
})
this.hideConfirmMute() this.hideConfirmMute()
}, },
unmuteUser () { unmuteUser () {

View File

@ -355,3 +355,8 @@
text-decoration: none; text-decoration: none;
} }
} }
.mute-expiry {
display: flex;
flex-direction: row;
}

View File

@ -325,7 +325,7 @@
> >
<i18n-t <i18n-t
keypath="user_card.mute_confirm" keypath="user_card.mute_confirm"
tag="span" tag="div"
> >
<template #user> <template #user>
<span <span
@ -333,6 +333,32 @@
/> />
</template> </template>
</i18n-t> </i18n-t>
<div
class="mute-expiry"
>
<label>
{{ $t('user_card.mute_duration_prompt') }}
</label>
<input
v-model="muteExpiryAmount"
type="number"
class="expiry-amount hide-number-spinner"
:min="0"
>
<Select
v-model="muteExpiryUnit"
unstyled="true"
class="expiry-unit"
>
<option
v-for="unit in muteExpiryUnits"
:key="unit"
:value="unit"
>
{{ $t(`time.${unit}_short`, ['']) }}
</option>
</Select>
</div>
</confirm-modal> </confirm-modal>
</teleport> </teleport>
</div> </div>

View File

@ -61,13 +61,16 @@ const editUserNote = (store, { id, comment }) => {
.then((relationship) => store.commit('updateUserRelationship', [relationship])) .then((relationship) => store.commit('updateUserRelationship', [relationship]))
} }
const muteUser = (store, id) => { const muteUser = (store, args) => {
const id = typeof args === 'object' ? args.id : args
const expiresIn = typeof args === 'object' ? args.expiresIn : 0
const predictedRelationship = store.state.relationships[id] || { id } const predictedRelationship = store.state.relationships[id] || { id }
predictedRelationship.muting = true predictedRelationship.muting = true
store.commit('updateUserRelationship', [predictedRelationship]) store.commit('updateUserRelationship', [predictedRelationship])
store.commit('addMuteId', id) store.commit('addMuteId', id)
return store.rootState.api.backendInteractor.muteUser({ id }) return store.rootState.api.backendInteractor.muteUser({ id, expiresIn })
.then((relationship) => { .then((relationship) => {
store.commit('updateUserRelationship', [relationship]) store.commit('updateUserRelationship', [relationship])
store.commit('addMuteId', id) store.commit('addMuteId', id)

View File

@ -1118,8 +1118,12 @@ const fetchMutes = ({ credentials }) => {
.then((users) => users.map(parseUser)) .then((users) => users.map(parseUser))
} }
const muteUser = ({ id, credentials }) => { const muteUser = ({ id, expiresIn, credentials }) => {
return promisedRequest({ url: MASTODON_MUTE_USER_URL(id), credentials, method: 'POST' }) const payload = {}
if (expiresIn) {
payload['expires_in'] = expiresIn
}
return promisedRequest({ url: MASTODON_MUTE_USER_URL(id), credentials, method: 'POST', payload })
} }
const unmuteUser = ({ id, credentials }) => { const unmuteUser = ({ id, credentials }) => {

View File

@ -41,3 +41,19 @@ export const relativeTimeShort = (date, nowThreshold = 1) => {
r.key += '_short' r.key += '_short'
return r return r
} }
export const unitToSeconds = (unit, amount) => {
switch (unit) {
case 'minutes': return 0.001 * amount * MINUTE
case 'hours': return 0.001 * amount * HOUR
case 'days': return 0.001 * amount * DAY
}
}
export const secondsToUnit = (unit, amount) => {
switch (unit) {
case 'minutes': return (1000 * amount) / MINUTE
case 'hours': return (1000 * amount) / HOUR
case 'days': return (1000 * amount) / DAY
}
}