#468 - show pinned timeline and add pinned label to the status

This commit is contained in:
dave 2019-04-04 15:10:34 -04:00 committed by taehoon
parent e28b19645a
commit 2c89d49a3d
11 changed files with 69 additions and 18 deletions

View file

@ -41,7 +41,8 @@ const conversation = {
props: [
'statusoid',
'collapsable',
'isPage'
'isPage',
'pinned'
],
created () {
if (this.isPage) {

View file

@ -13,6 +13,7 @@
:key="status.id"
:inlineExpanded="collapsable && isExpanded"
:statusoid="status"
:pinned="pinned"
:expandable='!isExpanded'
:focused="focused(status.id)"
:inConversation="isExpanded"

View file

@ -26,7 +26,8 @@ const Status = {
'replies',
'isPreview',
'noHeading',
'inlineExpanded'
'inlineExpanded',
'pinned'
],
data () {
return {

View file

@ -12,6 +12,13 @@
</div>
</template>
<template v-else>
<div v-if="pinned" class="status-pin">
<i class="fa icon-pin faint"></i>
<span class="faint">Pinned</span>
<div class="button-icon button-action-icon" v-if="status.pinned && ownStatus" @click.prevent="unpinStatus" title="Unpin">
<i class="fa icon-cancel"></i>
</div>
</div>
<div v-if="retweet && !noHeading && !inConversation" :class="[repeaterClass, { highlighted: repeaterStyle }]" :style="[repeaterStyle]" class="media container retweet-info">
<UserAvatar class="media-left" v-if="retweet" :betterShadow="betterShadow" :user="statusoid.user"/>
<div class="media-body faint">
@ -55,9 +62,6 @@
<div class="button-icon button-action-icon" v-if="!status.pinned && ownStatus" @click.prevent="pinStatus" title="Pin">
<i class="fa icon-pin"></i>
</div>
<div class="button-icon button-action-icon" v-if="status.pinned && ownStatus" @click.prevent="unpinStatus" title="Unpin">
<i class="fa icon-cancel"></i>
</div>
<div class="button-icon button-action-icon" v-if="expandable && !isPreview" @click.prevent="toggleExpanded" title="Expand">
<i class="button-icon icon-plus-squared"></i>
</div>
@ -205,6 +209,13 @@ $status-margin: 0.75em;
max-width: 100%;
}
.status-pin {
padding: 0.75em 0.75em 0;
display: flex;
align-items: center;
justify-content: flex-end;
}
.status-preview {
position: absolute;
max-width: 95%;

View file

@ -11,7 +11,8 @@ const Timeline = {
'userId',
'tag',
'embedded',
'count'
'count',
'noLoadMore'
],
data () {
return {

View file

@ -21,11 +21,12 @@
class="status-fadein"
:key="status.id"
:statusoid="status"
:pinned="timelineName === 'pinned'"
:collapsable="true"
/>
</div>
</div>
<div :class="classes.footer">
<div :class="classes.footer" v-if="!noLoadMore">
<div v-if="count===0" class="new-status-notification text-center panel-footer faint">
{{$t('timeline.no_statuses')}}
</div>

View file

@ -40,6 +40,9 @@ const UserProfile = {
timeline () {
return this.$store.state.statuses.timelines.user
},
pinned () {
return this.$store.state.statuses.timelines.pinned
},
favorites () {
return this.$store.state.statuses.timelines.favorites
},
@ -91,6 +94,7 @@ const UserProfile = {
fetchTimelines () {
const userId = this.userId
this.$store.dispatch('startFetchingTimeline', { timeline: 'user', userId })
this.$store.dispatch('startFetchingTimeline', { timeline: 'pinned', userId })
this.$store.dispatch('startFetchingTimeline', { timeline: 'media', userId })
if (this.isUs) {
this.$store.dispatch('startFetchingTimeline', { timeline: 'favorites', userId })
@ -98,6 +102,7 @@ const UserProfile = {
},
cleanUp () {
this.$store.dispatch('stopFetching', 'user')
this.$store.dispatch('stopFetching', 'pinned')
this.$store.dispatch('stopFetching', 'favorites')
this.$store.dispatch('stopFetching', 'media')
this.$store.commit('clearTimeline', { timeline: 'user' })

View file

@ -3,16 +3,25 @@
<div v-if="user" class="user-profile panel panel-default">
<UserCard :user="user" :switcher="true" :selected="timeline.viewing" rounded="top"/>
<tab-switcher :renderOnlyFocused="true" ref="tabSwitcher">
<Timeline
:label="$t('user_card.statuses')"
:disabled="!user.statuses_count"
:count="user.statuses_count"
:embedded="true"
:title="$t('user_profile.timeline_title')"
:timeline="timeline"
:timeline-name="'user'"
:user-id="userId"
/>
<div :label="$t('user_card.statuses')" :disabled="!user.statuses_count">
<Timeline
:count="user.statuses_count"
:embedded="true"
:title="$t('user_profile.timeline_title')"
:timeline="pinned"
:timeline-name="'pinned'"
:user-id="userId"
:no-load-more="true"
/>
<Timeline
:count="user.statuses_count"
:embedded="true"
:title="$t('user_profile.timeline_title')"
:timeline="timeline"
:timeline-name="'user'"
:user-id="userId"
/>
</div>
<div :label="$t('user_card.followees')" v-if="followsTabVisible" :disabled="!user.friends_count">
<FriendList :userId="userId">
<template slot="item" slot-scope="{item}">

View file

@ -47,7 +47,8 @@ export const defaultState = () => ({
publicAndExternal: emptyTl(),
friends: emptyTl(),
tag: emptyTl(),
dms: emptyTl()
dms: emptyTl(),
pinned: emptyTl()
}
})

View file

@ -506,6 +506,19 @@ const fetchTimeline = ({timeline, credentials, since = false, until = false, use
.then((data) => data.map(isNotifications ? parseNotification : parseStatus))
}
const fetchPinnedStatuses = ({ id, credentials }) => {
const url = MASTODON_USER_TIMELINE_URL(id) + '?pinned=true'
return fetch(url, { headers: authHeaders(credentials) })
.then((data) => {
if (data.ok) {
return data
}
throw new Error('Error fetching pinned timeline', data)
})
.then((data) => data.json())
.then((data) => data.map(parseStatus))
}
const verifyCredentials = (user) => {
return fetch(LOGIN_URL, {
method: 'POST',
@ -726,6 +739,7 @@ const reportUser = ({credentials, userId, statusIds, comment, forward}) => {
const apiService = {
verifyCredentials,
fetchTimeline,
fetchPinnedStatuses,
fetchConversation,
fetchStatus,
fetchFriends,

View file

@ -16,6 +16,12 @@ const update = ({store, statuses, timeline, showImmediately, userId}) => {
}
const fetchAndUpdate = ({store, credentials, timeline = 'friends', older = false, showImmediately = false, userId = false, tag = false, until}) => {
if (timeline === 'pinned') {
return apiService.fetchPinnedStatuses({ id: userId, credentials })
.then(statuses => {
update({ store, statuses, timeline, showImmediately, userId })
})
}
const args = { timeline, credentials }
const rootState = store.rootState || store.state
const timelineData = rootState.statuses.timelines[camelCase(timeline)]