diff --git a/src/App.scss b/src/App.scss
index 704d51cea..24afac8ab 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -675,11 +675,6 @@ option {
}
}
-.btn-block {
- display: block;
- width: 100%;
-}
-
.btn-group {
position: relative;
display: inline-flex;
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 1b133a089..28ff1e530 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -247,6 +247,7 @@ const getNodeInfo = async ({ store }) => {
const data = await res.json()
const metadata = data.metadata
const features = metadata.features
+ console.log(features)
store.dispatch('setInstanceOption', { name: 'name', value: metadata.nodeName })
store.dispatch('setInstanceOption', { name: 'registrationOpen', value: data.openRegistrations })
store.dispatch('setInstanceOption', { name: 'mediaProxyAvailable', value: features.includes('media_proxy') })
@@ -262,6 +263,7 @@ const getNodeInfo = async ({ store }) => {
store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled })
store.dispatch('setInstanceOption', { name: 'quotingAvailable', value: features.includes('quote_posting') })
store.dispatch('setInstanceOption', { name: 'groupActorAvailable', value: features.includes('pleroma:group_actors') })
+ store.dispatch('setInstanceOption', { name: 'blockExpiration', value: features.includes('pleroma:block_expiration') })
const uploadLimits = metadata.uploadLimits
store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadLimits.general) })
diff --git a/src/components/account_actions/account_actions.js b/src/components/account_actions/account_actions.js
index 9a63f57eb..f8ad0e11b 100644
--- a/src/components/account_actions/account_actions.js
+++ b/src/components/account_actions/account_actions.js
@@ -3,6 +3,7 @@ import ProgressButton from '../progress_button/progress_button.vue'
import Popover from '../popover/popover.vue'
import UserListMenu from 'src/components/user_list_menu/user_list_menu.vue'
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
+import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faEllipsisV
@@ -27,15 +28,10 @@ const AccountActions = {
ProgressButton,
Popover,
UserListMenu,
- ConfirmModal
+ ConfirmModal,
+ UserTimedFilterModal
},
methods: {
- showConfirmBlock () {
- this.showingConfirmBlock = true
- },
- hideConfirmBlock () {
- this.showingConfirmBlock = false
- },
showConfirmRemoveUserFromFollowers () {
this.showingConfirmRemoveFollower = true
},
@@ -49,10 +45,14 @@ const AccountActions = {
this.$store.dispatch('hideReblogs', this.user.id)
},
blockUser () {
- if (!this.shouldConfirmBlock) {
- this.doBlockUser()
+ if (this.$refs.timedBlockDialog) {
+ this.$refs.timedBlockDialog.optionallyPrompt()
} else {
- this.showConfirmBlock()
+ if (!this.shouldConfirmBlock) {
+ this.doBlockUser()
+ } else {
+ this.showingConfirmBlock = true
+ }
}
},
doBlockUser () {
@@ -91,6 +91,7 @@ const AccountActions = {
return this.$store.getters.mergedConfig.modalOnRemoveUserFromFollowers
},
...mapState({
+ blockExpirationSupported: state => state.instance.blockExpiration,
pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable
})
}
diff --git a/src/components/account_actions/account_actions.vue b/src/components/account_actions/account_actions.vue
index fd4837ee4..f3cca45d0 100644
--- a/src/components/account_actions/account_actions.vue
+++ b/src/components/account_actions/account_actions.vue
@@ -96,7 +96,8 @@
+
diff --git a/src/components/confirm_modal/mute_confirm.js b/src/components/confirm_modal/mute_confirm.js
index 1bef9f620..a279dc716 100644
--- a/src/components/confirm_modal/mute_confirm.js
+++ b/src/components/confirm_modal/mute_confirm.js
@@ -1,4 +1,3 @@
-import { unitToSeconds } from 'src/services/date_utils/date_utils.js'
import { mapGetters } from 'vuex'
import ConfirmModal from './confirm_modal.vue'
@@ -8,21 +7,13 @@ export default {
props: ['type', 'user', 'status'],
emits: ['hide', 'show', 'muted'],
data: () => ({
- showing: false,
- muteExpiryAmount: 2,
- muteExpiryUnit: 'hours'
+ showing: false
}),
components: {
ConfirmModal,
Select
},
computed: {
- muteExpiryValue () {
- unitToSeconds(this.muteExpiryUnit, this.muteExpiryAmount)
- },
- muteExpiryUnits () {
- return ['minutes', 'hours', 'days']
- },
domain () {
return this.user.fqn.split('@')[1]
},
@@ -31,13 +22,8 @@ export default {
return 'status.mute_domain_confirm'
} else if (this.type === 'conversation') {
return 'status.mute_conversation_confirm'
- } else {
- return 'user_card.mute_confirm'
}
},
- userIsMuted () {
- return this.$store.getters.relationship(this.user.id).muting
- },
conversationIsMuted () {
return this.status.conversation_muted
},
@@ -49,12 +35,9 @@ export default {
case 'domain': {
return this.mergedConfig.modalOnMuteDomain
}
- case 'conversation': {
+ default: { // conversation
return this.mergedConfig.modalOnMuteConversation
}
- default: {
- return this.mergedConfig.modalOnMute
- }
}
},
...mapGetters(['mergedConfig'])
@@ -79,7 +62,7 @@ export default {
switch (this.type) {
case 'domain': {
if (!this.domainIsMuted) {
- this.$store.dispatch('muteDomain', { id: this.domain, expiresIn: this.muteExpiryValue })
+ this.$store.dispatch('muteDomain', { id: this.domain })
} else {
this.$store.dispatch('unmuteDomain', { id: this.domain })
}
@@ -87,20 +70,12 @@ export default {
}
case 'conversation': {
if (!this.conversationIsMuted) {
- this.$store.dispatch('muteConversation', { id: this.status.id, expiresIn: this.muteExpiryValue })
+ this.$store.dispatch('muteConversation', { id: this.status.id })
} else {
this.$store.dispatch('unmuteConversation', { id: this.status.id })
}
break
}
- default: {
- if (!this.userIsMuted) {
- this.$store.dispatch('muteUser', { id: this.user.id, expiresIn: this.muteExpiryValue })
- } else {
- this.$store.dispatch('unmuteUser', { id: this.user.id })
- }
- break
- }
}
this.$emit('muted')
this.hide()
diff --git a/src/components/confirm_modal/mute_confirm.vue b/src/components/confirm_modal/mute_confirm.vue
index bf7ab338f..7c754b006 100644
--- a/src/components/confirm_modal/mute_confirm.vue
+++ b/src/components/confirm_modal/mute_confirm.vue
@@ -18,36 +18,6 @@
-
-
-
-
- {{ ' ' }}
-
-
-
diff --git a/src/components/settings_modal/tabs/filtering_tab.js b/src/components/settings_modal/tabs/filtering_tab.js
index 5ff137062..f78f6815c 100644
--- a/src/components/settings_modal/tabs/filtering_tab.js
+++ b/src/components/settings_modal/tabs/filtering_tab.js
@@ -107,7 +107,7 @@ const FilteringTab = {
...mapActions(useServerSideStorageStore, ['setPreference', 'unsetPreference', 'pushServerSideStorage']),
getDatetimeLocal (timestamp) {
const date = new Date(timestamp)
- let fmt = new Intl.NumberFormat("en-US", {minimumIntegerDigits: 2})
+ const fmt = new Intl.NumberFormat("en-US", {minimumIntegerDigits: 2})
const datetime = [
date.getFullYear(),
'-',
diff --git a/src/components/status_action_buttons/action_button_container.js b/src/components/status_action_buttons/action_button_container.js
index 313e3022f..a8f20800b 100644
--- a/src/components/status_action_buttons/action_button_container.js
+++ b/src/components/status_action_buttons/action_button_container.js
@@ -1,6 +1,7 @@
import ActionButton from './action_button.vue'
import Popover from 'src/components/popover/popover.vue'
import MuteConfirm from 'src/components/confirm_modal/mute_confirm.vue'
+import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
@@ -19,7 +20,8 @@ export default {
components: {
ActionButton,
Popover,
- MuteConfirm
+ MuteConfirm,
+ UserTimedFilterModal
},
props: ['button', 'status'],
emits: ['interacted'],
diff --git a/src/components/status_action_buttons/action_button_container.vue b/src/components/status_action_buttons/action_button_container.vue
index 931a40349..75f5010ee 100644
--- a/src/components/status_action_buttons/action_button_container.vue
+++ b/src/components/status_action_buttons/action_button_container.vue
@@ -94,11 +94,10 @@
:status="status"
:user="user"
/>
-
diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js
index be81b8ad5..addb49afb 100644
--- a/src/components/user_card/user_card.js
+++ b/src/components/user_card/user_card.js
@@ -8,7 +8,8 @@ import UserNote from '../user_note/user_note.vue'
import Select from '../select/select.vue'
import UserLink from '../user_link/user_link.vue'
import RichContent from 'src/components/rich_content/rich_content.jsx'
-import MuteConfirm from '../confirm_modal/mute_confirm.vue'
+import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue'
+
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { mapGetters } from 'vuex'
import { usePostStatusStore } from 'src/stores/post_status'
@@ -48,6 +49,19 @@ export default {
'onClose',
'hasNoteEditor'
],
+ components: {
+ UserAvatar,
+ RemoteFollow,
+ ModerationTools,
+ AccountActions,
+ ProgressButton,
+ FollowButton,
+ Select,
+ RichContent,
+ UserLink,
+ UserNote,
+ UserTimedFilterModal
+ },
data () {
return {
followRequestInProgress: false,
@@ -63,6 +77,7 @@ export default {
return this.$store.getters.findUser(this.userId)
},
relationship () {
+ console.log(this.$store.getters.relationship(this.userId))
return this.$store.getters.relationship(this.userId)
},
classes () {
@@ -144,22 +159,9 @@ export default {
},
...mapGetters(['mergedConfig'])
},
- components: {
- UserAvatar,
- RemoteFollow,
- ModerationTools,
- AccountActions,
- ProgressButton,
- FollowButton,
- Select,
- RichContent,
- UserLink,
- UserNote,
- MuteConfirm
- },
methods: {
muteUser () {
- this.$refs.confirmation.optionallyPrompt()
+ this.$refs.timedMuteDialog.optionallyPrompt()
},
unmuteUser () {
this.$store.dispatch('unmuteUser', this.user.id)
diff --git a/src/components/user_card/user_card.scss b/src/components/user_card/user_card.scss
index d263be1c0..418bef08b 100644
--- a/src/components/user_card/user_card.scss
+++ b/src/components/user_card/user_card.scss
@@ -8,6 +8,11 @@
--_still-image-label-visibility: hidden;
}
+ .btn-mute, .btn-mention {
+ display: block;
+ width: 100%;
+ }
+
.panel-heading {
padding: 0.5em 0;
text-align: center;
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index 36935424d..d05f9a6e4 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -232,7 +232,7 @@
-
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 019beba1c..64d11b07c 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -1392,6 +1392,10 @@
"mute_confirm": "Do you really want to mute {user}?",
"mute_confirm_accept_button": "Mute",
"mute_confirm_cancel_button": "Do not mute",
+ "expire_at": "Expire at",
+ "dont_ask_again": "Do not ask again",
+ "mute_block_temporarily": "Temporarily",
+ "mute_block_forever": "Forever",
"mute_duration_prompt": "Mute this user for (0 for indefinite time):",
"per_day": "per day",
"remote_follow": "Remote follow",
diff --git a/src/modules/default_config_state.js b/src/modules/default_config_state.js
index eb12d2df1..8ccf79e70 100644
--- a/src/modules/default_config_state.js
+++ b/src/modules/default_config_state.js
@@ -97,8 +97,11 @@ export const defaultState = {
alwaysShowSubjectInput: undefined, // instance default
postContentType: undefined, // instance default
minimalScopesMode: undefined, // instance default
+
// This hides statuses filtered via a word filter
hideFilteredStatuses: undefined, // instance default
+
+ // Confirmations
modalOnRepeat: undefined, // instance default
modalOnUnfollow: undefined, // instance default
modalOnBlock: undefined, // instance default
@@ -110,6 +113,11 @@ export const defaultState = {
modalOnApproveFollow: undefined, // instance default
modalOnDenyFollow: undefined, // instance default
modalOnRemoveUserFromFollowers: undefined, // instance default
+
+ // Expiry confirmations/default actions
+ onMuteDefaultAction: 'ask',
+ onBlockDefaultAction: 'ask',
+
modalMobileCenter: undefined,
playVideosInModal: false,
useOneClickNsfw: false,
diff --git a/src/modules/instance.js b/src/modules/instance.js
index 83671a881..cee039ccc 100644
--- a/src/modules/instance.js
+++ b/src/modules/instance.js
@@ -162,6 +162,7 @@ const defaultState = {
suggestionsWeb: '',
quotingAvailable: false,
groupActorAvailable: false,
+ blockExpiration: false,
// Html stuff
instanceSpecificPanelContent: '',
diff --git a/src/modules/users.js b/src/modules/users.js
index 01936c716..8779376b0 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -43,11 +43,20 @@ const getNotificationPermission = () => {
return Promise.resolve(Notification.permission)
}
-const blockUser = (store, id) => {
- return store.rootState.api.backendInteractor.blockUser({ id })
+const blockUser = (store, args) => {
+ const id = args.id
+ const expiresIn = typeof args === 'object' ? args.expiresIn : 0
+
+ const predictedRelationship = store.state.relationships[id] || { id }
+ store.commit('updateUserRelationship', [predictedRelationship])
+ store.commit('addBlockId', id)
+
+ return store.rootState.api.backendInteractor.blockUser({ id, expiresIn })
.then((relationship) => {
+ console.log(relationship)
store.commit('updateUserRelationship', [relationship])
store.commit('addBlockId', id)
+
store.commit('removeStatus', { timeline: 'friends', userId: id })
store.commit('removeStatus', { timeline: 'public', userId: id })
store.commit('removeStatus', { timeline: 'publicAndExternal', userId: id })
@@ -74,7 +83,6 @@ const muteUser = (store, args) => {
const expiresIn = typeof args === 'object' ? args.expiresIn : 0
const predictedRelationship = store.state.relationships[id] || { id }
- predictedRelationship.muting = true
store.commit('updateUserRelationship', [predictedRelationship])
store.commit('addMuteId', id)
@@ -360,20 +368,20 @@ const users = {
return blocks
})
},
- blockUser (store, id) {
- return blockUser(store, id)
+ blockUser (store, data) {
+ return blockUser(store, data)
},
- unblockUser (store, id) {
- return unblockUser(store, id)
+ unblockUser (store, data) {
+ return unblockUser(store, data)
},
removeUserFromFollowers (store, id) {
return removeUserFromFollowers(store, id)
},
- blockUsers (store, ids = []) {
- return Promise.all(ids.map(id => blockUser(store, id)))
+ blockUsers (store, data = []) {
+ return Promise.all(data.map(d => blockUser(store, d)))
},
- unblockUsers (store, ids = []) {
- return Promise.all(ids.map(id => unblockUser(store, id)))
+ unblockUsers (store, data = []) {
+ return Promise.all(data.map(d => unblockUser(store, d)))
},
editUserNote (store, args) {
return editUserNote(store, args)
@@ -396,8 +404,8 @@ const users = {
return mutes
})
},
- muteUser (store, id) {
- return muteUser(store, id)
+ muteUser (store, data) {
+ return muteUser(store, data)
},
unmuteUser (store, id) {
return unmuteUser(store, id)
@@ -408,11 +416,11 @@ const users = {
showReblogs (store, id) {
return showReblogs(store, id)
},
- muteUsers (store, ids = []) {
- return Promise.all(ids.map(id => muteUser(store, id)))
+ muteUsers (store, data = []) {
+ return Promise.all(data.map(d => muteUser(store, d)))
},
unmuteUsers (store, ids = []) {
- return Promise.all(ids.map(id => unmuteUser(store, id)))
+ return Promise.all(ids.map(d => unmuteUser(store, d)))
},
fetchDomainMutes (store) {
return store.rootState.api.backendInteractor.fetchDomainMutes()
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index 117c621d9..9328c8edc 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -319,11 +319,19 @@ const unmuteConversation = ({ id, credentials }) => {
.then((data) => parseStatus(data))
}
-const blockUser = ({ id, credentials }) => {
- return fetch(MASTODON_BLOCK_USER_URL(id), {
- headers: authHeaders(credentials),
- method: 'POST'
- }).then((data) => data.json())
+const blockUser = ({ id, expiresIn, credentials }) => {
+ const payload = {}
+ if (expiresIn) {
+ payload.expires_in = expiresIn
+ }
+
+ console.log(payload)
+ return promisedRequest({
+ url: MASTODON_BLOCK_USER_URL(id),
+ credentials,
+ method: 'POST',
+ payload
+ })
}
const unblockUser = ({ id, credentials }) => {
@@ -1172,7 +1180,13 @@ const muteUser = ({ id, expiresIn, credentials }) => {
if (expiresIn) {
payload.expires_in = expiresIn
}
- return promisedRequest({ url: MASTODON_MUTE_USER_URL(id), credentials, method: 'POST', payload })
+
+ return promisedRequest({
+ url: MASTODON_MUTE_USER_URL(id),
+ credentials,
+ method: 'POST',
+ payload
+ })
}
const unmuteUser = ({ id, credentials }) => {