diff --git a/bin/svgs.js b/bin/svgs.js
index 88558728..0366bb27 100644
--- a/bin/svgs.js
+++ b/bin/svgs.js
@@ -24,7 +24,6 @@ module.exports = [
{id: 'fa-paperclip', src: 'node_modules/font-awesome-svg-png/white/svg/paperclip.svg', title: 'Paperclip'},
{id: 'fa-thumb-tack', src: 'node_modules/font-awesome-svg-png/white/svg/thumb-tack.svg', title: 'Thumbtack'},
{id: 'fa-bars', src: 'node_modules/font-awesome-svg-png/white/svg/bars.svg', title: 'List'},
- {id: 'fa-volume-off', src: 'node_modules/font-awesome-svg-png/white/svg/volume-off.svg', title: 'Volume off'},
{id: 'fa-ban', src: 'node_modules/font-awesome-svg-png/white/svg/ban.svg', title: 'Ban'},
{id: 'fa-camera', src: 'node_modules/font-awesome-svg-png/white/svg/camera.svg', title: 'Add media'},
{id: 'fa-smile', src: 'node_modules/font-awesome-svg-png/white/svg/smile-o.svg', title: 'Custom emoji'},
@@ -33,5 +32,7 @@ module.exports = [
{id: 'fa-trash', src: 'node_modules/font-awesome-svg-png/white/svg/trash-o.svg', title: 'Delete'},
{id: 'fa-hourglass', src: 'node_modules/font-awesome-svg-png/white/svg/hourglass.svg', title: 'Follow requested'},
{id: 'fa-pencil', src: 'node_modules/font-awesome-svg-png/white/svg/pencil.svg', title: 'Compose'},
- {id: 'fa-times', src: 'node_modules/font-awesome-svg-png/white/svg/times.svg', title: 'Close'}
+ {id: 'fa-times', src: 'node_modules/font-awesome-svg-png/white/svg/times.svg', title: 'Close'},
+ {id: 'fa-volume-off', src: 'node_modules/font-awesome-svg-png/white/svg/volume-off.svg', title: 'Mute'},
+ {id: 'fa-volume-up', src: 'node_modules/font-awesome-svg-png/white/svg/volume-up.svg', title: 'Unmute'}
]
diff --git a/routes/_actions/mute.js b/routes/_actions/mute.js
new file mode 100644
index 00000000..a0bc6e47
--- /dev/null
+++ b/routes/_actions/mute.js
@@ -0,0 +1,27 @@
+import { store } from '../_store/store'
+import { muteAccount, unmuteAccount } from '../_api/mute'
+import { toast } from '../_utils/toast'
+import { updateProfileAndRelationship } from './accounts'
+
+export async function setAccountMuted (accountId, mute, toastOnSuccess) {
+ let instanceName = store.get('currentInstance')
+ let accessToken = store.get('accessToken')
+ try {
+ if (mute) {
+ await muteAccount(instanceName, accessToken, accountId)
+ } else {
+ await unmuteAccount(instanceName, accessToken, accountId)
+ }
+ await updateProfileAndRelationship(accountId)
+ if (toastOnSuccess) {
+ if (mute) {
+ toast.say('Muted account')
+ } else {
+ toast.say('Unmuted account')
+ }
+ }
+ } catch (e) {
+ console.error(e)
+ toast.say(`Unable to ${mute ? 'mute' : 'unmute'} account: ` + (e.message || ''))
+ }
+}
diff --git a/routes/_api/mute.js b/routes/_api/mute.js
new file mode 100644
index 00000000..9acb76a7
--- /dev/null
+++ b/routes/_api/mute.js
@@ -0,0 +1,12 @@
+import { auth, basename } from './utils'
+import { postWithTimeout } from '../_utils/ajax'
+
+export async function muteAccount (instanceName, accessToken, accountId) {
+ let url = `${basename(instanceName)}/api/v1/accounts/${accountId}/mute`
+ return postWithTimeout(url, null, auth(accessToken))
+}
+
+export async function unmuteAccount (instanceName, accessToken, accountId) {
+ let url = `${basename(instanceName)}/api/v1/accounts/${accountId}/unmute`
+ return postWithTimeout(url, null, auth(accessToken))
+}
diff --git a/routes/_components/dialog/components/AccountProfileOptionsDialog.html b/routes/_components/dialog/components/AccountProfileOptionsDialog.html
index ee10527a..9a187b28 100644
--- a/routes/_components/dialog/components/AccountProfileOptionsDialog.html
+++ b/routes/_components/dialog/components/AccountProfileOptionsDialog.html
@@ -16,6 +16,8 @@ import { show } from '../helpers/showDialog'
import { close } from '../helpers/closeDialog'
import { oncreate } from '../helpers/onCreateDialog'
import { setAccountBlocked } from '../../../_actions/block'
+import { setAccountMuted } from '../../../_actions/mute'
+import { setAccountFollowed } from '../../../_actions/follow'
export default {
oncreate,
@@ -24,21 +26,62 @@ export default {
id: createDialogId()
}),
computed: {
- blocking: (relationship) => relationship && relationship.blocking,
- items: (account, blocking) => (
- [
- {
+ // begin account data copypasta
+ verifyCredentialsId: (verifyCredentials) => verifyCredentials.id,
+ following: (relationship) => relationship && relationship.following,
+ followRequested: (relationship) => relationship && relationship.requested,
+ accountId: (account) => account && account.id,
+ acct: (account) => account.acct,
+ muting: (relationship) => relationship.muting,
+ blocking: (relationship) => relationship.blocking,
+ followLabel: (following, followRequested, account, acct) => {
+ if (typeof following === 'undefined' || !account) {
+ return ''
+ }
+ return (following || followRequested)
+ ? `Unfollow @${acct}`
+ : `Follow @${acct}`
+ },
+ followIcon: (following, followRequested) => {
+ return following ? '#fa-user-times' : followRequested ? '#fa-hourglass' : '#fa-user-plus'
+ },
+ blockLabel: (blocking, acct) => {
+ return blocking ? `Unblock @${acct}` : `Block @${acct}`
+ },
+ blockIcon: (blocking) => blocking ? '#fa-unlock' : '#fa-ban',
+ muteLabel: (muting, acct) => {
+ return muting ? `Unmute @${acct}` : `Mute @${acct}`
+ },
+ muteIcon: (muting) => muting ? '#fa-volume-up' : '#fa-volume-off',
+ // end account data copypasta
+ items: (blockLabel, blocking, blockIcon, muteLabel, muteIcon,
+ followLabel, followIcon, following, followRequested,
+ accountId, verifyCredentialsId, acct) => {
+ let isUser = accountId === verifyCredentialsId
+ return [
+ !isUser && {
key: 'mention',
- label: `Mention @${account.acct}`,
+ label: `Mention @${acct}`,
icon: '#fa-comments'
},
- {
+ !isUser && !blocking && {
+ key: 'follow',
+ label: followLabel,
+ icon: followIcon
+ },
+ !isUser && {
key: 'block',
- label: blocking ? `Unblock @${account.acct}` : `Block @${account.acct}`,
- icon: blocking ? '#fa-unlock' : '#fa-ban'
+ label: blockLabel,
+ icon: blockIcon
+ },
+ !isUser && !blocking && {
+ key: 'mute',
+ label: muteLabel,
+ icon: muteIcon
}
- ]
- )
+
+ ].filter(Boolean)
+ }
},
methods: {
show,
@@ -47,25 +90,41 @@ export default {
switch (item.key) {
case 'mention':
return this.onMentionClicked()
+ case 'follow':
+ return this.onFollowClicked()
case 'block':
return this.onBlockClicked()
+ case 'mute':
+ return this.onMuteClicked()
}
},
async onMentionClicked() {
- let account = this.get('account')
+ let acct = this.get('acct')
this.store.setComposeData('dialog', {
- text: `@${account.acct} `
+ text: `@${acct} `
})
let dialogs = await importDialogs()
dialogs.showComposeDialog()
this.close()
},
+ async onFollowClicked() {
+ let accountId = this.get('accountId')
+ let following = this.get('following')
+ this.close()
+ await setAccountFollowed(accountId, !following, true)
+ },
async onBlockClicked() {
let account = this.get('account')
let blocking = this.get('blocking')
let accountId = account.id
this.close()
await setAccountBlocked(accountId, !blocking, true)
+ },
+ async onMuteClicked() {
+ let accountId = this.get('accountId')
+ let muting = this.get('muting')
+ this.close()
+ await setAccountMuted(accountId, !muting, true)
}
},
components: {
diff --git a/routes/_components/dialog/components/StatusOptionsDialog.html b/routes/_components/dialog/components/StatusOptionsDialog.html
index c85fb5a2..d5445906 100644
--- a/routes/_components/dialog/components/StatusOptionsDialog.html
+++ b/routes/_components/dialog/components/StatusOptionsDialog.html
@@ -16,6 +16,7 @@ import { show } from '../helpers/showDialog'
import { close } from '../helpers/closeDialog'
import { oncreate } from '../helpers/onCreateDialog'
import { setAccountBlocked } from '../../../_actions/block'
+import { setAccountMuted } from '../../../_actions/mute'
export default {
oncreate,
@@ -23,44 +24,62 @@ export default {
relationship: ($currentAccountRelationship) => $currentAccountRelationship,
account: ($currentAccountProfile) => $currentAccountProfile,
verifyCredentials: ($currentVerifyCredentials) => $currentVerifyCredentials,
+ // begin account data copypasta
verifyCredentialsId: (verifyCredentials) => verifyCredentials.id,
following: (relationship) => relationship && relationship.following,
followRequested: (relationship) => relationship && relationship.requested,
accountId: (account) => account && account.id,
+ acct: (account) => account.acct,
+ muting: (relationship) => relationship.muting,
blocking: (relationship) => relationship.blocking,
- followLabel: (following, followRequested, account) => {
+ followLabel: (following, followRequested, account, acct) => {
if (typeof following === 'undefined' || !account) {
return ''
}
return (following || followRequested)
- ? `Unfollow @${account.acct}`
- : `Follow @${account.acct}`
+ ? `Unfollow @${acct}`
+ : `Follow @${acct}`
},
- blockLabel: (blocking, account) => {
- return blocking ? `Unblock @${account.acct}` : `Block @${account.acct}`
+ followIcon: (following, followRequested) => {
+ return following ? '#fa-user-times' : followRequested ? '#fa-hourglass' : '#fa-user-plus'
},
- items: (blockLabel, blocking, followLabel, following, followRequested, accountId, verifyCredentialsId) => (
- [
- accountId === verifyCredentialsId &&
- {
+ blockLabel: (blocking, acct) => {
+ return blocking ? `Unblock @${acct}` : `Block @${acct}`
+ },
+ blockIcon: (blocking) => blocking ? '#fa-unlock' : '#fa-ban',
+ muteLabel: (muting, acct) => {
+ return muting ? `Unmute @${acct}` : `Mute @${acct}`
+ },
+ muteIcon: (muting) => muting ? '#fa-volume-up' : '#fa-volume-off',
+ // end account data copypasta
+ items: (blockLabel, blocking, blockIcon, muteLabel, muteIcon,
+ followLabel, followIcon, following, followRequested,
+ accountId, verifyCredentialsId) => {
+ let isUser = accountId === verifyCredentialsId
+ return [
+ isUser && {
key: 'delete',
label: 'Delete',
icon: '#fa-trash'
},
- accountId !== verifyCredentialsId && !blocking &&
- {
+ !isUser && !blocking && {
key: 'follow',
label: followLabel,
- icon: following ? '#fa-user-times' : followRequested ? '#fa-hourglass' : '#fa-user-plus'
+ icon: followIcon
},
- accountId !== verifyCredentialsId &&
- {
+ !isUser && {
key: 'block',
label: blockLabel,
- icon: blocking ? '#fa-unlock' : '#fa-ban'
+ icon: blockIcon
+ },
+ !isUser && !blocking && {
+ key: 'mute',
+ label: muteLabel,
+ icon: muteIcon
}
+
].filter(Boolean)
- )
+ }
},
components: {
ModalDialog,
@@ -78,6 +97,8 @@ export default {
return this.onFollowClicked()
case 'block':
return this.onBlockClicked()
+ case 'mute':
+ return this.onMuteClicked()
}
},
async onDeleteClicked() {
@@ -96,6 +117,12 @@ export default {
let blocking = this.get('blocking')
this.close()
await setAccountBlocked(accountId, !blocking, true)
+ },
+ async onMuteClicked() {
+ let accountId = this.get('accountId')
+ let muting = this.get('muting')
+ this.close()
+ await setAccountMuted(accountId, !muting, true)
}
}
}
diff --git a/routes/_components/dialog/creators/showAccountProfileOptionsDialog.js b/routes/_components/dialog/creators/showAccountProfileOptionsDialog.js
index 51e38e46..3dd964fc 100644
--- a/routes/_components/dialog/creators/showAccountProfileOptionsDialog.js
+++ b/routes/_components/dialog/creators/showAccountProfileOptionsDialog.js
@@ -2,7 +2,7 @@ import AccountProfileOptionsDialog from '../components/AccountProfileOptionsDial
import { createDialogElement } from '../helpers/createDialogElement'
import { createDialogId } from '../helpers/createDialogId'
-export function showAccountProfileOptionsDialog (account, relationship) {
+export function showAccountProfileOptionsDialog (account, relationship, verifyCredentials) {
let dialog = new AccountProfileOptionsDialog({
target: createDialogElement(),
data: {
@@ -10,7 +10,8 @@ export function showAccountProfileOptionsDialog (account, relationship) {
label: 'Profile options dialog',
title: '',
account: account,
- relationship: relationship
+ relationship: relationship,
+ verifyCredentials: verifyCredentials
}
})
dialog.show()
diff --git a/routes/_components/profile/AccountProfile.html b/routes/_components/profile/AccountProfile.html
index 629ad274..20260aad 100644
--- a/routes/_components/profile/AccountProfile.html
+++ b/routes/_components/profile/AccountProfile.html
@@ -5,7 +5,7 @@
-
+
diff --git a/routes/_components/profile/AccountProfileDetails.html b/routes/_components/profile/AccountProfileDetails.html
index 86f0f75d..7f7a9e3b 100644
--- a/routes/_components/profile/AccountProfileDetails.html
+++ b/routes/_components/profile/AccountProfileDetails.html
@@ -120,8 +120,9 @@
async onMoreOptionsClick() {
let account = this.get('account')
let relationship = this.get('relationship')
+ let verifyCredentials = this.get('verifyCredentials')
let dialogs = await importDialogs()
- dialogs.showAccountProfileOptionsDialog(account, relationship)
+ dialogs.showAccountProfileOptionsDialog(account, relationship, verifyCredentials)
}
},
components: {
diff --git a/templates/2xx.html b/templates/2xx.html
index 0d6d3b13..539857a3 100644
--- a/templates/2xx.html
+++ b/templates/2xx.html
@@ -106,7 +106,6 @@ if (!localStorage.store_currentInstance) {
Paperclip
Thumbtack
List
-Volume off
Ban
Add media
Custom emoji
@@ -116,6 +115,8 @@ if (!localStorage.store_currentInstance) {
Follow requested
Compose
Close
+Mute
+Unmute