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:
Henry Jameson 2019-05-09 22:04:17 +03:00
commit 0084a63e41
22 changed files with 193 additions and 113 deletions

View file

@ -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);

View file

@ -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">

View file

@ -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)
}
} }
} }

View file

@ -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>

View file

@ -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)"

View file

@ -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;

View file

@ -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})
} }
} }

View file

@ -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 })
} }
} }
} }

View file

@ -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>

View file

@ -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 })

View file

@ -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>

View file

@ -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) {

View file

@ -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>

View file

@ -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",

View file

@ -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",

View file

@ -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": "Безопасность",

View file

@ -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

View file

@ -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(_ => _)
}
)
) )
} }
}, },

View file

@ -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))
} }

View file

@ -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

View file

@ -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
} }