more options button to follow/unfollow
This commit is contained in:
parent
92176df3ab
commit
c13771c3a0
|
@ -3,7 +3,7 @@ import { followAccount, unfollowAccount } from '../_api/follow'
|
|||
import { database } from '../_database/database'
|
||||
import { toast } from '../_utils/toast'
|
||||
|
||||
export async function setAccountFollowed (accountId, follow) {
|
||||
export async function setAccountFollowed (accountId, follow, toastOnSuccess) {
|
||||
let instanceName = store.get('currentInstance')
|
||||
let accessToken = store.get('accessToken')
|
||||
try {
|
||||
|
@ -15,6 +15,9 @@ export async function setAccountFollowed (accountId, follow) {
|
|||
let relationship = await database.getRelationship(instanceName, accountId)
|
||||
relationship.following = follow
|
||||
await database.setRelationship(instanceName, relationship)
|
||||
if (toastOnSuccess) {
|
||||
toast.say(`${follow ? 'Followed' : 'Unfollowed'}`)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
toast.say(`Unable to ${follow ? 'follow' : 'unfollow'} account: ` + (e.message || ''))
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
<ul class="generic-dialog-list">
|
||||
{{#each items as item @key}}
|
||||
<li class="generic-dialog-list-item">
|
||||
<button class="generic-dialog-list-button" on:click="fire('click', item)">
|
||||
<svg>
|
||||
<use xlink:href="{{item.icon}}" />
|
||||
</svg>
|
||||
<span>
|
||||
{{item.label}}
|
||||
</span>
|
||||
<svg class="{{item.selected ? '' : 'hidden'}}" aria-hidden="{{!item.selected}}">
|
||||
<use xlink:href="#fa-check" />
|
||||
</svg>
|
||||
</button>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
<style>
|
||||
.generic-dialog-list {
|
||||
list-style: none;
|
||||
width: 100%;
|
||||
border: 1px solid var(--settings-list-item-border);
|
||||
box-sizing: border-box;
|
||||
min-width: 300px;
|
||||
max-width: calc(100vw - 20px);
|
||||
}
|
||||
.generic-dialog-list-item {
|
||||
border: 1px solid var(--settings-list-item-border);
|
||||
font-size: 1.2em;
|
||||
display: flex;
|
||||
}
|
||||
.generic-dialog-list-item svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
fill: var(--svg-fill);
|
||||
}
|
||||
.generic-dialog-list-button {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
background: var(--settings-list-item-bg);
|
||||
border: none;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.generic-dialog-list-button span {
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
margin-left: 20px;
|
||||
}
|
||||
.generic-dialog-list-button:hover {
|
||||
background: var(--settings-list-item-bg-hover);
|
||||
}
|
||||
.generic-dialog-list-button:active {
|
||||
background: var(--settings-list-item-bg-active);
|
||||
}
|
||||
</style>
|
|
@ -1,86 +1,28 @@
|
|||
<ModalDialog :label :shown :closed :title background="var(--main-bg)">
|
||||
<ul class="post-privacy">
|
||||
{{#each postPrivacyOptions as option}}
|
||||
<li class="post-privacy-item">
|
||||
<button class="post-privacy-button" on:click="onClick(option)">
|
||||
<svg>
|
||||
<use xlink:href="{{option.icon}}" />
|
||||
</svg>
|
||||
<span>
|
||||
{{option.label}}
|
||||
</span>
|
||||
<svg class="{{isSelected(option, postPrivacy) ? '' : 'hidden'}}"
|
||||
aria-hidden="{{!isSelected(option, postPrivacy)}}">
|
||||
<use xlink:href="#fa-check" />
|
||||
</svg>
|
||||
</button>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
<GenericDialogList :items on:click="onClick(event)" />
|
||||
</ModalDialog>
|
||||
<style>
|
||||
.post-privacy {
|
||||
list-style: none;
|
||||
width: 100%;
|
||||
border: 1px solid var(--settings-list-item-border);
|
||||
box-sizing: border-box;
|
||||
min-width: 300px;
|
||||
max-width: calc(100vw - 20px);
|
||||
}
|
||||
.post-privacy-item {
|
||||
border: 1px solid var(--settings-list-item-border);
|
||||
font-size: 1.2em;
|
||||
display: flex;
|
||||
}
|
||||
.post-privacy-item svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
fill: var(--svg-fill);
|
||||
}
|
||||
.post-privacy-button {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
background: var(--settings-list-item-bg);
|
||||
border: none;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.post-privacy-button span {
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
margin-left: 20px;
|
||||
}
|
||||
.post-privacy-button:hover {
|
||||
background: var(--settings-list-item-bg-hover);
|
||||
}
|
||||
.post-privacy-button:active {
|
||||
background: var(--settings-list-item-bg-active);
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
import ModalDialog from './ModalDialog.html'
|
||||
import { store } from '../../_store/store'
|
||||
import { POST_PRIVACY_OPTIONS } from '../../_static/statuses'
|
||||
import { setPostPrivacy } from '../../_actions/postPrivacy'
|
||||
import GenericDialogList from './GenericDialogList.html'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ModalDialog
|
||||
ModalDialog,
|
||||
GenericDialogList
|
||||
},
|
||||
store: () => store,
|
||||
data: () => ({
|
||||
postPrivacyOptions: POST_PRIVACY_OPTIONS
|
||||
}),
|
||||
helpers: {
|
||||
isSelected: (option, postPrivacy) => postPrivacy.key === option.key
|
||||
},
|
||||
methods: {
|
||||
async show() {
|
||||
this.set({shown: true})
|
||||
},
|
||||
onClick(option) {
|
||||
setPostPrivacy(this.get('realm'), option.key)
|
||||
onClick(item) {
|
||||
setPostPrivacy(this.get('realm'), item.key)
|
||||
this.set({closed: true})
|
||||
}
|
||||
},
|
||||
|
@ -91,6 +33,14 @@
|
|||
},
|
||||
postPrivacyKey: (composeData, $currentVerifyCredentials) => {
|
||||
return composeData.postPrivacy || $currentVerifyCredentials.source.privacy
|
||||
},
|
||||
items: (postPrivacy, postPrivacyOptions) => {
|
||||
return postPrivacyOptions.map(option => ({
|
||||
key: option.key,
|
||||
label: option.label,
|
||||
icon: option.icon,
|
||||
selected: postPrivacy.key === option.key
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
<ModalDialog :label :shown :closed :title background="var(--main-bg)">
|
||||
<GenericDialogList :items on:click="onClick(event)"/>
|
||||
</ModalDialog>
|
||||
<script>
|
||||
import ModalDialog from './ModalDialog.html'
|
||||
import { store } from '../../_store/store'
|
||||
import GenericDialogList from './GenericDialogList.html'
|
||||
import { setAccountFollowed } from '../../_actions/follow'
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
relationship: ($currentAccountRelationship) => $currentAccountRelationship,
|
||||
account: ($currentAccountProfile) => $currentAccountProfile,
|
||||
following: (relationship) => relationship && !!relationship.following,
|
||||
accountName: (account) => account && (account.display_name || account.acct),
|
||||
accountId: (account) => account && account.id,
|
||||
followLabel: (following, accountName) => {
|
||||
if (typeof following === 'undefined' || !accountName) {
|
||||
return ''
|
||||
}
|
||||
return following ? `Unfollow ${accountName}` : `Follow ${accountName}`
|
||||
},
|
||||
items: (followLabel, following) => {
|
||||
return [
|
||||
{
|
||||
key: 'follow',
|
||||
label: followLabel,
|
||||
icon: following ? '#fa-user-times' : '#fa-user-plus'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
components: {
|
||||
ModalDialog,
|
||||
GenericDialogList
|
||||
},
|
||||
store: () => store,
|
||||
methods: {
|
||||
async show() {
|
||||
this.set({shown: true})
|
||||
},
|
||||
async onClick(item) {
|
||||
if (item.key === 'follow') {
|
||||
let accountId = this.get('accountId')
|
||||
let following = this.get('following')
|
||||
await setAccountFollowed(accountId, !following, true)
|
||||
this.set({closed: true})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -3,3 +3,4 @@ export * from './showImageDialog'
|
|||
export * from './showVideoDialog'
|
||||
export * from './showEmojiDialog'
|
||||
export * from './showPostPrivacyDialog'
|
||||
export * from './showStatusOptionsDialog'
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import StatusOptionsDialog from './StatusOptionsDialog.html'
|
||||
|
||||
export function showStatusOptionsDialog (statusId) {
|
||||
let dialog = new StatusOptionsDialog({
|
||||
target: document.getElementById('modal-dialog'),
|
||||
data: {
|
||||
label: 'Status options dialog',
|
||||
title: 'Status options',
|
||||
statusId: statusId
|
||||
}
|
||||
})
|
||||
dialog.show()
|
||||
}
|
|
@ -4,7 +4,6 @@
|
|||
href="#fa-reply"
|
||||
disabled="{{disableReply}}"
|
||||
delegateKey="{{replyKey}}"
|
||||
ref:replyNode
|
||||
/>
|
||||
<IconButton
|
||||
label="{{reblogLabel}}"
|
||||
|
@ -13,7 +12,6 @@
|
|||
disabled="{{reblogDisabled}}"
|
||||
href="{{reblogIcon}}"
|
||||
delegateKey="{{reblogKey}}"
|
||||
ref:reblogNode
|
||||
/>
|
||||
<IconButton
|
||||
label="Favorite"
|
||||
|
@ -21,11 +19,11 @@
|
|||
pressed="{{favorited}}"
|
||||
href="#fa-star"
|
||||
delegateKey="{{favoriteKey}}"
|
||||
ref:favoriteNode
|
||||
/>
|
||||
<IconButton
|
||||
label="Show more actions"
|
||||
label="Show more options"
|
||||
href="#fa-ellipsis-h"
|
||||
delegateKey="{{optionsKey}}"
|
||||
/>
|
||||
</div>
|
||||
<style>
|
||||
|
@ -45,17 +43,21 @@
|
|||
import { setFavorited } from '../../_actions/favorite'
|
||||
import { setReblogged } from '../../_actions/reblog'
|
||||
import { goto } from 'sapper/runtime.js'
|
||||
import { importDialogs } from '../../_utils/asyncModules'
|
||||
import { updateProfileAndRelationship } from '../../_actions/accounts'
|
||||
|
||||
export default {
|
||||
oncreate() {
|
||||
registerClickDelegate(this.get('favoriteKey'), () => this.onFavoriteClick())
|
||||
registerClickDelegate(this.get('reblogKey'), () => this.onReblogClick())
|
||||
registerClickDelegate(this.get('replyKey'), () => this.onReplyClick())
|
||||
registerClickDelegate(this.get('optionsKey'), () => this.onOptionsClick())
|
||||
},
|
||||
ondestroy() {
|
||||
unregisterClickDelegate(this.get('favoriteKey'))
|
||||
unregisterClickDelegate(this.get('reblogKey'))
|
||||
unregisterClickDelegate(this.get('replyKey'))
|
||||
unregisterClickDelegate(this.get('optionsKey'))
|
||||
},
|
||||
components: {
|
||||
IconButton
|
||||
|
@ -75,6 +77,14 @@
|
|||
onReplyClick() {
|
||||
let statusId = this.get('statusId')
|
||||
goto(`/statuses/${statusId}/reply`)
|
||||
},
|
||||
async onOptionsClick() {
|
||||
let statusId = this.get('statusId')
|
||||
let accountId = this.get('accountId')
|
||||
let updateRelationshipPromise = updateProfileAndRelationship(accountId)
|
||||
let dialogs = await importDialogs()
|
||||
await updateRelationshipPromise
|
||||
dialogs.showStatusOptionsDialog(statusId)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -115,10 +125,13 @@
|
|||
return status.favourited
|
||||
},
|
||||
statusId: (status) => status.id,
|
||||
accountId: (status) => status.account.id,
|
||||
disableReply: (statusId, timelineType, timelineValue) => timelineType === 'reply' && statusId === timelineValue,
|
||||
favoriteKey: (statusId, timelineType, timelineValue) => `fav-${timelineType}-${timelineValue}-${statusId}`,
|
||||
reblogKey: (statusId, timelineType, timelineValue) => `reblog-${timelineType}-${timelineValue}-${statusId}`,
|
||||
replyKey: (statusId, timelineType, timelineValue) => `reply-${timelineType}-${timelineValue}-${statusId}`,
|
||||
keyPrefix: (timelineType, timelineValue, statusId) => `${timelineType}-${timelineValue}-${statusId}`,
|
||||
favoriteKey: (keyPrefix) => `${keyPrefix}-fav`,
|
||||
reblogKey: (keyPrefix) => `${keyPrefix}-reblog`,
|
||||
replyKey: (keyPrefix) => `${keyPrefix}-reply`,
|
||||
optionsKey: (keyPrefix) => `${keyPrefix}-options`,
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -8,9 +8,9 @@ test('Changes post privacy', async t => {
|
|||
await t.useRole(foobarRole)
|
||||
.expect(postPrivacyButton.getAttribute('aria-label')).eql('Adjust privacy (currently Public)')
|
||||
.click(postPrivacyButton)
|
||||
.click('.post-privacy li:nth-child(2) button')
|
||||
.click('.generic-dialog-list li:nth-child(2) button')
|
||||
.expect(postPrivacyButton.getAttribute('aria-label')).eql('Adjust privacy (currently Unlisted)')
|
||||
.click(postPrivacyButton)
|
||||
.click('.post-privacy li:nth-child(1) button')
|
||||
.click('.generic-dialog-list li:nth-child(1) button')
|
||||
.expect(postPrivacyButton.getAttribute('aria-label')).eql('Adjust privacy (currently Public)')
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue