Merge branch 'develop' into 'themes-accent'
# Conflicts: # src/components/emoji_reactions/emoji_reactions.vue
This commit is contained in:
commit
84ebae8ed3
|
@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Pleroma AMOLED dark theme
|
- Pleroma AMOLED dark theme
|
||||||
- User level domain mutes, under User Settings -> Mutes
|
- User level domain mutes, under User Settings -> Mutes
|
||||||
- Emoji reactions for statuses
|
- Emoji reactions for statuses
|
||||||
|
- MRF keyword policy disclosure
|
||||||
### Changed
|
### Changed
|
||||||
- theme engine update to 3 (themes v2.1 introduction)
|
- theme engine update to 3 (themes v2.1 introduction)
|
||||||
- massive internal changes in theme engine - slowly away from "generate things separately with spaghetti code" towards "feed all data into single 'generateTheme' function and declare slot inheritance and all in a separate file"
|
- massive internal changes in theme engine - slowly away from "generate things separately with spaghetti code" towards "feed all data into single 'generateTheme' function and declare slot inheritance and all in a separate file"
|
||||||
|
|
|
@ -78,7 +78,7 @@ button {
|
||||||
border-radius: $fallback--btnRadius;
|
border-radius: $fallback--btnRadius;
|
||||||
border-radius: var(--btnRadius, $fallback--btnRadius);
|
border-radius: var(--btnRadius, $fallback--btnRadius);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 1), 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
|
box-shadow: $fallback--buttonShadow;
|
||||||
box-shadow: var(--buttonShadow);
|
box-shadow: var(--buttonShadow);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
|
|
|
@ -27,3 +27,5 @@ $fallback--tooltipRadius: 5px;
|
||||||
$fallback--avatarRadius: 4px;
|
$fallback--avatarRadius: 4px;
|
||||||
$fallback--avatarAltRadius: 10px;
|
$fallback--avatarAltRadius: 10px;
|
||||||
$fallback--attachmentRadius: 10px;
|
$fallback--attachmentRadius: 10px;
|
||||||
|
|
||||||
|
$fallback--buttonShadow: 0px 0px 2px 0px rgba(0, 0, 0, 1), 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
|
||||||
|
|
|
@ -1,17 +1,55 @@
|
||||||
|
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||||
|
|
||||||
|
const EMOJI_REACTION_COUNT_CUTOFF = 12
|
||||||
|
|
||||||
const EmojiReactions = {
|
const EmojiReactions = {
|
||||||
name: 'EmojiReactions',
|
name: 'EmojiReactions',
|
||||||
|
components: {
|
||||||
|
UserAvatar
|
||||||
|
},
|
||||||
props: ['status'],
|
props: ['status'],
|
||||||
|
data: () => ({
|
||||||
|
showAll: false,
|
||||||
|
popperOptions: {
|
||||||
|
modifiers: {
|
||||||
|
preventOverflow: { padding: { top: 50 }, boundariesElement: 'viewport' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
|
tooManyReactions () {
|
||||||
|
return this.status.emoji_reactions.length > EMOJI_REACTION_COUNT_CUTOFF
|
||||||
|
},
|
||||||
emojiReactions () {
|
emojiReactions () {
|
||||||
return this.status.emoji_reactions
|
return this.showAll
|
||||||
|
? this.status.emoji_reactions
|
||||||
|
: this.status.emoji_reactions.slice(0, EMOJI_REACTION_COUNT_CUTOFF)
|
||||||
|
},
|
||||||
|
showMoreString () {
|
||||||
|
return `+${this.status.emoji_reactions.length - EMOJI_REACTION_COUNT_CUTOFF}`
|
||||||
|
},
|
||||||
|
accountsForEmoji () {
|
||||||
|
return this.status.emoji_reactions.reduce((acc, reaction) => {
|
||||||
|
acc[reaction.name] = reaction.accounts || []
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
},
|
||||||
|
loggedIn () {
|
||||||
|
return !!this.$store.state.users.currentUser
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
toggleShowAll () {
|
||||||
|
this.showAll = !this.showAll
|
||||||
|
},
|
||||||
reactedWith (emoji) {
|
reactedWith (emoji) {
|
||||||
const user = this.$store.state.users.currentUser
|
return this.status.emoji_reactions.find(r => r.name === emoji).me
|
||||||
const reaction = this.status.emoji_reactions.find(r => r.emoji === emoji)
|
},
|
||||||
return reaction.accounts && reaction.accounts.find(u => u.id === user.id)
|
fetchEmojiReactionsByIfMissing () {
|
||||||
|
const hasNoAccounts = this.status.emoji_reactions.find(r => !r.accounts)
|
||||||
|
if (hasNoAccounts) {
|
||||||
|
this.$store.dispatch('fetchEmojiReactionsBy', this.status.id)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
reactWith (emoji) {
|
reactWith (emoji) {
|
||||||
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
|
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
|
||||||
|
@ -20,6 +58,8 @@ const EmojiReactions = {
|
||||||
this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji })
|
this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji })
|
||||||
},
|
},
|
||||||
emojiOnClick (emoji, event) {
|
emojiOnClick (emoji, event) {
|
||||||
|
if (!this.loggedIn) return
|
||||||
|
|
||||||
if (this.reactedWith(emoji)) {
|
if (this.reactedWith(emoji)) {
|
||||||
this.unreact(emoji)
|
this.unreact(emoji)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,16 +1,58 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="emoji-reactions">
|
<div class="emoji-reactions">
|
||||||
<button
|
<v-popover
|
||||||
v-for="(reaction) in emojiReactions"
|
v-for="(reaction) in emojiReactions"
|
||||||
:key="reaction.emoji"
|
:key="reaction.name"
|
||||||
class="emoji-reaction btn btn-default"
|
:popper-options="popperOptions"
|
||||||
:class="{ 'toggled': reactedWith(reaction.emoji) }"
|
trigger="hover"
|
||||||
@click="emojiOnClick(reaction.emoji, $event)"
|
placement="top"
|
||||||
>
|
>
|
||||||
<span class="reaction-emoji">{{ reaction.emoji }}</span>
|
|
||||||
<span>{{ reaction.count }}</span>
|
<div
|
||||||
</button>
|
slot="popover"
|
||||||
|
class="reacted-users"
|
||||||
|
>
|
||||||
|
<div v-if="accountsForEmoji[reaction.name].length">
|
||||||
|
<div
|
||||||
|
v-for="(account) in accountsForEmoji[reaction.name]"
|
||||||
|
:key="account.id"
|
||||||
|
class="reacted-user"
|
||||||
|
>
|
||||||
|
<UserAvatar
|
||||||
|
:user="account"
|
||||||
|
class="avatar-small"
|
||||||
|
:compact="true"
|
||||||
|
/>
|
||||||
|
<div class="reacted-user-names">
|
||||||
|
<span class="reacted-user-name" v-html="account.name_html" />
|
||||||
|
<span class="reacted-user-screen-name">{{ account.screen_name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<i class="icon-spin4 animate-spin" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="emoji-reaction btn btn-default"
|
||||||
|
:class="{ 'picked-reaction': reactedWith(reaction.name), 'not-clickable': !loggedIn }"
|
||||||
|
@click="emojiOnClick(reaction.name, $event)"
|
||||||
|
@mouseenter="fetchEmojiReactionsByIfMissing()"
|
||||||
|
>
|
||||||
|
<span class="reaction-emoji">{{ reaction.name }}</span>
|
||||||
|
<span>{{ reaction.count }}</span>
|
||||||
|
</button>
|
||||||
|
</v-popover>
|
||||||
|
<a
|
||||||
|
v-if="tooManyReactions"
|
||||||
|
@click="toggleShowAll"
|
||||||
|
class="emoji-reaction-expand faint"
|
||||||
|
href='javascript:void(0)'
|
||||||
|
>
|
||||||
|
{{ showAll ? $t('general.show_less') : showMoreString }}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./emoji_reactions.js" ></script>
|
<script src="./emoji_reactions.js" ></script>
|
||||||
|
@ -23,6 +65,31 @@
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.reacted-users {
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reacted-user {
|
||||||
|
padding: 0.25em;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.reacted-user-names {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.reacted-user-screen-name {
|
||||||
|
font-size: 9px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.emoji-reaction {
|
.emoji-reaction {
|
||||||
padding: 0 0.5em;
|
padding: 0 0.5em;
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
|
@ -38,6 +105,26 @@
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.not-clickable {
|
||||||
|
cursor: default;
|
||||||
|
&:hover {
|
||||||
|
box-shadow: $fallback--buttonShadow;
|
||||||
|
box-shadow: var(--buttonShadow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-reaction-expand {
|
||||||
|
padding: 0 0.5em;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -10,6 +10,7 @@ const tabModeDict = {
|
||||||
const Interactions = {
|
const Interactions = {
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
allowFollowingMove: this.$store.state.users.currentUser.allow_following_move,
|
||||||
filterMode: tabModeDict['mentions']
|
filterMode: tabModeDict['mentions']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
:label="$t('interactions.follows')"
|
:label="$t('interactions.follows')"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
|
v-if="!allowFollowingMove"
|
||||||
key="moves"
|
key="moves"
|
||||||
:label="$t('interactions.moves')"
|
:label="$t('interactions.moves')"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -11,7 +11,10 @@ const MRFTransparencyPanel = {
|
||||||
rejectInstances: state => get(state, 'instance.federationPolicy.mrf_simple.reject', []),
|
rejectInstances: state => get(state, 'instance.federationPolicy.mrf_simple.reject', []),
|
||||||
ftlRemovalInstances: state => get(state, 'instance.federationPolicy.mrf_simple.federated_timeline_removal', []),
|
ftlRemovalInstances: state => get(state, 'instance.federationPolicy.mrf_simple.federated_timeline_removal', []),
|
||||||
mediaNsfwInstances: state => get(state, 'instance.federationPolicy.mrf_simple.media_nsfw', []),
|
mediaNsfwInstances: state => get(state, 'instance.federationPolicy.mrf_simple.media_nsfw', []),
|
||||||
mediaRemovalInstances: state => get(state, 'instance.federationPolicy.mrf_simple.media_removal', [])
|
mediaRemovalInstances: state => get(state, 'instance.federationPolicy.mrf_simple.media_removal', []),
|
||||||
|
keywordsFtlRemoval: state => get(state, 'instance.federationPolicy.mrf_keyword.federated_timeline_removal', []),
|
||||||
|
keywordsReject: state => get(state, 'instance.federationPolicy.mrf_keyword.reject', []),
|
||||||
|
keywordsReplace: state => get(state, 'instance.federationPolicy.mrf_keyword.replace', [])
|
||||||
}),
|
}),
|
||||||
hasInstanceSpecificPolicies () {
|
hasInstanceSpecificPolicies () {
|
||||||
return this.quarantineInstances.length ||
|
return this.quarantineInstances.length ||
|
||||||
|
@ -20,6 +23,11 @@ const MRFTransparencyPanel = {
|
||||||
this.ftlRemovalInstances.length ||
|
this.ftlRemovalInstances.length ||
|
||||||
this.mediaNsfwInstances.length ||
|
this.mediaNsfwInstances.length ||
|
||||||
this.mediaRemovalInstances.length
|
this.mediaRemovalInstances.length
|
||||||
|
},
|
||||||
|
hasKeywordPolicies () {
|
||||||
|
return this.keywordsFtlRemoval.length ||
|
||||||
|
this.keywordsReject.length ||
|
||||||
|
this.keywordsReplace.length
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,6 +109,49 @@
|
||||||
/>
|
/>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h2 v-if="hasKeywordPolicies">
|
||||||
|
{{ $t("about.mrf.keyword.keyword_policies") }}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div v-if="keywordsFtlRemoval.length">
|
||||||
|
<h4>{{ $t("about.mrf.keyword.ftl_removal") }}</h4>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li
|
||||||
|
v-for="keyword in keywordsFtlRemoval"
|
||||||
|
:key="keyword"
|
||||||
|
v-text="keyword"
|
||||||
|
/>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="keywordsReject.length">
|
||||||
|
<h4>{{ $t("about.mrf.keyword.reject") }}</h4>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li
|
||||||
|
v-for="keyword in keywordsReject"
|
||||||
|
:key="keyword"
|
||||||
|
v-text="keyword"
|
||||||
|
/>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="keywordsReplace.length">
|
||||||
|
<h4>{{ $t("about.mrf.keyword.replace") }}</h4>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li
|
||||||
|
v-for="keyword in keywordsReplace"
|
||||||
|
:key="keyword"
|
||||||
|
>
|
||||||
|
{{ keyword.pattern }}
|
||||||
|
{{ $t("about.mrf.keyword.is_replaced_by") }}
|
||||||
|
{{ keyword.replacement }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -78,6 +78,13 @@
|
||||||
<i class="fa icon-arrow-curved lit" />
|
<i class="fa icon-arrow-curved lit" />
|
||||||
<small>{{ $t('notifications.migrated_to') }}</small>
|
<small>{{ $t('notifications.migrated_to') }}</small>
|
||||||
</span>
|
</span>
|
||||||
|
<span v-if="notification.type === 'pleroma:emoji_reaction'">
|
||||||
|
<small>
|
||||||
|
<i18n path="notifications.reacted_with">
|
||||||
|
<span class="emoji-reaction-emoji">{{ notification.emoji }}</span>
|
||||||
|
</i18n>
|
||||||
|
</small>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="notification.type === 'follow' || notification.type === 'move'"
|
v-if="notification.type === 'follow' || notification.type === 'move'"
|
||||||
|
|
|
@ -97,6 +97,10 @@
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.emoji-reaction-emoji {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.notification-details {
|
.notification-details {
|
||||||
min-width: 0px;
|
min-width: 0px;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
|
|
|
@ -22,7 +22,12 @@ const ReactButton = {
|
||||||
this.showTooltip = false
|
this.showTooltip = false
|
||||||
},
|
},
|
||||||
addReaction (event, emoji) {
|
addReaction (event, emoji) {
|
||||||
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
|
const existingReaction = this.status.emoji_reactions.find(r => r.name === emoji)
|
||||||
|
if (existingReaction && existingReaction.me) {
|
||||||
|
this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji })
|
||||||
|
} else {
|
||||||
|
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
|
||||||
|
}
|
||||||
this.closeReactionSelect()
|
this.closeReactionSelect()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -54,6 +54,10 @@
|
||||||
|
|
||||||
.reaction-picker-filter {
|
.reaction-picker-filter {
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
|
display: flex;
|
||||||
|
input {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.reaction-picker-divider {
|
.reaction-picker-divider {
|
||||||
|
|
|
@ -92,6 +92,11 @@
|
||||||
{{ $t('settings.reply_link_preview') }}
|
{{ $t('settings.reply_link_preview') }}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<Checkbox v-model="emojiReactionsOnTimeline">
|
||||||
|
{{ $t('settings.emoji_reactions_on_timeline') }}
|
||||||
|
</Checkbox>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -328,6 +333,11 @@
|
||||||
{{ $t('settings.notification_visibility_moves') }}
|
{{ $t('settings.notification_visibility_moves') }}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<Checkbox v-model="notificationVisibility.emojiReactions">
|
||||||
|
{{ $t('settings.notification_visibility_emoji_reactions') }}
|
||||||
|
</Checkbox>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -256,6 +256,16 @@ const Status = {
|
||||||
file => !fileType.fileMatchesSomeType(this.galleryTypes, file)
|
file => !fileType.fileMatchesSomeType(this.galleryTypes, file)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
hasImageAttachments () {
|
||||||
|
return this.status.attachments.some(
|
||||||
|
file => fileType.fileType(file.mimetype) === 'image'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
hasVideoAttachments () {
|
||||||
|
return this.status.attachments.some(
|
||||||
|
file => fileType.fileType(file.mimetype) === 'video'
|
||||||
|
)
|
||||||
|
},
|
||||||
maxThumbnails () {
|
maxThumbnails () {
|
||||||
return this.mergedConfig.maxThumbnails
|
return this.mergedConfig.maxThumbnails
|
||||||
},
|
},
|
||||||
|
|
|
@ -277,7 +277,21 @@
|
||||||
href="#"
|
href="#"
|
||||||
class="cw-status-hider"
|
class="cw-status-hider"
|
||||||
@click.prevent="toggleShowMore"
|
@click.prevent="toggleShowMore"
|
||||||
>{{ $t("general.show_more") }}</a>
|
>
|
||||||
|
{{ $t("general.show_more") }}
|
||||||
|
<span
|
||||||
|
v-if="hasImageAttachments"
|
||||||
|
class="icon-picture"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
v-if="hasVideoAttachments"
|
||||||
|
class="icon-video"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
v-if="status.card"
|
||||||
|
class="icon-link"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
<a
|
<a
|
||||||
v-if="showingMore"
|
v-if="showingMore"
|
||||||
href="#"
|
href="#"
|
||||||
|
@ -355,6 +369,7 @@
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<EmojiReactions
|
<EmojiReactions
|
||||||
|
v-if="(mergedConfig.emojiReactionsOnTimeline || isFocused) && (!noHeading && !isPreview)"
|
||||||
:status="status"
|
:status="status"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ const UserSettings = {
|
||||||
showRole: this.$store.state.users.currentUser.show_role,
|
showRole: this.$store.state.users.currentUser.show_role,
|
||||||
role: this.$store.state.users.currentUser.role,
|
role: this.$store.state.users.currentUser.role,
|
||||||
discoverable: this.$store.state.users.currentUser.discoverable,
|
discoverable: this.$store.state.users.currentUser.discoverable,
|
||||||
|
allowFollowingMove: this.$store.state.users.currentUser.allow_following_move,
|
||||||
pickAvatarBtnVisible: true,
|
pickAvatarBtnVisible: true,
|
||||||
bannerUploading: false,
|
bannerUploading: false,
|
||||||
backgroundUploading: false,
|
backgroundUploading: false,
|
||||||
|
@ -162,6 +163,7 @@ const UserSettings = {
|
||||||
hide_follows: this.hideFollows,
|
hide_follows: this.hideFollows,
|
||||||
hide_followers: this.hideFollowers,
|
hide_followers: this.hideFollowers,
|
||||||
discoverable: this.discoverable,
|
discoverable: this.discoverable,
|
||||||
|
allow_following_move: this.allowFollowingMove,
|
||||||
hide_follows_count: this.hideFollowsCount,
|
hide_follows_count: this.hideFollowsCount,
|
||||||
hide_followers_count: this.hideFollowersCount,
|
hide_followers_count: this.hideFollowersCount,
|
||||||
show_role: this.showRole
|
show_role: this.showRole
|
||||||
|
|
|
@ -90,9 +90,7 @@
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<Checkbox
|
<Checkbox v-model="hideFollowers">
|
||||||
v-model="hideFollowers"
|
|
||||||
>
|
|
||||||
{{ $t('settings.hide_followers_description') }}
|
{{ $t('settings.hide_followers_description') }}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</p>
|
</p>
|
||||||
|
@ -104,6 +102,11 @@
|
||||||
{{ $t('settings.hide_followers_count_description') }}
|
{{ $t('settings.hide_followers_count_description') }}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<Checkbox v-model="allowFollowingMove">
|
||||||
|
{{ $t('settings.allow_following_move') }}
|
||||||
|
</Checkbox>
|
||||||
|
</p>
|
||||||
<p v-if="role === 'admin' || role === 'moderator'">
|
<p v-if="role === 'admin' || role === 'moderator'">
|
||||||
<Checkbox v-model="showRole">
|
<Checkbox v-model="showRole">
|
||||||
<template v-if="role === 'admin'">
|
<template v-if="role === 'admin'">
|
||||||
|
|
|
@ -16,7 +16,16 @@
|
||||||
"mrf_policy_simple_media_removal": "Media Removal",
|
"mrf_policy_simple_media_removal": "Media Removal",
|
||||||
"mrf_policy_simple_media_removal_desc": "This instance removes media from posts on the following instances:",
|
"mrf_policy_simple_media_removal_desc": "This instance removes media from posts on the following instances:",
|
||||||
"mrf_policy_simple_media_nsfw": "Media Force-set As Sensitive",
|
"mrf_policy_simple_media_nsfw": "Media Force-set As Sensitive",
|
||||||
"mrf_policy_simple_media_nsfw_desc": "This instance forces media to be set sensitive in posts on the following instances:"
|
"mrf_policy_simple_media_nsfw_desc": "This instance forces media to be set sensitive in posts on the following instances:",
|
||||||
|
"mrf": {
|
||||||
|
"keyword": {
|
||||||
|
"keyword_policies": "Keyword Policies",
|
||||||
|
"ftl_removal": "Removal from \"The Whole Known Network\" Timeline",
|
||||||
|
"reject": "Reject",
|
||||||
|
"replace": "Replace",
|
||||||
|
"is_replaced_by": "→"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"chat": {
|
"chat": {
|
||||||
"title": "Chat"
|
"title": "Chat"
|
||||||
|
@ -118,7 +127,8 @@
|
||||||
"read": "Read!",
|
"read": "Read!",
|
||||||
"repeated_you": "repeated your status",
|
"repeated_you": "repeated your status",
|
||||||
"no_more_notifications": "No more notifications",
|
"no_more_notifications": "No more notifications",
|
||||||
"migrated_to": "migrated to"
|
"migrated_to": "migrated to",
|
||||||
|
"reacted_with": "reacted with {0}"
|
||||||
},
|
},
|
||||||
"polls": {
|
"polls": {
|
||||||
"add_poll": "Add Poll",
|
"add_poll": "Add Poll",
|
||||||
|
@ -233,6 +243,7 @@
|
||||||
"desc": "To enable two-factor authentication, enter the code from your two-factor app:"
|
"desc": "To enable two-factor authentication, enter the code from your two-factor app:"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"allow_following_move": "Allow auto-follow when following account moves",
|
||||||
"attachmentRadius": "Attachments",
|
"attachmentRadius": "Attachments",
|
||||||
"attachments": "Attachments",
|
"attachments": "Attachments",
|
||||||
"autoload": "Enable automatic loading when scrolled to the bottom",
|
"autoload": "Enable automatic loading when scrolled to the bottom",
|
||||||
|
@ -274,6 +285,7 @@
|
||||||
"domain_mutes": "Domains",
|
"domain_mutes": "Domains",
|
||||||
"avatar_size_instruction": "The recommended minimum size for avatar images is 150x150 pixels.",
|
"avatar_size_instruction": "The recommended minimum size for avatar images is 150x150 pixels.",
|
||||||
"pad_emoji": "Pad emoji with spaces when adding from picker",
|
"pad_emoji": "Pad emoji with spaces when adding from picker",
|
||||||
|
"emoji_reactions_on_timeline": "Show emoji reactions on timeline",
|
||||||
"export_theme": "Save preset",
|
"export_theme": "Save preset",
|
||||||
"filtering": "Filtering",
|
"filtering": "Filtering",
|
||||||
"filtering_explanation": "All statuses containing these words will be muted, one per line",
|
"filtering_explanation": "All statuses containing these words will be muted, one per line",
|
||||||
|
@ -323,6 +335,7 @@
|
||||||
"notification_visibility_mentions": "Mentions",
|
"notification_visibility_mentions": "Mentions",
|
||||||
"notification_visibility_repeats": "Repeats",
|
"notification_visibility_repeats": "Repeats",
|
||||||
"notification_visibility_moves": "User Migrates",
|
"notification_visibility_moves": "User Migrates",
|
||||||
|
"notification_visibility_emoji_reactions": "Reactions",
|
||||||
"no_rich_text_description": "Strip rich text formatting from all posts",
|
"no_rich_text_description": "Strip rich text formatting from all posts",
|
||||||
"no_blocks": "No blocks",
|
"no_blocks": "No blocks",
|
||||||
"no_mutes": "No mutes",
|
"no_mutes": "No mutes",
|
||||||
|
|
|
@ -53,7 +53,8 @@
|
||||||
"notifications": "Ilmoitukset",
|
"notifications": "Ilmoitukset",
|
||||||
"read": "Lue!",
|
"read": "Lue!",
|
||||||
"repeated_you": "toisti viestisi",
|
"repeated_you": "toisti viestisi",
|
||||||
"no_more_notifications": "Ei enempää ilmoituksia"
|
"no_more_notifications": "Ei enempää ilmoituksia",
|
||||||
|
"reacted_with": "lisäsi reaktion {0}"
|
||||||
},
|
},
|
||||||
"polls": {
|
"polls": {
|
||||||
"add_poll": "Lisää äänestys",
|
"add_poll": "Lisää äänestys",
|
||||||
|
@ -140,6 +141,7 @@
|
||||||
"delete_account_description": "Poista tilisi ja viestisi pysyvästi.",
|
"delete_account_description": "Poista tilisi ja viestisi pysyvästi.",
|
||||||
"delete_account_error": "Virhe poistaessa tiliäsi. Jos virhe jatkuu, ota yhteyttä palvelimesi ylläpitoon.",
|
"delete_account_error": "Virhe poistaessa tiliäsi. Jos virhe jatkuu, ota yhteyttä palvelimesi ylläpitoon.",
|
||||||
"delete_account_instructions": "Syötä salasanasi vahvistaaksesi tilin poiston.",
|
"delete_account_instructions": "Syötä salasanasi vahvistaaksesi tilin poiston.",
|
||||||
|
"emoji_reactions_on_timeline": "Näytä emojireaktiot aikajanalla",
|
||||||
"export_theme": "Tallenna teema",
|
"export_theme": "Tallenna teema",
|
||||||
"filtering": "Suodatus",
|
"filtering": "Suodatus",
|
||||||
"filtering_explanation": "Kaikki viestit, jotka sisältävät näitä sanoja, suodatetaan. Yksi sana per rivi.",
|
"filtering_explanation": "Kaikki viestit, jotka sisältävät näitä sanoja, suodatetaan. Yksi sana per rivi.",
|
||||||
|
@ -183,6 +185,7 @@
|
||||||
"notification_visibility_likes": "Tykkäykset",
|
"notification_visibility_likes": "Tykkäykset",
|
||||||
"notification_visibility_mentions": "Maininnat",
|
"notification_visibility_mentions": "Maininnat",
|
||||||
"notification_visibility_repeats": "Toistot",
|
"notification_visibility_repeats": "Toistot",
|
||||||
|
"notification_visibility_emoji_reactions": "Reaktiot",
|
||||||
"no_rich_text_description": "Älä näytä tekstin muotoilua.",
|
"no_rich_text_description": "Älä näytä tekstin muotoilua.",
|
||||||
"hide_network_description": "Älä näytä seurauksiani tai seuraajiani",
|
"hide_network_description": "Älä näytä seurauksiani tai seuraajiani",
|
||||||
"nsfw_clickthrough": "Piilota NSFW liitteet klikkauksen taakse",
|
"nsfw_clickthrough": "Piilota NSFW liitteet klikkauksen taakse",
|
||||||
|
|
|
@ -23,6 +23,7 @@ export const defaultState = {
|
||||||
autoLoad: true,
|
autoLoad: true,
|
||||||
streaming: false,
|
streaming: false,
|
||||||
hoverPreview: true,
|
hoverPreview: true,
|
||||||
|
emojiReactionsOnTimeline: true,
|
||||||
autohideFloatingPostButton: false,
|
autohideFloatingPostButton: false,
|
||||||
pauseOnUnfocused: true,
|
pauseOnUnfocused: true,
|
||||||
stopGifs: false,
|
stopGifs: false,
|
||||||
|
@ -32,7 +33,8 @@ export const defaultState = {
|
||||||
mentions: true,
|
mentions: true,
|
||||||
likes: true,
|
likes: true,
|
||||||
repeats: true,
|
repeats: true,
|
||||||
moves: true
|
moves: true,
|
||||||
|
emojiReactions: false
|
||||||
},
|
},
|
||||||
webPushNotifications: false,
|
webPushNotifications: false,
|
||||||
muteWords: [],
|
muteWords: [],
|
||||||
|
|
|
@ -81,7 +81,8 @@ const visibleNotificationTypes = (rootState) => {
|
||||||
rootState.config.notificationVisibility.mentions && 'mention',
|
rootState.config.notificationVisibility.mentions && 'mention',
|
||||||
rootState.config.notificationVisibility.repeats && 'repeat',
|
rootState.config.notificationVisibility.repeats && 'repeat',
|
||||||
rootState.config.notificationVisibility.follows && 'follow',
|
rootState.config.notificationVisibility.follows && 'follow',
|
||||||
rootState.config.notificationVisibility.moves && 'move'
|
rootState.config.notificationVisibility.moves && 'move',
|
||||||
|
rootState.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reactions'
|
||||||
].filter(_ => _)
|
].filter(_ => _)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,6 +326,10 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
|
||||||
notification.status = notification.status && addStatusToGlobalStorage(state, notification.status).item
|
notification.status = notification.status && addStatusToGlobalStorage(state, notification.status).item
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (notification.type === 'pleroma:emoji_reaction') {
|
||||||
|
dispatch('fetchEmojiReactionsBy', notification.status.id)
|
||||||
|
}
|
||||||
|
|
||||||
// Only add a new notification if we don't have one for the same action
|
// Only add a new notification if we don't have one for the same action
|
||||||
if (!state.notifications.idStore.hasOwnProperty(notification.id)) {
|
if (!state.notifications.idStore.hasOwnProperty(notification.id)) {
|
||||||
state.notifications.maxId = notification.id > state.notifications.maxId
|
state.notifications.maxId = notification.id > state.notifications.maxId
|
||||||
|
@ -358,7 +363,9 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i18nString) {
|
if (notification.type === 'pleroma:emoji_reaction') {
|
||||||
|
notifObj.body = rootGetters.i18n.t('notifications.reacted_with', [notification.emoji])
|
||||||
|
} else if (i18nString) {
|
||||||
notifObj.body = rootGetters.i18n.t('notifications.' + i18nString)
|
notifObj.body = rootGetters.i18n.t('notifications.' + i18nString)
|
||||||
} else {
|
} else {
|
||||||
notifObj.body = notification.status.text
|
notifObj.body = notification.status.text
|
||||||
|
@ -371,10 +378,10 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!notification.seen && !state.notifications.desktopNotificationSilence && visibleNotificationTypes.includes(notification.type)) {
|
if (!notification.seen && !state.notifications.desktopNotificationSilence && visibleNotificationTypes.includes(notification.type)) {
|
||||||
let notification = new window.Notification(title, notifObj)
|
let desktopNotification = new window.Notification(title, notifObj)
|
||||||
// Chrome is known for not closing notifications automatically
|
// Chrome is known for not closing notifications automatically
|
||||||
// according to MDN, anyway.
|
// according to MDN, anyway.
|
||||||
setTimeout(notification.close.bind(notification), 5000)
|
setTimeout(desktopNotification.close.bind(desktopNotification), 5000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (notification.seen) {
|
} else if (notification.seen) {
|
||||||
|
@ -537,12 +544,13 @@ export const mutations = {
|
||||||
},
|
},
|
||||||
addOwnReaction (state, { id, emoji, currentUser }) {
|
addOwnReaction (state, { id, emoji, currentUser }) {
|
||||||
const status = state.allStatusesObject[id]
|
const status = state.allStatusesObject[id]
|
||||||
const reactionIndex = findIndex(status.emoji_reactions, { emoji })
|
const reactionIndex = findIndex(status.emoji_reactions, { name: emoji })
|
||||||
const reaction = status.emoji_reactions[reactionIndex] || { emoji, count: 0, accounts: [] }
|
const reaction = status.emoji_reactions[reactionIndex] || { name: emoji, count: 0, accounts: [] }
|
||||||
|
|
||||||
const newReaction = {
|
const newReaction = {
|
||||||
...reaction,
|
...reaction,
|
||||||
count: reaction.count + 1,
|
count: reaction.count + 1,
|
||||||
|
me: true,
|
||||||
accounts: [
|
accounts: [
|
||||||
...reaction.accounts,
|
...reaction.accounts,
|
||||||
currentUser
|
currentUser
|
||||||
|
@ -558,21 +566,23 @@ export const mutations = {
|
||||||
},
|
},
|
||||||
removeOwnReaction (state, { id, emoji, currentUser }) {
|
removeOwnReaction (state, { id, emoji, currentUser }) {
|
||||||
const status = state.allStatusesObject[id]
|
const status = state.allStatusesObject[id]
|
||||||
const reactionIndex = findIndex(status.emoji_reactions, { emoji })
|
const reactionIndex = findIndex(status.emoji_reactions, { name: emoji })
|
||||||
if (reactionIndex < 0) return
|
if (reactionIndex < 0) return
|
||||||
|
|
||||||
const reaction = status.emoji_reactions[reactionIndex]
|
const reaction = status.emoji_reactions[reactionIndex]
|
||||||
|
const accounts = reaction.accounts || []
|
||||||
|
|
||||||
const newReaction = {
|
const newReaction = {
|
||||||
...reaction,
|
...reaction,
|
||||||
count: reaction.count - 1,
|
count: reaction.count - 1,
|
||||||
accounts: reaction.accounts.filter(acc => acc.id === currentUser.id)
|
me: false,
|
||||||
|
accounts: accounts.filter(acc => acc.id !== currentUser.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newReaction.count > 0) {
|
if (newReaction.count > 0) {
|
||||||
set(status.emoji_reactions, reactionIndex, newReaction)
|
set(status.emoji_reactions, reactionIndex, newReaction)
|
||||||
} else {
|
} else {
|
||||||
set(status, 'emoji_reactions', status.emoji_reactions.filter(r => r.emoji !== emoji))
|
set(status, 'emoji_reactions', status.emoji_reactions.filter(r => r.name !== emoji))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateStatusWithPoll (state, { id, poll }) {
|
updateStatusWithPoll (state, { id, poll }) {
|
||||||
|
@ -681,18 +691,22 @@ const statuses = {
|
||||||
},
|
},
|
||||||
reactWithEmoji ({ rootState, dispatch, commit }, { id, emoji }) {
|
reactWithEmoji ({ rootState, dispatch, commit }, { id, emoji }) {
|
||||||
const currentUser = rootState.users.currentUser
|
const currentUser = rootState.users.currentUser
|
||||||
|
if (!currentUser) return
|
||||||
|
|
||||||
commit('addOwnReaction', { id, emoji, currentUser })
|
commit('addOwnReaction', { id, emoji, currentUser })
|
||||||
rootState.api.backendInteractor.reactWithEmoji({ id, emoji }).then(
|
rootState.api.backendInteractor.reactWithEmoji({ id, emoji }).then(
|
||||||
status => {
|
ok => {
|
||||||
dispatch('fetchEmojiReactionsBy', id)
|
dispatch('fetchEmojiReactionsBy', id)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
unreactWithEmoji ({ rootState, dispatch, commit }, { id, emoji }) {
|
unreactWithEmoji ({ rootState, dispatch, commit }, { id, emoji }) {
|
||||||
const currentUser = rootState.users.currentUser
|
const currentUser = rootState.users.currentUser
|
||||||
|
if (!currentUser) return
|
||||||
|
|
||||||
commit('removeOwnReaction', { id, emoji, currentUser })
|
commit('removeOwnReaction', { id, emoji, currentUser })
|
||||||
rootState.api.backendInteractor.unreactWithEmoji({ id, emoji }).then(
|
rootState.api.backendInteractor.unreactWithEmoji({ id, emoji }).then(
|
||||||
status => {
|
ok => {
|
||||||
dispatch('fetchEmojiReactionsBy', id)
|
dispatch('fetchEmojiReactionsBy', id)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -74,9 +74,9 @@ const MASTODON_SEARCH_2 = `/api/v2/search`
|
||||||
const MASTODON_USER_SEARCH_URL = '/api/v1/accounts/search'
|
const MASTODON_USER_SEARCH_URL = '/api/v1/accounts/search'
|
||||||
const MASTODON_DOMAIN_BLOCKS_URL = '/api/v1/domain_blocks'
|
const MASTODON_DOMAIN_BLOCKS_URL = '/api/v1/domain_blocks'
|
||||||
const MASTODON_STREAMING = '/api/v1/streaming'
|
const MASTODON_STREAMING = '/api/v1/streaming'
|
||||||
const PLEROMA_EMOJI_REACTIONS_URL = id => `/api/v1/pleroma/statuses/${id}/emoji_reactions_by`
|
const PLEROMA_EMOJI_REACTIONS_URL = id => `/api/v1/pleroma/statuses/${id}/reactions`
|
||||||
const PLEROMA_EMOJI_REACT_URL = id => `/api/v1/pleroma/statuses/${id}/react_with_emoji`
|
const PLEROMA_EMOJI_REACT_URL = (id, emoji) => `/api/v1/pleroma/statuses/${id}/reactions/${emoji}`
|
||||||
const PLEROMA_EMOJI_UNREACT_URL = id => `/api/v1/pleroma/statuses/${id}/unreact_with_emoji`
|
const PLEROMA_EMOJI_UNREACT_URL = (id, emoji) => `/api/v1/pleroma/statuses/${id}/reactions/${emoji}`
|
||||||
|
|
||||||
const oldfetch = window.fetch
|
const oldfetch = window.fetch
|
||||||
|
|
||||||
|
@ -495,7 +495,8 @@ const fetchTimeline = ({
|
||||||
until = false,
|
until = false,
|
||||||
userId = false,
|
userId = false,
|
||||||
tag = false,
|
tag = false,
|
||||||
withMuted = false
|
withMuted = false,
|
||||||
|
withMove = false
|
||||||
}) => {
|
}) => {
|
||||||
const timelineUrls = {
|
const timelineUrls = {
|
||||||
public: MASTODON_PUBLIC_TIMELINE,
|
public: MASTODON_PUBLIC_TIMELINE,
|
||||||
|
@ -535,6 +536,9 @@ const fetchTimeline = ({
|
||||||
if (timeline === 'public' || timeline === 'publicAndExternal') {
|
if (timeline === 'public' || timeline === 'publicAndExternal') {
|
||||||
params.push(['only_media', false])
|
params.push(['only_media', false])
|
||||||
}
|
}
|
||||||
|
if (timeline === 'notifications') {
|
||||||
|
params.push(['with_move', withMove])
|
||||||
|
}
|
||||||
|
|
||||||
params.push(['count', 20])
|
params.push(['count', 20])
|
||||||
params.push(['with_muted', withMuted])
|
params.push(['with_muted', withMuted])
|
||||||
|
@ -884,25 +888,27 @@ const fetchRebloggedByUsers = ({ id }) => {
|
||||||
return promisedRequest({ url: MASTODON_STATUS_REBLOGGEDBY_URL(id) }).then((users) => users.map(parseUser))
|
return promisedRequest({ url: MASTODON_STATUS_REBLOGGEDBY_URL(id) }).then((users) => users.map(parseUser))
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchEmojiReactions = ({ id }) => {
|
const fetchEmojiReactions = ({ id, credentials }) => {
|
||||||
return promisedRequest({ url: PLEROMA_EMOJI_REACTIONS_URL(id) })
|
return promisedRequest({ url: PLEROMA_EMOJI_REACTIONS_URL(id), credentials })
|
||||||
|
.then((reactions) => reactions.map(r => {
|
||||||
|
r.accounts = r.accounts.map(parseUser)
|
||||||
|
return r
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
const reactWithEmoji = ({ id, emoji, credentials }) => {
|
const reactWithEmoji = ({ id, emoji, credentials }) => {
|
||||||
return promisedRequest({
|
return promisedRequest({
|
||||||
url: PLEROMA_EMOJI_REACT_URL(id),
|
url: PLEROMA_EMOJI_REACT_URL(id, emoji),
|
||||||
method: 'POST',
|
method: 'PUT',
|
||||||
credentials,
|
credentials
|
||||||
payload: { emoji }
|
|
||||||
}).then(parseStatus)
|
}).then(parseStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
const unreactWithEmoji = ({ id, emoji, credentials }) => {
|
const unreactWithEmoji = ({ id, emoji, credentials }) => {
|
||||||
return promisedRequest({
|
return promisedRequest({
|
||||||
url: PLEROMA_EMOJI_UNREACT_URL(id),
|
url: PLEROMA_EMOJI_UNREACT_URL(id, emoji),
|
||||||
method: 'POST',
|
method: 'DELETE',
|
||||||
credentials,
|
credentials
|
||||||
payload: { emoji }
|
|
||||||
}).then(parseStatus)
|
}).then(parseStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,8 @@ export const parseUser = (data) => {
|
||||||
output.subscribed = relationship.subscribing
|
output.subscribed = relationship.subscribing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output.allow_following_move = data.pleroma.allow_following_move
|
||||||
|
|
||||||
output.hide_follows = data.pleroma.hide_follows
|
output.hide_follows = data.pleroma.hide_follows
|
||||||
output.hide_followers = data.pleroma.hide_followers
|
output.hide_followers = data.pleroma.hide_followers
|
||||||
output.hide_follows_count = data.pleroma.hide_follows_count
|
output.hide_follows_count = data.pleroma.hide_follows_count
|
||||||
|
@ -352,6 +354,7 @@ export const parseNotification = (data) => {
|
||||||
? null
|
? null
|
||||||
: parseUser(data.target)
|
: parseUser(data.target)
|
||||||
output.from_profile = parseUser(data.account)
|
output.from_profile = parseUser(data.account)
|
||||||
|
output.emoji = data.emoji
|
||||||
} else {
|
} else {
|
||||||
const parsedNotice = parseStatus(data.notice)
|
const parsedNotice = parseStatus(data.notice)
|
||||||
output.type = data.ntype
|
output.type = data.ntype
|
||||||
|
|
|
@ -7,7 +7,8 @@ export const visibleTypes = store => ([
|
||||||
store.state.config.notificationVisibility.mentions && 'mention',
|
store.state.config.notificationVisibility.mentions && 'mention',
|
||||||
store.state.config.notificationVisibility.repeats && 'repeat',
|
store.state.config.notificationVisibility.repeats && 'repeat',
|
||||||
store.state.config.notificationVisibility.follows && 'follow',
|
store.state.config.notificationVisibility.follows && 'follow',
|
||||||
store.state.config.notificationVisibility.moves && 'move'
|
store.state.config.notificationVisibility.moves && 'move',
|
||||||
|
store.state.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reaction'
|
||||||
].filter(_ => _))
|
].filter(_ => _))
|
||||||
|
|
||||||
const sortById = (a, b) => {
|
const sortById = (a, b) => {
|
||||||
|
|
|
@ -11,9 +11,12 @@ const fetchAndUpdate = ({ store, credentials, older = false }) => {
|
||||||
const rootState = store.rootState || store.state
|
const rootState = store.rootState || store.state
|
||||||
const timelineData = rootState.statuses.notifications
|
const timelineData = rootState.statuses.notifications
|
||||||
const hideMutedPosts = getters.mergedConfig.hideMutedPosts
|
const hideMutedPosts = getters.mergedConfig.hideMutedPosts
|
||||||
|
const allowFollowingMove = rootState.users.currentUser.allow_following_move
|
||||||
|
|
||||||
args['withMuted'] = !hideMutedPosts
|
args['withMuted'] = !hideMutedPosts
|
||||||
|
|
||||||
|
args['withMove'] = !allowFollowingMove
|
||||||
|
|
||||||
args['timeline'] = 'notifications'
|
args['timeline'] = 'notifications'
|
||||||
if (older) {
|
if (older) {
|
||||||
if (timelineData.minId !== Number.POSITIVE_INFINITY) {
|
if (timelineData.minId !== Number.POSITIVE_INFINITY) {
|
||||||
|
|
|
@ -339,6 +339,12 @@
|
||||||
"css": "arrow-curved",
|
"css": "arrow-curved",
|
||||||
"code": 59426,
|
"code": 59426,
|
||||||
"src": "iconic"
|
"src": "iconic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "0ddd3e8201ccc7d41f7b7c9d27eca6c1",
|
||||||
|
"css": "link",
|
||||||
|
"code": 59427,
|
||||||
|
"src": "fontawesome"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,11 +245,12 @@ describe('Statuses module', () => {
|
||||||
it('increments count in existing reaction', () => {
|
it('increments count in existing reaction', () => {
|
||||||
const state = defaultState()
|
const state = defaultState()
|
||||||
const status = makeMockStatus({ id: '1' })
|
const status = makeMockStatus({ id: '1' })
|
||||||
status.emoji_reactions = [ { emoji: '😂', count: 1, accounts: [] } ]
|
status.emoji_reactions = [ { name: '😂', count: 1, accounts: [] } ]
|
||||||
|
|
||||||
mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
|
mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
|
||||||
mutations.addOwnReaction(state, { id: '1', emoji: '😂', currentUser: { id: 'me' } })
|
mutations.addOwnReaction(state, { id: '1', emoji: '😂', currentUser: { id: 'me' } })
|
||||||
expect(state.allStatusesObject['1'].emoji_reactions[0].count).to.eql(2)
|
expect(state.allStatusesObject['1'].emoji_reactions[0].count).to.eql(2)
|
||||||
|
expect(state.allStatusesObject['1'].emoji_reactions[0].me).to.eql(true)
|
||||||
expect(state.allStatusesObject['1'].emoji_reactions[0].accounts[0].id).to.eql('me')
|
expect(state.allStatusesObject['1'].emoji_reactions[0].accounts[0].id).to.eql('me')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -261,27 +262,29 @@ describe('Statuses module', () => {
|
||||||
mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
|
mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
|
||||||
mutations.addOwnReaction(state, { id: '1', emoji: '😂', currentUser: { id: 'me' } })
|
mutations.addOwnReaction(state, { id: '1', emoji: '😂', currentUser: { id: 'me' } })
|
||||||
expect(state.allStatusesObject['1'].emoji_reactions[0].count).to.eql(1)
|
expect(state.allStatusesObject['1'].emoji_reactions[0].count).to.eql(1)
|
||||||
|
expect(state.allStatusesObject['1'].emoji_reactions[0].me).to.eql(true)
|
||||||
expect(state.allStatusesObject['1'].emoji_reactions[0].accounts[0].id).to.eql('me')
|
expect(state.allStatusesObject['1'].emoji_reactions[0].accounts[0].id).to.eql('me')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('decreases count in existing reaction', () => {
|
it('decreases count in existing reaction', () => {
|
||||||
const state = defaultState()
|
const state = defaultState()
|
||||||
const status = makeMockStatus({ id: '1' })
|
const status = makeMockStatus({ id: '1' })
|
||||||
status.emoji_reactions = [ { emoji: '😂', count: 2, accounts: [{ id: 'me' }] } ]
|
status.emoji_reactions = [ { name: '😂', count: 2, accounts: [{ id: 'me' }] } ]
|
||||||
|
|
||||||
mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
|
mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
|
||||||
mutations.removeOwnReaction(state, { id: '1', emoji: '😂', currentUser: {} })
|
mutations.removeOwnReaction(state, { id: '1', emoji: '😂', currentUser: { id: 'me' } })
|
||||||
expect(state.allStatusesObject['1'].emoji_reactions[0].count).to.eql(1)
|
expect(state.allStatusesObject['1'].emoji_reactions[0].count).to.eql(1)
|
||||||
|
expect(state.allStatusesObject['1'].emoji_reactions[0].me).to.eql(false)
|
||||||
expect(state.allStatusesObject['1'].emoji_reactions[0].accounts).to.eql([])
|
expect(state.allStatusesObject['1'].emoji_reactions[0].accounts).to.eql([])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('removes a reaction', () => {
|
it('removes a reaction', () => {
|
||||||
const state = defaultState()
|
const state = defaultState()
|
||||||
const status = makeMockStatus({ id: '1' })
|
const status = makeMockStatus({ id: '1' })
|
||||||
status.emoji_reactions = [{ emoji: '😂', count: 1, accounts: [{ id: 'me' }] }]
|
status.emoji_reactions = [{ name: '😂', count: 1, accounts: [{ id: 'me' }] }]
|
||||||
|
|
||||||
mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
|
mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
|
||||||
mutations.removeOwnReaction(state, { id: '1', emoji: '😂', currentUser: {} })
|
mutations.removeOwnReaction(state, { id: '1', emoji: '😂', currentUser: { id: 'me' } })
|
||||||
expect(state.allStatusesObject['1'].emoji_reactions.length).to.eql(0)
|
expect(state.allStatusesObject['1'].emoji_reactions.length).to.eql(0)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue