#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: [ props: [
'statusoid', 'statusoid',
'collapsable', 'collapsable',
'isPage' 'isPage',
'pinned'
], ],
created () { created () {
if (this.isPage) { if (this.isPage) {

View file

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

View file

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

View file

@ -12,6 +12,13 @@
</div> </div>
</template> </template>
<template v-else> <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"> <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"/> <UserAvatar class="media-left" v-if="retweet" :betterShadow="betterShadow" :user="statusoid.user"/>
<div class="media-body faint"> <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"> <div class="button-icon button-action-icon" v-if="!status.pinned && ownStatus" @click.prevent="pinStatus" title="Pin">
<i class="fa icon-pin"></i> <i class="fa icon-pin"></i>
</div> </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"> <div class="button-icon button-action-icon" v-if="expandable && !isPreview" @click.prevent="toggleExpanded" title="Expand">
<i class="button-icon icon-plus-squared"></i> <i class="button-icon icon-plus-squared"></i>
</div> </div>
@ -205,6 +209,13 @@ $status-margin: 0.75em;
max-width: 100%; max-width: 100%;
} }
.status-pin {
padding: 0.75em 0.75em 0;
display: flex;
align-items: center;
justify-content: flex-end;
}
.status-preview { .status-preview {
position: absolute; position: absolute;
max-width: 95%; max-width: 95%;

View file

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

View file

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

View file

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

View file

@ -3,9 +3,17 @@
<div v-if="user" class="user-profile panel panel-default"> <div v-if="user" class="user-profile panel panel-default">
<UserCard :user="user" :switcher="true" :selected="timeline.viewing" rounded="top"/> <UserCard :user="user" :switcher="true" :selected="timeline.viewing" rounded="top"/>
<tab-switcher :renderOnlyFocused="true" ref="tabSwitcher"> <tab-switcher :renderOnlyFocused="true" ref="tabSwitcher">
<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 <Timeline
:label="$t('user_card.statuses')"
:disabled="!user.statuses_count"
:count="user.statuses_count" :count="user.statuses_count"
:embedded="true" :embedded="true"
:title="$t('user_profile.timeline_title')" :title="$t('user_profile.timeline_title')"
@ -13,6 +21,7 @@
:timeline-name="'user'" :timeline-name="'user'"
:user-id="userId" :user-id="userId"
/> />
</div>
<div :label="$t('user_card.followees')" v-if="followsTabVisible" :disabled="!user.friends_count"> <div :label="$t('user_card.followees')" v-if="followsTabVisible" :disabled="!user.friends_count">
<FriendList :userId="userId"> <FriendList :userId="userId">
<template slot="item" slot-scope="{item}"> <template slot="item" slot-scope="{item}">

View file

@ -47,7 +47,8 @@ export const defaultState = () => ({
publicAndExternal: emptyTl(), publicAndExternal: emptyTl(),
friends: emptyTl(), friends: emptyTl(),
tag: 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)) .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) => { const verifyCredentials = (user) => {
return fetch(LOGIN_URL, { return fetch(LOGIN_URL, {
method: 'POST', method: 'POST',
@ -726,6 +739,7 @@ const reportUser = ({credentials, userId, statusIds, comment, forward}) => {
const apiService = { const apiService = {
verifyCredentials, verifyCredentials,
fetchTimeline, fetchTimeline,
fetchPinnedStatuses,
fetchConversation, fetchConversation,
fetchStatus, fetchStatus,
fetchFriends, 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}) => { 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 args = { timeline, credentials }
const rootState = store.rootState || store.state const rootState = store.rootState || store.state
const timelineData = rootState.statuses.timelines[camelCase(timeline)] const timelineData = rootState.statuses.timelines[camelCase(timeline)]