kopia lustrzana https://github.com/nextcloud/social
Merge pull request #1729 from nextcloud/artonge/fix/again_some_fixes
Fix blocking issuespull/1716/head
commit
6d945ff03c
|
@ -378,7 +378,7 @@ export default {
|
||||||
this.updateStatusContent()
|
this.updateStatusContent()
|
||||||
},
|
},
|
||||||
keyup(event) {
|
keyup(event) {
|
||||||
if (event.shiftKey || event.ctrlKey) {
|
if (event.ctrlKey) {
|
||||||
this.createPost(event)
|
this.createPost(event)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,10 +1,24 @@
|
||||||
<template>
|
<template>
|
||||||
<li :class="['timeline-entry', hasHeader ? 'with-header' : '']">
|
<component :is="element" class="timeline-entry" :class="{ 'notification': isNotification, 'with-header': hasHeader }">
|
||||||
<div v-if="isNotification" class="notification">
|
<div v-if="isNotification" class="notification__header">
|
||||||
<Bell :size="22" />
|
<span class="notification__summary">
|
||||||
<span class="notification-action">
|
<img :src="notification.account.avatar">
|
||||||
|
<Heart v-if="notification.type === 'favourite'" :size="16" />
|
||||||
|
<Repeat v-if="notification.type === 'reblog'" :size="16" />
|
||||||
{{ actionSummary }}
|
{{ actionSummary }}
|
||||||
</span>
|
</span>
|
||||||
|
<span class="notification__details">
|
||||||
|
<router-link :to="{ name: 'single-post', params: {
|
||||||
|
account: item.account.display_name,
|
||||||
|
id: notification.status.id,
|
||||||
|
type: 'single-post',
|
||||||
|
} }"
|
||||||
|
:data-timestamp="notification.created_at"
|
||||||
|
class="post-timestamp live-relative-timestamp"
|
||||||
|
:title="notificationFormattedDate">
|
||||||
|
{{ notificationRelativeTimestamp }}
|
||||||
|
</router-link>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<template v-else-if="isBoost">
|
<template v-else-if="isBoost">
|
||||||
<div class="container-icon-boost boost">
|
<div class="container-icon-boost boost">
|
||||||
|
@ -24,18 +38,22 @@
|
||||||
:item="item.account" />
|
:item="item.account" />
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<TimelineAvatar class="entry__avatar" :item="entryContent" />
|
<TimelineAvatar v-if="!isNotification" class="entry__avatar" :item="entryContent" />
|
||||||
<TimelinePost class="entry__content"
|
<TimelinePost class="entry__content"
|
||||||
:item="entryContent"
|
:item="entryContent"
|
||||||
:type="type" />
|
:type="type" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</li>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Bell from 'vue-material-design-icons/Bell.vue'
|
import Bell from 'vue-material-design-icons/Bell.vue'
|
||||||
|
import Repeat from 'vue-material-design-icons/Repeat.vue'
|
||||||
|
import Reply from 'vue-material-design-icons/Reply.vue'
|
||||||
|
import Heart from 'vue-material-design-icons/Heart.vue'
|
||||||
import { translate } from '@nextcloud/l10n'
|
import { translate } from '@nextcloud/l10n'
|
||||||
|
import moment from '@nextcloud/moment'
|
||||||
import TimelinePost from './TimelinePost.vue'
|
import TimelinePost from './TimelinePost.vue'
|
||||||
import TimelineAvatar from './TimelineAvatar.vue'
|
import TimelineAvatar from './TimelineAvatar.vue'
|
||||||
import UserEntry from './UserEntry.vue'
|
import UserEntry from './UserEntry.vue'
|
||||||
|
@ -48,6 +66,9 @@ export default {
|
||||||
TimelineAvatar,
|
TimelineAvatar,
|
||||||
UserEntry,
|
UserEntry,
|
||||||
Bell,
|
Bell,
|
||||||
|
Repeat,
|
||||||
|
Reply,
|
||||||
|
Heart,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
/** @type {import('vue').PropType<import('../types/Mastodon.js').Status|import('../types/Mastodon.js').Notification>} */
|
/** @type {import('vue').PropType<import('../types/Mastodon.js').Status|import('../types/Mastodon.js').Notification>} */
|
||||||
|
@ -59,6 +80,10 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
element: {
|
||||||
|
type: String,
|
||||||
|
default: 'li',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
/**
|
/**
|
||||||
|
@ -77,6 +102,14 @@ export default {
|
||||||
isNotification() {
|
isNotification() {
|
||||||
return this.item.type !== undefined
|
return this.item.type !== undefined
|
||||||
},
|
},
|
||||||
|
/** @return {string} */
|
||||||
|
notificationFormattedDate() {
|
||||||
|
return moment(this.notification.created_at).format('LLL')
|
||||||
|
},
|
||||||
|
/** @return {string} */
|
||||||
|
notificationRelativeTimestamp() {
|
||||||
|
return moment(this.notification.created_at).fromNow()
|
||||||
|
},
|
||||||
/** @return {boolean} */
|
/** @return {boolean} */
|
||||||
isBoost() {
|
isBoost() {
|
||||||
return this.status.reblog !== null
|
return this.status.reblog !== null
|
||||||
|
@ -137,21 +170,61 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification {
|
.notification {
|
||||||
display: flex;
|
border-bottom: 1px solid var(--color-border);
|
||||||
padding-left: 2rem;
|
|
||||||
gap: 0.2rem;
|
|
||||||
margin-top: 1rem;
|
|
||||||
|
|
||||||
&-action {
|
&__header {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.2rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__summary {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
grid-row: 1;
|
grid-row: 1;
|
||||||
grid-column: 2;
|
grid-column: 2;
|
||||||
color: var(--color-text-lighter);
|
color: var(--color-text-lighter);
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-right: 3px;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-top: -1px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-design-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 16px;
|
||||||
|
left: 20px;
|
||||||
|
padding: 2px;
|
||||||
|
background: var(--color-main-background);
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid var(--color-background-dark);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.bell-icon {
|
&__details a {
|
||||||
opacity: .5;
|
color: var(--color-text-lighter);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.post-header) {
|
||||||
|
.post-visibility {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-timestamp {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,16 +14,16 @@
|
||||||
</span>
|
</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<VisibilityIcon v-if="visibility"
|
|
||||||
:title="visibility.text"
|
|
||||||
class="post-visibility"
|
|
||||||
:visibility="visibility.id" />
|
|
||||||
<a :data-timestamp="timestamp"
|
<a :data-timestamp="timestamp"
|
||||||
class="post-timestamp live-relative-timestamp"
|
class="post-timestamp live-relative-timestamp"
|
||||||
:title="formattedDate"
|
:title="formattedDate"
|
||||||
@click="getSinglePostTimeline">
|
@click="getSinglePostTimeline">
|
||||||
{{ relativeTimestamp }}
|
{{ relativeTimestamp }}
|
||||||
</a>
|
</a>
|
||||||
|
<VisibilityIcon v-if="visibility"
|
||||||
|
:title="visibility.text"
|
||||||
|
class="post-visibility"
|
||||||
|
:visibility="visibility.id" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="item.content" class="post-message">
|
<div v-if="item.content" class="post-message">
|
||||||
<MessageContent :item="item" />
|
<MessageContent :item="item" />
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
<PostAttachment v-if="hasAttachments" :attachments="item.media_attachments || []" />
|
<PostAttachment v-if="hasAttachments" :attachments="item.media_attachments || []" />
|
||||||
<div v-if="$route && $route.params.type !== 'notifications' && !serverData.public" class="post-actions">
|
<div v-if="$route && $route.params.type !== 'notifications' && !serverData.public" class="post-actions">
|
||||||
<NcButton :title="t('social', 'Reply')"
|
<NcButton :title="t('social', 'Reply')"
|
||||||
type="tertiary-no-background"
|
type="tertiary"
|
||||||
@click="reply">
|
@click="reply">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<Reply :size="20" />
|
<Reply :size="20" />
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
</NcButton>
|
</NcButton>
|
||||||
<NcButton v-if="item.visibility === 'public' || item.visibility === 'unlisted'"
|
<NcButton v-if="item.visibility === 'public' || item.visibility === 'unlisted'"
|
||||||
:title="t('social', 'Boost')"
|
:title="t('social', 'Boost')"
|
||||||
type="tertiary-no-background"
|
type="tertiary"
|
||||||
@click="boost">
|
@click="boost">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<Repeat :size="20" :fill-color="isBoosted ? 'var(--color-primary)' : 'var(--color-main-text)'" />
|
<Repeat :size="20" :fill-color="isBoosted ? 'var(--color-primary)' : 'var(--color-main-text)'" />
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
</NcButton>
|
</NcButton>
|
||||||
<NcButton v-if="!isLiked"
|
<NcButton v-if="!isLiked"
|
||||||
:title="t('social', 'Like')"
|
:title="t('social', 'Like')"
|
||||||
type="tertiary-no-background"
|
type="tertiary"
|
||||||
@click="like">
|
@click="like">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<HeartOutline :size="20" />
|
<HeartOutline :size="20" />
|
||||||
|
@ -72,7 +72,7 @@
|
||||||
</NcButton>
|
</NcButton>
|
||||||
<NcButton v-if="isLiked"
|
<NcButton v-if="isLiked"
|
||||||
:title="t('social', 'Undo Like')"
|
:title="t('social', 'Undo Like')"
|
||||||
type="tertiary-no-background"
|
type="tertiary"
|
||||||
@click="like">
|
@click="like">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<Heart :size="20" :fill-color="'var(--color-error)'" />
|
<Heart :size="20" :fill-color="'var(--color-error)'" />
|
||||||
|
@ -208,24 +208,18 @@ export default {
|
||||||
getSinglePostTimeline(e) {
|
getSinglePostTimeline(e) {
|
||||||
// Display internal or external post
|
// Display internal or external post
|
||||||
if (!this.isLocal) {
|
if (!this.isLocal) {
|
||||||
// TODO - fix
|
logger.warn("Don't know what to do with posts of type " + this.type, { post: this.item })
|
||||||
if (this.type === 'Note') {
|
return
|
||||||
window.open(this.item.id)
|
|
||||||
} else if (this.type === 'Announce') {
|
|
||||||
window.open(this.item.object)
|
|
||||||
} else {
|
|
||||||
logger.warn("Don't know what to do with posts of type " + this.type, { post: this.item })
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.$router.push({
|
|
||||||
name: 'single-post',
|
|
||||||
params: {
|
|
||||||
account: this.item.account.display_name,
|
|
||||||
id: this.item.id,
|
|
||||||
type: 'single-post',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.$router.push({
|
||||||
|
name: 'single-post',
|
||||||
|
params: {
|
||||||
|
account: this.item.account.display_name,
|
||||||
|
id: this.item.id,
|
||||||
|
type: 'single-post',
|
||||||
|
},
|
||||||
|
})
|
||||||
},
|
},
|
||||||
userDisplayName(actorInfo) {
|
userDisplayName(actorInfo) {
|
||||||
return actorInfo.name !== '' ? actorInfo.name : actorInfo.preferredUsername
|
return actorInfo.name !== '' ? actorInfo.name : actorInfo.preferredUsername
|
||||||
|
@ -236,7 +230,7 @@ export default {
|
||||||
},
|
},
|
||||||
boost() {
|
boost() {
|
||||||
const params = {
|
const params = {
|
||||||
post: this.item,
|
status: this.item,
|
||||||
parentAnnounce: this.reblog,
|
parentAnnounce: this.reblog,
|
||||||
}
|
}
|
||||||
if (this.isBoosted) {
|
if (this.isBoosted) {
|
||||||
|
@ -250,7 +244,7 @@ export default {
|
||||||
},
|
},
|
||||||
like() {
|
like() {
|
||||||
const params = {
|
const params = {
|
||||||
post: this.item,
|
status: this.item,
|
||||||
parentAnnounce: this.reblog,
|
parentAnnounce: this.reblog,
|
||||||
}
|
}
|
||||||
if (this.isLiked) {
|
if (this.isLiked) {
|
||||||
|
@ -330,6 +324,11 @@ export default {
|
||||||
margin-left: -13px;
|
margin-left: -13px;
|
||||||
height: 44px;
|
height: 44px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
margin: 4px;
|
||||||
|
|
||||||
|
.button-vue:hover {
|
||||||
|
background: var(--color-background-dark);
|
||||||
|
}
|
||||||
|
|
||||||
.post-actions-more {
|
.post-actions-more {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
@ -33,13 +33,17 @@ import logger from '../services/logger.js'
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
/**
|
/**
|
||||||
* @type {Object<string, import('../types/Mastodon.js').Status>} timeline - The posts' collection
|
* @type {Object<string, import('../types/Mastodon.js').Status>} List of locally known statuses
|
||||||
*/
|
*/
|
||||||
timeline: {},
|
statuses: {},
|
||||||
/**
|
/**
|
||||||
* @type {Object<string, import('../types/Mastodon.js').Status>} timeline - The parents posts' collection
|
* @type {string[]} timeline - The statuses' collection
|
||||||
*/
|
*/
|
||||||
parentsTimeline: {},
|
timeline: [],
|
||||||
|
/**
|
||||||
|
* @type {string[]} parentsTimeline - The parents statuses' collection
|
||||||
|
*/
|
||||||
|
parentsTimeline: [],
|
||||||
/**
|
/**
|
||||||
* @type {string} type - Timeline's type: 'home', 'single-post',...
|
* @type {string} type - Timeline's type: 'home', 'single-post',...
|
||||||
*/
|
*/
|
||||||
|
@ -49,6 +53,7 @@ const state = {
|
||||||
* @property {string} params.account ???
|
* @property {string} params.account ???
|
||||||
* @property {string} params.id
|
* @property {string} params.id
|
||||||
* @property {string} params.type ???
|
* @property {string} params.type ???
|
||||||
|
* @property {string?} params.singlePost ???
|
||||||
*/
|
*/
|
||||||
params: {},
|
params: {},
|
||||||
/**
|
/**
|
||||||
|
@ -66,28 +71,63 @@ const state = {
|
||||||
|
|
||||||
/** @type {import('vuex').MutationTree<state>} */
|
/** @type {import('vuex').MutationTree<state>} */
|
||||||
const mutations = {
|
const mutations = {
|
||||||
|
/**
|
||||||
|
* @param state
|
||||||
|
* @param {import ('../types/Mastodon.js').Status} status
|
||||||
|
*/
|
||||||
|
addToStatuses(state, status) {
|
||||||
|
Vue.set(state.statuses, status.id, status)
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* @param state
|
* @param state
|
||||||
* @param {import ('../types/Mastodon.js').Status[]|import('../types/Mastodon.js').Context} data
|
* @param {import ('../types/Mastodon.js').Status[]|import('../types/Mastodon.js').Context} data
|
||||||
*/
|
*/
|
||||||
addToTimeline(state, data) {
|
addToTimeline(state, data) {
|
||||||
if (Array.isArray(data)) {
|
if (Array.isArray(data)) {
|
||||||
data.forEach((post) => Vue.set(state.timeline, post.id, post))
|
data.forEach(status => Vue.set(state.statuses, status.id, status))
|
||||||
|
data
|
||||||
|
.filter(status => state.timeline.indexOf(status.id) === -1)
|
||||||
|
.forEach(status => state.timeline.push(status.id))
|
||||||
} else {
|
} else {
|
||||||
data.descendants.forEach((post) => Vue.set(state.timeline, post.id, post))
|
data.descendants.forEach(status => Vue.set(state.statuses, status.id, status))
|
||||||
data.ancestors.forEach((post) => Vue.set(state.parentsTimeline, post.id, post))
|
data.ancestors.forEach(status => Vue.set(state.statuses, status.id, status))
|
||||||
|
|
||||||
|
data.descendants
|
||||||
|
.filter(status => state.timeline.indexOf(status.id) === -1)
|
||||||
|
.forEach(status => state.timeline.push(status.id))
|
||||||
|
data.ancestors
|
||||||
|
.filter(status => state.parentsTimeline.indexOf(status.id) === -1)
|
||||||
|
.forEach(status => state.parentsTimeline.push(status.id))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param state
|
* @param state
|
||||||
* @param {import('../types/Mastodon.js').Status} post
|
* @param {import ('../types/Mastodon.js').Status[]} data
|
||||||
*/
|
*/
|
||||||
removePost(state, post) {
|
updateInTimelines(state, data) {
|
||||||
Vue.delete(state.timeline, post.id)
|
data.forEach((status) => {
|
||||||
|
if (state.statuses[status.id] !== undefined) {
|
||||||
|
Vue.set(state.statuses, status.id, status)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @param state
|
||||||
|
* @param {import('../types/Mastodon.js').Status} status
|
||||||
|
*/
|
||||||
|
removeStatusf(state, status) {
|
||||||
|
const timelineIndex = state.timeline.indexOf(status.id)
|
||||||
|
if (timelineIndex !== -1) {
|
||||||
|
state.timeline.splice(timelineIndex, 1)
|
||||||
|
}
|
||||||
|
const parentsTimelineIndex = state.parentsTimeline.indexOf(status.id)
|
||||||
|
if (timelineIndex !== -1) {
|
||||||
|
state.parentsTimeline.splice(parentsTimelineIndex, 1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
resetTimeline(state) {
|
resetTimeline(state) {
|
||||||
state.timeline = {}
|
state.timeline = []
|
||||||
state.parentsTimeline = {}
|
state.parentsTimeline = []
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param state
|
* @param state
|
||||||
|
@ -116,53 +156,41 @@ const mutations = {
|
||||||
/**
|
/**
|
||||||
* @param state
|
* @param state
|
||||||
* @param {object} root0
|
* @param {object} root0
|
||||||
* @param {import('../types/Mastodon.js').Status} root0.post
|
* @param {import('../types/Mastodon.js').Status} root0.status
|
||||||
*/
|
*/
|
||||||
likePost(state, { post }) {
|
likeStatus(state, { status }) {
|
||||||
if (state.timeline[post.id] !== undefined) {
|
if (state.statuses[status.id] !== undefined) {
|
||||||
Vue.set(state.timeline[post.id], 'favourited', true)
|
Vue.set(state.statuses[status.id], 'favourited', true)
|
||||||
}
|
|
||||||
if (post.reblog !== null && state.timeline[post.reblog.id] !== undefined) {
|
|
||||||
Vue.set(state.timeline[post.reblog.id], 'favourited', true)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param state
|
* @param state
|
||||||
* @param {object} root0
|
* @param {object} root0
|
||||||
* @param {import('../types/Mastodon.js').Status} root0.post
|
* @param {import('../types/Mastodon.js').Status} root0.status
|
||||||
*/
|
*/
|
||||||
unlikePost(state, { post }) {
|
unlikeStatus(state, { status }) {
|
||||||
if (state.timeline[post.id] !== undefined) {
|
if (state.statuses[status.id] !== undefined) {
|
||||||
Vue.set(state.timeline[post.id], 'favourited', false)
|
Vue.set(state.statuses[status.id], 'favourited', false)
|
||||||
}
|
|
||||||
if (post.reblog !== null && state.timeline[post.reblog.id] !== undefined) {
|
|
||||||
Vue.set(state.timeline[post.reblog.id], 'favourited', false)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param state
|
* @param state
|
||||||
* @param {object} root0
|
* @param {object} root0
|
||||||
* @param {import('../types/Mastodon.js').Status} root0.post
|
* @param {import('../types/Mastodon.js').Status} root0.status
|
||||||
*/
|
*/
|
||||||
boostPost(state, { post }) {
|
boostStatus(state, { status }) {
|
||||||
if (state.timeline[post.id] !== undefined) {
|
if (state.statuses[status.id] !== undefined) {
|
||||||
Vue.set(state.timeline[post.id], 'reblogged', true)
|
Vue.set(state.statuses[status.id], 'reblogged', true)
|
||||||
}
|
|
||||||
if (post.reblog !== null && state.timeline[post.reblog.id] !== undefined) {
|
|
||||||
Vue.set(state.timeline[post.reblog.id], 'reblogged', true)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param state
|
* @param state
|
||||||
* @param {object} root0
|
* @param {object} root0
|
||||||
* @param {import('../types/Mastodon.js').Status} root0.post
|
* @param {import('../types/Mastodon.js').Status} root0.status
|
||||||
*/
|
*/
|
||||||
unboostPost(state, { post }) {
|
unboostStatus(state, { status }) {
|
||||||
if (state.timeline[post.id] !== undefined) {
|
if (state.statuses[status.id] !== undefined) {
|
||||||
Vue.set(state.timeline[post.id], 'reblogged', false)
|
Vue.set(state.statuses[status.id], 'reblogged', false)
|
||||||
}
|
|
||||||
if (post.reblog !== null && state.timeline[post.reblog.id] !== undefined) {
|
|
||||||
Vue.set(state.timeline[post.reblog.id], 'reblogged', false)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -173,23 +201,24 @@ const getters = {
|
||||||
return state.composerDisplayStatus
|
return state.composerDisplayStatus
|
||||||
},
|
},
|
||||||
getTimeline(state) {
|
getTimeline(state) {
|
||||||
return Object.values(state.timeline).sort(function(a, b) {
|
return state.timeline
|
||||||
return new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
|
.map(statusId => state.statuses[statusId])
|
||||||
})
|
.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
|
||||||
},
|
},
|
||||||
getParentsTimeline(state) {
|
getParentsTimeline(state) {
|
||||||
return Object.values(state.parentsTimeline).sort(function(a, b) {
|
return state.parentsTimeline
|
||||||
return new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
|
.map(statusId => state.statuses[statusId])
|
||||||
})
|
.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
|
||||||
|
},
|
||||||
|
getSinglePost(state) {
|
||||||
|
return state.statuses[state.params.singlePost]
|
||||||
},
|
},
|
||||||
getPostFromTimeline(state) {
|
getPostFromTimeline(state) {
|
||||||
return (postId) => {
|
return (/** @type {string} */ statusId) => {
|
||||||
if (state.timeline[postId] !== undefined) {
|
if (state.statuses[statusId] !== undefined) {
|
||||||
return state.timeline[postId]
|
return state.statuses[statusId]
|
||||||
} else if (state.parentsTimeline[postId] !== undefined) {
|
|
||||||
return state.parentsTimeline[postId]
|
|
||||||
} else {
|
} else {
|
||||||
logger.warn('Could not find post in timeline', { postId })
|
logger.warn('Could not find status in timeline', { statusId })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -234,108 +263,108 @@ const actions = {
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param context
|
* @param context
|
||||||
* @param {import('../types/Mastodon.js').Status} post
|
* @param {import('../types/Mastodon.js').Status} status
|
||||||
*/
|
*/
|
||||||
async post(context, post) {
|
async post(context, status) {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.post(generateUrl('apps/social/api/v1/statuses'), post)
|
const { data } = await axios.post(generateUrl('apps/social/api/v1/statuses'), status)
|
||||||
logger.info('Post created', data.id)
|
logger.info('Post created', data.id)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showError('Failed to create a post')
|
showError('Failed to create a status')
|
||||||
logger.error('Failed to create a post', { error })
|
logger.error('Failed to create a status', { error })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param context
|
* @param context
|
||||||
* @param {import('../types/Mastodon.js').Status} post
|
* @param {import('../types/Mastodon.js').Status} status
|
||||||
*/
|
*/
|
||||||
async postDelete(context, post) {
|
async postDelete(context, status) {
|
||||||
try {
|
try {
|
||||||
context.commit('removePost', post)
|
context.commit('removeStatusf', status)
|
||||||
const response = await axios.delete(generateUrl(`apps/social/api/v1/post?id=${post.uri}`))
|
const response = await axios.delete(generateUrl(`apps/social/api/v1/post?id=${status.uri}`))
|
||||||
logger.info('Post deleted with token ' + response.data.result.token)
|
logger.info('Post deleted with token ' + response.data.result.token)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
context.commit('addToTimeline', [post])
|
context.commit('updateInTimelines', [status])
|
||||||
showError('Failed to delete the post')
|
showError('Failed to delete the status')
|
||||||
logger.error('Failed to delete the post', { error })
|
logger.error('Failed to delete the status', { error })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param context
|
* @param context
|
||||||
* @param {object} root0
|
* @param {object} root0
|
||||||
* @param {import('../types/Mastodon.js').Status} root0.post
|
* @param {import('../types/Mastodon.js').Status} root0.status
|
||||||
*/
|
*/
|
||||||
async postLike(context, { post }) {
|
async postLike(context, { status }) {
|
||||||
try {
|
try {
|
||||||
context.commit('likePost', { post })
|
context.commit('likeStatus', { status })
|
||||||
const response = await axios.post(generateUrl(`apps/social/api/v1/statuses/${post.id}/favourite`))
|
const response = await axios.post(generateUrl(`apps/social/api/v1/statuses/${status.id}/favourite`))
|
||||||
logger.info('Post liked')
|
logger.info('Post liked')
|
||||||
context.commit('addToTimeline', [response.data])
|
context.commit('updateInTimelines', [response.data])
|
||||||
return response
|
return response
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
context.commit('unlikePost', { post })
|
context.commit('unlikeStatus', { status })
|
||||||
showError('Failed to like post')
|
showError('Failed to like status')
|
||||||
logger.error('Failed to like post', { error })
|
logger.error('Failed to like status', { error })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param context
|
* @param context
|
||||||
* @param {object} root0
|
* @param {object} root0
|
||||||
* @param {import('../types/Mastodon.js').Status} root0.post
|
* @param {import('../types/Mastodon.js').Status} root0.status
|
||||||
*/
|
*/
|
||||||
async postUnlike(context, { post }) {
|
async postUnlike(context, { status }) {
|
||||||
try {
|
try {
|
||||||
// Remove post from list if we are in the 'liked' timeline
|
// Remove status from list if we are in the 'liked' timeline
|
||||||
if (state.type === 'liked') {
|
if (state.type === 'liked') {
|
||||||
context.commit('removePost', post)
|
context.commit('removeStatusf', status)
|
||||||
}
|
}
|
||||||
context.commit('unlikePost', { post })
|
context.commit('unlikeStatus', { status })
|
||||||
const response = await axios.post(generateUrl(`apps/social/api/v1/statuses/${post.id}/unfavourite`))
|
const response = await axios.post(generateUrl(`apps/social/api/v1/statuses/${status.id}/unfavourite`))
|
||||||
logger.info('Post unliked')
|
logger.info('Post unliked')
|
||||||
context.commit('addToTimeline', [response.data])
|
context.commit('updateInTimelines', [response.data])
|
||||||
return response
|
return response
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Readd post from list if we are in the 'liked' timeline
|
// Readd status from list if we are in the 'liked' timeline
|
||||||
if (state.type === 'liked') {
|
if (state.type === 'liked') {
|
||||||
context.commit('addToTimeline', [post])
|
context.commit('addToTimeline', [status])
|
||||||
}
|
}
|
||||||
context.commit('likePost', { post })
|
context.commit('likeStatus', { status })
|
||||||
showError('Failed to unlike post')
|
showError('Failed to unlike status')
|
||||||
logger.error('Failed to unlike post', { error })
|
logger.error('Failed to unlike status', { error })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param context
|
* @param context
|
||||||
* @param {object} root0
|
* @param {object} root0
|
||||||
* @param {import('../types/Mastodon.js').Status} root0.post
|
* @param {import('../types/Mastodon.js').Status} root0.status
|
||||||
*/
|
*/
|
||||||
async postBoost(context, { post }) {
|
async postBoost(context, { status }) {
|
||||||
try {
|
try {
|
||||||
context.commit('boostPost', { post })
|
context.commit('boostStatus', { status })
|
||||||
const response = await axios.post(generateUrl(`apps/social/api/v1/statuses/${post.id}/reblog`))
|
const response = await axios.post(generateUrl(`apps/social/api/v1/statuses/${status.id}/reblog`))
|
||||||
logger.info('Post boosted')
|
logger.info('Post boosted')
|
||||||
context.commit('addToTimeline', [response.data])
|
context.commit('updateInTimelines', [response.data])
|
||||||
return response
|
return response
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
context.commit('unboostPost', { post })
|
context.commit('unboostStatus', { status })
|
||||||
showError('Failed to create a boost post')
|
showError('Failed to create a boost status')
|
||||||
logger.error('Failed to create a boost post', { error })
|
logger.error('Failed to create a boost status', { error })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param context
|
* @param context
|
||||||
* @param {object} root0
|
* @param {object} root0
|
||||||
* @param {import('../types/Mastodon.js').Status} root0.post
|
* @param {import('../types/Mastodon.js').Status} root0.status
|
||||||
*/
|
*/
|
||||||
async postUnBoost(context, { post }) {
|
async postUnBoost(context, { status }) {
|
||||||
try {
|
try {
|
||||||
context.commit('unboostPost', { post })
|
context.commit('unboostStatus', { status })
|
||||||
const response = await axios.post(generateUrl(`apps/social/api/v1/statuses/${post.id}/unreblog`))
|
const response = await axios.post(generateUrl(`apps/social/api/v1/statuses/${status.id}/unreblog`))
|
||||||
logger.info('Boost deleted')
|
logger.info('Boost deleted')
|
||||||
context.commit('addToTimeline', [response.data])
|
context.commit('updateInTimelines', [response.data])
|
||||||
return response
|
return response
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
context.commit('boostPost', { post })
|
context.commit('boostStatus', { status })
|
||||||
showError('Failed to delete the boost')
|
showError('Failed to delete the boost')
|
||||||
logger.error('Failed to delete the boost', { error })
|
logger.error('Failed to delete the boost', { error })
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<Composer v-if="type !== 'notifications' && type !== 'single-post'" :default-visibility="type === 'direct' ? 'direct' : undefined" />
|
<Composer v-if="type !== 'notifications' && type !== 'single-post'" :default-visibility="type === 'direct' ? 'direct' : undefined" />
|
||||||
|
|
||||||
<h2 v-if="type === 'tags'">
|
<h2 v-if="type === 'tags'">
|
||||||
#{{ $route.params.tag }}
|
#{{ $route.params.tag }}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
|
<h2 v-if="type === 'notifications'">
|
||||||
|
{{ t('social', 'Notifications') }}
|
||||||
|
</h2>
|
||||||
|
|
||||||
<TimelineList :type="type" />
|
<TimelineList :type="type" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -7,8 +7,9 @@
|
||||||
:reverse-order="true" />
|
:reverse-order="true" />
|
||||||
<TimelineEntry ref="mainPost"
|
<TimelineEntry ref="mainPost"
|
||||||
class="main-post"
|
class="main-post"
|
||||||
:item="mainPost"
|
:item="singlePost"
|
||||||
type="single-post" />
|
type="single-post"
|
||||||
|
element="div" />
|
||||||
<TimelineList v-if="timeline" class="descendants" :type="$route.params.type" />
|
<TimelineList v-if="timeline" class="descendants" :type="$route.params.type" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -36,11 +37,14 @@ export default {
|
||||||
],
|
],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
mainPost: {},
|
|
||||||
uid: this.$route.params.account,
|
uid: this.$route.params.account,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
/** @return {Status?} */
|
||||||
|
singlePost() {
|
||||||
|
return this.$store.getters.getSinglePost
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* @description Tells whether Composer shall be displayed or not
|
* @description Tells whether Composer shall be displayed or not
|
||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
|
@ -79,15 +83,17 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async beforeMount() {
|
async beforeMount() {
|
||||||
this.mainPost = this.$store.getters.getPostFromTimeline(this.$route.params.id) || loadState('social', 'item')
|
const singlePost = this.$store.getters.getPostFromTimeline(this.$route.params.id) || loadState('social', 'item')
|
||||||
|
|
||||||
// Fetch single post timeline
|
// Fetch single post timeline
|
||||||
|
this.$store.commit('addToStatuses', singlePost)
|
||||||
this.$store.dispatch('changeTimelineType', {
|
this.$store.dispatch('changeTimelineType', {
|
||||||
type: 'single-post',
|
type: 'single-post',
|
||||||
params: {
|
params: {
|
||||||
account: this.account,
|
account: this.account,
|
||||||
id: this.$route.params.id,
|
id: this.$route.params.id,
|
||||||
type: 'single-post',
|
type: 'single-post',
|
||||||
|
singlePost: this.$route.params.id || loadState('social', 'item').id,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue