Merge remote-tracking branch 'upstream/develop' into shigusegubu
* upstream/develop: (24 commits) link interaction avatars to the user profile Use more clear explanation in the scope notice, make sure the hide button doesn't overlap with text in notice. use backendInteractor refactor api service functions using new helper clean up update favorite number earlier update status interaction upon retweet action response sync up favoritedBy with favorite/unfavorite action do not regenerate status object reduce needless calculation Move scope visibility notice to the status form, make it dismissible Revert "eliminate expandable prop in favor of inConversation" status attention doesn’t have relationship entities make it short fix wrong inlineExpanded expanded is always false, eliminate it eliminate expandable prop in favor of inConversation fix conversationId comparision bug using integer format Display additional scope description above the status form for mobile users. Update es.json ...
This commit is contained in:
commit
0084a63e41
22 changed files with 193 additions and 113 deletions
13
src/App.scss
13
src/App.scss
|
@ -648,6 +648,19 @@ nav {
|
||||||
border-radius: var(--inputRadius, $fallback--inputRadius);
|
border-radius: var(--inputRadius, $fallback--inputRadius);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notice-dismissible {
|
||||||
|
padding-right: 4rem;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.dismiss {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: .5em;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes modal-background-fadein {
|
@keyframes modal-background-fadein {
|
||||||
from {
|
from {
|
||||||
background-color: rgba(0, 0, 0, 0);
|
background-color: rgba(0, 0, 0, 0);
|
||||||
|
|
|
@ -18,12 +18,13 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div v-if="" class="container" id="content">
|
<div class="container" id="content">
|
||||||
<div class="sidebar-flexer mobile-hidden" v-if="!isMobileLayout">
|
<div class="sidebar-flexer mobile-hidden">
|
||||||
<div class="sidebar-bounds">
|
<div class="sidebar-bounds">
|
||||||
<div class="sidebar-scroller">
|
<div class="sidebar-scroller">
|
||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
<user-panel></user-panel>
|
<user-panel></user-panel>
|
||||||
|
<div v-if="!isMobileLayout">
|
||||||
<nav-panel></nav-panel>
|
<nav-panel></nav-panel>
|
||||||
<instance-specific-panel v-if="showInstanceSpecificPanel"></instance-specific-panel>
|
<instance-specific-panel v-if="showInstanceSpecificPanel"></instance-specific-panel>
|
||||||
<features-panel v-if="!currentUser && showFeaturesPanel"></features-panel>
|
<features-panel v-if="!currentUser && showFeaturesPanel"></features-panel>
|
||||||
|
@ -33,6 +34,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div v-if="!currentUser" class="login-hint panel panel-default">
|
<div v-if="!currentUser" class="login-hint panel panel-default">
|
||||||
<router-link :to="{ name: 'login' }" class="panel-body">
|
<router-link :to="{ name: 'login' }" class="panel-body">
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||||
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
|
|
||||||
const AvatarList = {
|
const AvatarList = {
|
||||||
props: ['users'],
|
props: ['users'],
|
||||||
|
@ -9,6 +10,11 @@ const AvatarList = {
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
UserAvatar
|
UserAvatar
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
userProfileLink (user) {
|
||||||
|
return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="avatars">
|
<div class="avatars">
|
||||||
<div class="avatars-item" v-for="user in slicedUsers">
|
<router-link :to="userProfileLink(user)" class="avatars-item" v-for="user in slicedUsers">
|
||||||
<UserAvatar :user="user" class="avatar-small" />
|
<UserAvatar :user="user" class="avatar-small" />
|
||||||
</div>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
@goto="setHighlight"
|
@goto="setHighlight"
|
||||||
@toggleExpanded="toggleExpanded"
|
@toggleExpanded="toggleExpanded"
|
||||||
:key="status.id"
|
:key="status.id"
|
||||||
:inlineExpanded="collapsable"
|
:inlineExpanded="collapsable && isExpanded"
|
||||||
:statusoid="status"
|
:statusoid="status"
|
||||||
:expandable='!isExpanded'
|
:expandable='!isExpanded'
|
||||||
:focused="focused(status.id)"
|
:focused="focused(status.id)"
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
.media-modal-view {
|
.media-modal-view {
|
||||||
|
z-index: 1001;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
.modal-view-button-arrow {
|
.modal-view-button-arrow {
|
||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import PostStatusForm from '../post_status_form/post_status_form.vue'
|
import PostStatusForm from '../post_status_form/post_status_form.vue'
|
||||||
import { throttle } from 'lodash'
|
import { debounce } from 'lodash'
|
||||||
|
|
||||||
const MobilePostStatusModal = {
|
const MobilePostStatusModal = {
|
||||||
components: {
|
components: {
|
||||||
|
@ -16,11 +16,15 @@ const MobilePostStatusModal = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
window.addEventListener('scroll', this.handleScroll)
|
if (this.autohideFloatingPostButton) {
|
||||||
|
this.activateFloatingPostButtonAutohide()
|
||||||
|
}
|
||||||
window.addEventListener('resize', this.handleOSK)
|
window.addEventListener('resize', this.handleOSK)
|
||||||
},
|
},
|
||||||
destroyed () {
|
destroyed () {
|
||||||
window.removeEventListener('scroll', this.handleScroll)
|
if (this.autohideFloatingPostButton) {
|
||||||
|
this.deactivateFloatingPostButtonAutohide()
|
||||||
|
}
|
||||||
window.removeEventListener('resize', this.handleOSK)
|
window.removeEventListener('resize', this.handleOSK)
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -28,10 +32,30 @@ const MobilePostStatusModal = {
|
||||||
return this.$store.state.users.currentUser
|
return this.$store.state.users.currentUser
|
||||||
},
|
},
|
||||||
isHidden () {
|
isHidden () {
|
||||||
return this.hidden || this.inputActive
|
return this.autohideFloatingPostButton && (this.hidden || this.inputActive)
|
||||||
|
},
|
||||||
|
autohideFloatingPostButton () {
|
||||||
|
return !!this.$store.state.config.autohideFloatingPostButton
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
autohideFloatingPostButton: function (isEnabled) {
|
||||||
|
if (isEnabled) {
|
||||||
|
this.activateFloatingPostButtonAutohide()
|
||||||
|
} else {
|
||||||
|
this.deactivateFloatingPostButtonAutohide()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
activateFloatingPostButtonAutohide () {
|
||||||
|
window.addEventListener('scroll', this.handleScrollStart)
|
||||||
|
window.addEventListener('scroll', this.handleScrollEnd)
|
||||||
|
},
|
||||||
|
deactivateFloatingPostButtonAutohide () {
|
||||||
|
window.removeEventListener('scroll', this.handleScrollStart)
|
||||||
|
window.removeEventListener('scroll', this.handleScrollEnd)
|
||||||
|
},
|
||||||
openPostForm () {
|
openPostForm () {
|
||||||
this.postFormOpen = true
|
this.postFormOpen = true
|
||||||
this.hidden = true
|
this.hidden = true
|
||||||
|
@ -65,26 +89,19 @@ const MobilePostStatusModal = {
|
||||||
this.inputActive = false
|
this.inputActive = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleScroll: throttle(function () {
|
handleScrollStart: debounce(function () {
|
||||||
const scrollAmount = window.scrollY - this.oldScrollPos
|
if (window.scrollY > this.oldScrollPos) {
|
||||||
const scrollingDown = scrollAmount > 0
|
this.hidden = true
|
||||||
|
} else {
|
||||||
if (scrollingDown !== this.scrollingDown) {
|
|
||||||
this.amountScrolled = 0
|
|
||||||
this.scrollingDown = scrollingDown
|
|
||||||
if (!scrollingDown) {
|
|
||||||
this.hidden = false
|
this.hidden = false
|
||||||
}
|
}
|
||||||
} else if (scrollingDown) {
|
|
||||||
this.amountScrolled += scrollAmount
|
|
||||||
if (this.amountScrolled > 100 && !this.hidden) {
|
|
||||||
this.hidden = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.oldScrollPos = window.scrollY
|
this.oldScrollPos = window.scrollY
|
||||||
this.scrollingDown = scrollingDown
|
}, 100, {leading: true, trailing: false}),
|
||||||
}, 100)
|
|
||||||
|
handleScrollEnd: debounce(function () {
|
||||||
|
this.hidden = false
|
||||||
|
this.oldScrollPos = window.scrollY
|
||||||
|
}, 100, {leading: false, trailing: true})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -182,6 +182,9 @@ const PostStatusForm = {
|
||||||
},
|
},
|
||||||
safeDMEnabled () {
|
safeDMEnabled () {
|
||||||
return this.$store.state.instance.safeDM
|
return this.$store.state.instance.safeDM
|
||||||
|
},
|
||||||
|
hideScopeNotice () {
|
||||||
|
return this.$store.state.config.hideScopeNotice
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -336,6 +339,9 @@ const PostStatusForm = {
|
||||||
},
|
},
|
||||||
changeVis (visibility) {
|
changeVis (visibility) {
|
||||||
this.newStatus.visibility = visibility
|
this.newStatus.visibility = visibility
|
||||||
|
},
|
||||||
|
dismissScopeNotice () {
|
||||||
|
this.$store.dispatch('setOption', { name: 'hideScopeNotice', value: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,25 @@
|
||||||
class="visibility-notice">
|
class="visibility-notice">
|
||||||
<router-link :to="{ name: 'user-settings' }">{{ $t('post_status.account_not_locked_warning_link') }}</router-link>
|
<router-link :to="{ name: 'user-settings' }">{{ $t('post_status.account_not_locked_warning_link') }}</router-link>
|
||||||
</i18n>
|
</i18n>
|
||||||
<p v-if="newStatus.visibility === 'direct'" class="visibility-notice">
|
<p v-if="!hideScopeNotice && newStatus.visibility === 'public'" class="visibility-notice notice-dismissible">
|
||||||
|
<span>{{ $t('post_status.scope_notice.public') }}</span>
|
||||||
|
<a v-on:click.prevent="dismissScopeNotice()" class="button-icon dismiss">
|
||||||
|
<i class='icon-cancel'></i>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p v-else-if="!hideScopeNotice && newStatus.visibility === 'unlisted'" class="visibility-notice notice-dismissible">
|
||||||
|
<span>{{ $t('post_status.scope_notice.unlisted') }}</span>
|
||||||
|
<a v-on:click.prevent="dismissScopeNotice()" class="button-icon dismiss">
|
||||||
|
<i class='icon-cancel'></i>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p v-else-if="!hideScopeNotice && newStatus.visibility === 'private' && $store.state.users.currentUser.locked" class="visibility-notice notice-dismissible">
|
||||||
|
<span>{{ $t('post_status.scope_notice.private') }}</span>
|
||||||
|
<a v-on:click.prevent="dismissScopeNotice()" class="button-icon dismiss">
|
||||||
|
<i class='icon-cancel'></i>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p v-else-if="newStatus.visibility === 'direct'" class="visibility-notice">
|
||||||
<span v-if="safeDMEnabled">{{ $t('post_status.direct_warning_to_first_only') }}</span>
|
<span v-if="safeDMEnabled">{{ $t('post_status.direct_warning_to_first_only') }}</span>
|
||||||
<span v-else>{{ $t('post_status.direct_warning_to_all') }}</span>
|
<span v-else>{{ $t('post_status.direct_warning_to_all') }}</span>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -46,6 +46,7 @@ const settings = {
|
||||||
streamingLocal: user.streaming,
|
streamingLocal: user.streaming,
|
||||||
pauseOnUnfocusedLocal: user.pauseOnUnfocused,
|
pauseOnUnfocusedLocal: user.pauseOnUnfocused,
|
||||||
hoverPreviewLocal: user.hoverPreview,
|
hoverPreviewLocal: user.hoverPreview,
|
||||||
|
autohideFloatingPostButtonLocal: user.autohideFloatingPostButton,
|
||||||
|
|
||||||
hideMutedPostsLocal: typeof user.hideMutedPosts === 'undefined'
|
hideMutedPostsLocal: typeof user.hideMutedPosts === 'undefined'
|
||||||
? instance.hideMutedPosts
|
? instance.hideMutedPosts
|
||||||
|
@ -183,6 +184,9 @@ const settings = {
|
||||||
hoverPreviewLocal (value) {
|
hoverPreviewLocal (value) {
|
||||||
this.$store.dispatch('setOption', { name: 'hoverPreview', value })
|
this.$store.dispatch('setOption', { name: 'hoverPreview', value })
|
||||||
},
|
},
|
||||||
|
autohideFloatingPostButtonLocal (value) {
|
||||||
|
this.$store.dispatch('setOption', { name: 'autohideFloatingPostButton', value })
|
||||||
|
},
|
||||||
muteWordsString (value) {
|
muteWordsString (value) {
|
||||||
value = filter(value.split('\n'), (word) => trim(word).length > 0)
|
value = filter(value.split('\n'), (word) => trim(word).length > 0)
|
||||||
this.$store.dispatch('setOption', { name: 'muteWords', value })
|
this.$store.dispatch('setOption', { name: 'muteWords', value })
|
||||||
|
|
|
@ -122,6 +122,10 @@
|
||||||
{{$t('settings.minimal_scopes_mode')}} {{$t('settings.instance_default', { value: minimalScopesModeDefault })}}
|
{{$t('settings.minimal_scopes_mode')}} {{$t('settings.instance_default', { value: minimalScopesModeDefault })}}
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<input type="checkbox" id="autohideFloatingPostButton" v-model="autohideFloatingPostButtonLocal">
|
||||||
|
<label for="autohideFloatingPostButton">{{$t('settings.autohide_floating_post_button')}}</label>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ const Status = {
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
replying: false,
|
replying: false,
|
||||||
expanded: false,
|
|
||||||
unmuted: false,
|
unmuted: false,
|
||||||
userExpanded: false,
|
userExpanded: false,
|
||||||
preview: null,
|
preview: null,
|
||||||
|
@ -161,7 +160,7 @@ const Status = {
|
||||||
if (this.$store.state.config.replyVisibility === 'all') {
|
if (this.$store.state.config.replyVisibility === 'all') {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (this.inlineExpanded || this.expanded || this.inConversation || !this.isReply) {
|
if (this.inConversation || !this.isReply) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (this.status.user.id === this.$store.state.users.currentUser.id) {
|
if (this.status.user.id === this.$store.state.users.currentUser.id) {
|
||||||
|
@ -175,7 +174,7 @@ const Status = {
|
||||||
if (this.status.user.id === this.status.attentions[i].id) {
|
if (this.status.user.id === this.status.attentions[i].id) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (checkFollowing && this.status.attentions[i].following) {
|
if (checkFollowing && this.$store.getters.findUser(this.status.attentions[i].id).following) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (this.status.attentions[i].id === this.$store.state.users.currentUser.id) {
|
if (this.status.attentions[i].id === this.$store.state.users.currentUser.id) {
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<div class="favs-repeated-users" v-if="combinedFavsAndRepeatsUsers.length > 0 && isFocused">
|
<div class="favs-repeated-users" v-if="isFocused && combinedFavsAndRepeatsUsers.length > 0">
|
||||||
<div class="stats">
|
<div class="stats">
|
||||||
<div class="stat-count" v-if="statusFromGlobalRepository.rebloggedBy && statusFromGlobalRepository.rebloggedBy.length > 0">
|
<div class="stat-count" v-if="statusFromGlobalRepository.rebloggedBy && statusFromGlobalRepository.rebloggedBy.length > 0">
|
||||||
<a class="stat-title">{{ $t('status.repeats') }}</a>
|
<a class="stat-title">{{ $t('status.repeats') }}</a>
|
||||||
|
|
|
@ -94,6 +94,11 @@
|
||||||
"direct_warning_to_all": "This post will be visible to all the mentioned users.",
|
"direct_warning_to_all": "This post will be visible to all the mentioned users.",
|
||||||
"direct_warning_to_first_only": "This post will only be visible to the mentioned users at the beginning of the message.",
|
"direct_warning_to_first_only": "This post will only be visible to the mentioned users at the beginning of the message.",
|
||||||
"posting": "Posting",
|
"posting": "Posting",
|
||||||
|
"scope_notice": {
|
||||||
|
"public": "This post will be visible to everyone",
|
||||||
|
"private": "This post will be visible to your followers only",
|
||||||
|
"unlisted": "This post will not be visible in Public Timeline and The Whole Known Network"
|
||||||
|
},
|
||||||
"scope": {
|
"scope": {
|
||||||
"direct": "Direct - Post to mentioned users only",
|
"direct": "Direct - Post to mentioned users only",
|
||||||
"private": "Followers-only - Post to followers only",
|
"private": "Followers-only - Post to followers only",
|
||||||
|
@ -233,6 +238,7 @@
|
||||||
"reply_visibility_all": "Show all replies",
|
"reply_visibility_all": "Show all replies",
|
||||||
"reply_visibility_following": "Only show replies directed at me or users I'm following",
|
"reply_visibility_following": "Only show replies directed at me or users I'm following",
|
||||||
"reply_visibility_self": "Only show replies directed at me",
|
"reply_visibility_self": "Only show replies directed at me",
|
||||||
|
"autohide_floating_post_button": "Automatically hide New Post button (mobile)",
|
||||||
"saving_err": "Error saving settings",
|
"saving_err": "Error saving settings",
|
||||||
"saving_ok": "Settings saved",
|
"saving_ok": "Settings saved",
|
||||||
"search_user_to_block": "Search whom you want to block",
|
"search_user_to_block": "Search whom you want to block",
|
||||||
|
|
|
@ -420,6 +420,7 @@
|
||||||
"muted": "Silenciado",
|
"muted": "Silenciado",
|
||||||
"per_day": "por día",
|
"per_day": "por día",
|
||||||
"remote_follow": "Seguir",
|
"remote_follow": "Seguir",
|
||||||
|
"report": "Reportar",
|
||||||
"statuses": "Estados",
|
"statuses": "Estados",
|
||||||
"unblock": "Desbloquear",
|
"unblock": "Desbloquear",
|
||||||
"unblock_progress": "Desbloqueando...",
|
"unblock_progress": "Desbloqueando...",
|
||||||
|
@ -451,6 +452,15 @@
|
||||||
"timeline_title": "Linea temporal del usuario",
|
"timeline_title": "Linea temporal del usuario",
|
||||||
"profile_does_not_exist": "Lo sentimos, este perfil no existe.",
|
"profile_does_not_exist": "Lo sentimos, este perfil no existe.",
|
||||||
"profile_loading_error": "Lo sentimos, hubo un error al cargar este perfil."
|
"profile_loading_error": "Lo sentimos, hubo un error al cargar este perfil."
|
||||||
|
},
|
||||||
|
"user_reporting": {
|
||||||
|
"title": "Reportando a {0}",
|
||||||
|
"add_comment_description": "El informe será enviado a los moderadores de su instancia. Puedes proporcionar una explicación de por qué estás reportando esta cuenta a continuación:",
|
||||||
|
"additional_comments": "Comentarios adicionales",
|
||||||
|
"forward_description": "La cuenta es de otro servidor. ¿Enviar una copia del informe allí también?",
|
||||||
|
"forward_to": "Reenviar a {0}",
|
||||||
|
"submit": "Enviar",
|
||||||
|
"generic_error": "Se produjo un error al procesar la solicitud."
|
||||||
},
|
},
|
||||||
"who_to_follow": {
|
"who_to_follow": {
|
||||||
"more": "Más",
|
"more": "Más",
|
||||||
|
|
|
@ -42,8 +42,13 @@
|
||||||
"attachments_sensitive": "Вложения содержат чувствительный контент",
|
"attachments_sensitive": "Вложения содержат чувствительный контент",
|
||||||
"content_warning": "Тема (не обязательно)",
|
"content_warning": "Тема (не обязательно)",
|
||||||
"default": "Что нового?",
|
"default": "Что нового?",
|
||||||
"direct_warning": "Этот пост будет видет только упомянутым пользователям",
|
"direct_warning": "Этот пост будет виден только упомянутым пользователям",
|
||||||
"posting": "Отправляется",
|
"posting": "Отправляется",
|
||||||
|
"scope_notice": {
|
||||||
|
"public": "Этот пост будет виден всем",
|
||||||
|
"private": "Этот пост будет виден только вашим подписчикам",
|
||||||
|
"unlisted": "Этот пост не будет виден в публичной и федеративной ленте"
|
||||||
|
},
|
||||||
"scope": {
|
"scope": {
|
||||||
"direct": "Личное - этот пост видят только те кто в нём упомянут",
|
"direct": "Личное - этот пост видят только те кто в нём упомянут",
|
||||||
"private": "Для подписчиков - этот пост видят только подписчики",
|
"private": "Для подписчиков - этот пост видят только подписчики",
|
||||||
|
@ -152,6 +157,7 @@
|
||||||
"reply_visibility_all": "Показывать все ответы",
|
"reply_visibility_all": "Показывать все ответы",
|
||||||
"reply_visibility_following": "Показывать только ответы мне и тех на кого я подписан",
|
"reply_visibility_following": "Показывать только ответы мне и тех на кого я подписан",
|
||||||
"reply_visibility_self": "Показывать только ответы мне",
|
"reply_visibility_self": "Показывать только ответы мне",
|
||||||
|
"autohide_floating_post_button": "Автоматически скрывать кнопку постинга (в мобильной версии)",
|
||||||
"saving_err": "Не удалось сохранить настройки",
|
"saving_err": "Не удалось сохранить настройки",
|
||||||
"saving_ok": "Сохранено",
|
"saving_ok": "Сохранено",
|
||||||
"security_tab": "Безопасность",
|
"security_tab": "Безопасность",
|
||||||
|
|
|
@ -17,6 +17,7 @@ const defaultState = {
|
||||||
autoLoad: true,
|
autoLoad: true,
|
||||||
streaming: false,
|
streaming: false,
|
||||||
hoverPreview: true,
|
hoverPreview: true,
|
||||||
|
autohideFloatingPostButton: false,
|
||||||
pauseOnUnfocused: true,
|
pauseOnUnfocused: true,
|
||||||
stopGifs: false,
|
stopGifs: false,
|
||||||
replyVisibility: 'all',
|
replyVisibility: 'all',
|
||||||
|
@ -30,6 +31,7 @@ const defaultState = {
|
||||||
muteWords: [],
|
muteWords: [],
|
||||||
highlight: {},
|
highlight: {},
|
||||||
interfaceLanguage: browserLocale,
|
interfaceLanguage: browserLocale,
|
||||||
|
hideScopeNotice: false,
|
||||||
scopeCopy: undefined, // instance default
|
scopeCopy: undefined, // instance default
|
||||||
subjectLineBehavior: undefined, // instance default
|
subjectLineBehavior: undefined, // instance default
|
||||||
alwaysShowSubjectInput: undefined, // instance default
|
alwaysShowSubjectInput: undefined, // instance default
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { remove, slice, each, find, maxBy, minBy, merge, first, last, isArray, omitBy } from 'lodash'
|
import { remove, slice, each, findIndex, find, maxBy, minBy, merge, first, last, isArray, omitBy } from 'lodash'
|
||||||
import { set } from 'vue'
|
import { set } from 'vue'
|
||||||
import apiService from '../services/api/api.service.js'
|
import apiService from '../services/api/api.service.js'
|
||||||
// import parse from '../services/status_parser/status_parser.js'
|
// import parse from '../services/status_parser/status_parser.js'
|
||||||
|
@ -402,12 +402,27 @@ export const mutations = {
|
||||||
},
|
},
|
||||||
setFavorited (state, { status, value }) {
|
setFavorited (state, { status, value }) {
|
||||||
const newStatus = state.allStatusesObject[status.id]
|
const newStatus = state.allStatusesObject[status.id]
|
||||||
|
|
||||||
|
if (newStatus.favorited !== value) {
|
||||||
|
if (value) {
|
||||||
|
newStatus.fave_num++
|
||||||
|
} else {
|
||||||
|
newStatus.fave_num--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
newStatus.favorited = value
|
newStatus.favorited = value
|
||||||
},
|
},
|
||||||
setFavoritedConfirm (state, { status }) {
|
setFavoritedConfirm (state, { status, user }) {
|
||||||
const newStatus = state.allStatusesObject[status.id]
|
const newStatus = state.allStatusesObject[status.id]
|
||||||
newStatus.favorited = status.favorited
|
newStatus.favorited = status.favorited
|
||||||
newStatus.fave_num = status.fave_num
|
newStatus.fave_num = status.fave_num
|
||||||
|
const index = findIndex(newStatus.favoritedBy, { id: user.id })
|
||||||
|
if (index !== -1 && !newStatus.favorited) {
|
||||||
|
newStatus.favoritedBy.splice(index, 1)
|
||||||
|
} else if (index === -1 && newStatus.favorited) {
|
||||||
|
newStatus.favoritedBy.push(user)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setRetweeted (state, { status, value }) {
|
setRetweeted (state, { status, value }) {
|
||||||
const newStatus = state.allStatusesObject[status.id]
|
const newStatus = state.allStatusesObject[status.id]
|
||||||
|
@ -422,6 +437,17 @@ export const mutations = {
|
||||||
|
|
||||||
newStatus.repeated = value
|
newStatus.repeated = value
|
||||||
},
|
},
|
||||||
|
setRetweetedConfirm (state, { status, user }) {
|
||||||
|
const newStatus = state.allStatusesObject[status.id]
|
||||||
|
newStatus.repeated = status.repeated
|
||||||
|
newStatus.repeat_num = status.repeat_num
|
||||||
|
const index = findIndex(newStatus.rebloggedBy, { id: user.id })
|
||||||
|
if (index !== -1 && !newStatus.repeated) {
|
||||||
|
newStatus.rebloggedBy.splice(index, 1)
|
||||||
|
} else if (index === -1 && newStatus.repeated) {
|
||||||
|
newStatus.rebloggedBy.push(user)
|
||||||
|
}
|
||||||
|
},
|
||||||
setDeleted (state, { status }) {
|
setDeleted (state, { status }) {
|
||||||
const newStatus = state.allStatusesObject[status.id]
|
const newStatus = state.allStatusesObject[status.id]
|
||||||
newStatus.deleted = true
|
newStatus.deleted = true
|
||||||
|
@ -461,11 +487,9 @@ export const mutations = {
|
||||||
state.timelines[timeline].flushMarker = id
|
state.timelines[timeline].flushMarker = id
|
||||||
},
|
},
|
||||||
addFavsAndRepeats (state, { id, favoritedByUsers, rebloggedByUsers }) {
|
addFavsAndRepeats (state, { id, favoritedByUsers, rebloggedByUsers }) {
|
||||||
state.allStatusesObject[id] = {
|
const newStatus = state.allStatusesObject[id]
|
||||||
...state.allStatusesObject[id],
|
newStatus.favoritedBy = favoritedByUsers.filter(_ => _)
|
||||||
favoritedBy: favoritedByUsers,
|
newStatus.rebloggedBy = rebloggedByUsers.filter(_ => _)
|
||||||
rebloggedBy: rebloggedByUsers
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,27 +524,26 @@ const statuses = {
|
||||||
favorite ({ rootState, commit }, status) {
|
favorite ({ rootState, commit }, status) {
|
||||||
// Optimistic favoriting...
|
// Optimistic favoriting...
|
||||||
commit('setFavorited', { status, value: true })
|
commit('setFavorited', { status, value: true })
|
||||||
apiService.favorite({ id: status.id, credentials: rootState.users.currentUser.credentials })
|
rootState.api.backendInteractor.favorite(status.id)
|
||||||
.then(status => {
|
.then(status => commit('setFavoritedConfirm', { status, user: rootState.users.currentUser }))
|
||||||
commit('setFavoritedConfirm', { status })
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
unfavorite ({ rootState, commit }, status) {
|
unfavorite ({ rootState, commit }, status) {
|
||||||
// Optimistic favoriting...
|
// Optimistic unfavoriting...
|
||||||
commit('setFavorited', { status, value: false })
|
commit('setFavorited', { status, value: false })
|
||||||
apiService.unfavorite({ id: status.id, credentials: rootState.users.currentUser.credentials })
|
rootState.api.backendInteractor.unfavorite(status.id)
|
||||||
.then(status => {
|
.then(status => commit('setFavoritedConfirm', { status, user: rootState.users.currentUser }))
|
||||||
commit('setFavoritedConfirm', { status })
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
retweet ({ rootState, commit }, status) {
|
retweet ({ rootState, commit }, status) {
|
||||||
// Optimistic retweeting...
|
// Optimistic retweeting...
|
||||||
commit('setRetweeted', { status, value: true })
|
commit('setRetweeted', { status, value: true })
|
||||||
apiService.retweet({ id: status.id, credentials: rootState.users.currentUser.credentials })
|
rootState.api.backendInteractor.retweet(status.id)
|
||||||
|
.then(status => commit('setRetweetedConfirm', { status: status.retweeted_status, user: rootState.users.currentUser }))
|
||||||
},
|
},
|
||||||
unretweet ({ rootState, commit }, status) {
|
unretweet ({ rootState, commit }, status) {
|
||||||
|
// Optimistic unretweeting...
|
||||||
commit('setRetweeted', { status, value: false })
|
commit('setRetweeted', { status, value: false })
|
||||||
apiService.unretweet({ id: status.id, credentials: rootState.users.currentUser.credentials })
|
rootState.api.backendInteractor.unretweet(status.id)
|
||||||
|
.then(status => commit('setRetweetedConfirm', { status, user: rootState.users.currentUser }))
|
||||||
},
|
},
|
||||||
queueFlush ({ rootState, commit }, { timeline, id }) {
|
queueFlush ({ rootState, commit }, { timeline, id }) {
|
||||||
commit('queueFlush', { timeline, id })
|
commit('queueFlush', { timeline, id })
|
||||||
|
@ -537,14 +560,7 @@ const statuses = {
|
||||||
rootState.api.backendInteractor.fetchFavoritedByUsers(id),
|
rootState.api.backendInteractor.fetchFavoritedByUsers(id),
|
||||||
rootState.api.backendInteractor.fetchRebloggedByUsers(id)
|
rootState.api.backendInteractor.fetchRebloggedByUsers(id)
|
||||||
]).then(([favoritedByUsers, rebloggedByUsers]) =>
|
]).then(([favoritedByUsers, rebloggedByUsers]) =>
|
||||||
commit(
|
commit('addFavsAndRepeats', { id, favoritedByUsers, rebloggedByUsers })
|
||||||
'addFavsAndRepeats',
|
|
||||||
{
|
|
||||||
id,
|
|
||||||
favoritedByUsers: favoritedByUsers.filter(_ => _),
|
|
||||||
rebloggedByUsers: rebloggedByUsers.filter(_ => _)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -506,62 +506,22 @@ const verifyCredentials = (user) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const favorite = ({ id, credentials }) => {
|
const favorite = ({ id, credentials }) => {
|
||||||
return fetch(MASTODON_FAVORITE_URL(id), {
|
return promisedRequest({ url: MASTODON_FAVORITE_URL(id), method: 'POST', credentials })
|
||||||
headers: authHeaders(credentials),
|
|
||||||
method: 'POST'
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) {
|
|
||||||
return response.json()
|
|
||||||
} else {
|
|
||||||
throw new Error('Error favoriting post')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then((data) => parseStatus(data))
|
.then((data) => parseStatus(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
const unfavorite = ({ id, credentials }) => {
|
const unfavorite = ({ id, credentials }) => {
|
||||||
return fetch(MASTODON_UNFAVORITE_URL(id), {
|
return promisedRequest({ url: MASTODON_UNFAVORITE_URL(id), method: 'POST', credentials })
|
||||||
headers: authHeaders(credentials),
|
|
||||||
method: 'POST'
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) {
|
|
||||||
return response.json()
|
|
||||||
} else {
|
|
||||||
throw new Error('Error removing favorite')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then((data) => parseStatus(data))
|
.then((data) => parseStatus(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
const retweet = ({ id, credentials }) => {
|
const retweet = ({ id, credentials }) => {
|
||||||
return fetch(MASTODON_RETWEET_URL(id), {
|
return promisedRequest({ url: MASTODON_RETWEET_URL(id), method: 'POST', credentials })
|
||||||
headers: authHeaders(credentials),
|
|
||||||
method: 'POST'
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) {
|
|
||||||
return response.json()
|
|
||||||
} else {
|
|
||||||
throw new Error('Error repeating post')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then((data) => parseStatus(data))
|
.then((data) => parseStatus(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
const unretweet = ({ id, credentials }) => {
|
const unretweet = ({ id, credentials }) => {
|
||||||
return fetch(MASTODON_UNRETWEET_URL(id), {
|
return promisedRequest({ url: MASTODON_UNRETWEET_URL(id), method: 'POST', credentials })
|
||||||
headers: authHeaders(credentials),
|
|
||||||
method: 'POST'
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) {
|
|
||||||
return response.json()
|
|
||||||
} else {
|
|
||||||
throw new Error('Error removing repeat')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then((data) => parseStatus(data))
|
.then((data) => parseStatus(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,11 @@ const backendInteractorService = (credentials) => {
|
||||||
const fetchRebloggedByUsers = (id) => apiService.fetchRebloggedByUsers({id})
|
const fetchRebloggedByUsers = (id) => apiService.fetchRebloggedByUsers({id})
|
||||||
const reportUser = (params) => apiService.reportUser({credentials, ...params})
|
const reportUser = (params) => apiService.reportUser({credentials, ...params})
|
||||||
|
|
||||||
|
const favorite = (id) => apiService.favorite({id, credentials})
|
||||||
|
const unfavorite = (id) => apiService.unfavorite({id, credentials})
|
||||||
|
const retweet = (id) => apiService.retweet({id, credentials})
|
||||||
|
const unretweet = (id) => apiService.unretweet({id, credentials})
|
||||||
|
|
||||||
const backendInteractorServiceInstance = {
|
const backendInteractorServiceInstance = {
|
||||||
fetchStatus,
|
fetchStatus,
|
||||||
fetchConversation,
|
fetchConversation,
|
||||||
|
@ -161,7 +166,11 @@ const backendInteractorService = (credentials) => {
|
||||||
denyUser,
|
denyUser,
|
||||||
fetchFavoritedByUsers,
|
fetchFavoritedByUsers,
|
||||||
fetchRebloggedByUsers,
|
fetchRebloggedByUsers,
|
||||||
reportUser
|
reportUser,
|
||||||
|
favorite,
|
||||||
|
unfavorite,
|
||||||
|
retweet,
|
||||||
|
unretweet
|
||||||
}
|
}
|
||||||
|
|
||||||
return backendInteractorServiceInstance
|
return backendInteractorServiceInstance
|
||||||
|
|
|
@ -309,7 +309,7 @@ export const parseNotification = (data) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
output.created_at = new Date(data.created_at)
|
output.created_at = new Date(data.created_at)
|
||||||
output.id = data.id
|
output.id = parseInt(data.id)
|
||||||
|
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue