Compare commits

...

4 Commits

9 changed files with 108 additions and 58 deletions

View File

@ -23,6 +23,7 @@ const Timeline = {
'userId',
'listId',
'tag',
'fetchParams',
'embedded',
'count',
'pinnedStatusIds',
@ -181,7 +182,8 @@ const Timeline = {
showImmediately: true,
userId: this.userId,
listId: this.listId,
tag: this.tag
tag: this.tag,
params: this.fetchParams,
}).then(({ statuses }) => {
if (statuses && statuses.length === 0) {
this.bottomedOut = true

View File

@ -3,6 +3,7 @@ import UserCard from '../user_card/user_card.vue'
import FollowCard from '../follow_card/follow_card.vue'
import Timeline from '../timeline/timeline.vue'
import Conversation from '../conversation/conversation.vue'
import Checkbox from 'src/components/checkbox/checkbox.vue'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import RichContent from 'src/components/rich_content/rich_content.jsx'
import List from '../list/list.vue'
@ -55,7 +56,12 @@ const UserProfile = {
followsTab: 'users',
footerRef: null,
note: null,
noteLoading: false
noteLoading: false,
showPinned: true,
filterParams: {
showReplies: false,
showRepeats: true,
}
}
},
created () {
@ -70,10 +76,35 @@ const UserProfile = {
},
computed: {
timeline () {
return this.$store.state.statuses.timelines.user
const { user, pinned } = this.$store.state.statuses.timelines
if (!this.showPinned) {
return user
}
return {
...user,
statuses: [...pinned.statuses, ...user.statuses],
visibleStatuses: [...pinned.visibleStatuses, ...user.visibleStatuses],
statusesObject: {
...pinned.statusesObject,
...user.statusesObject,
}
}
},
replies () {
return this.$store.state.statuses.timelines.replies
hasPinned () {
return !!(this.user.pinnedStatusIds || []).length
},
fetchParams () {
if (this.tab !== 'statuses') {
return []
}
const params = []
if (!this.filterParams.showReplies) {
params.push(['exclude_replies', 1])
}
if (!this.filterParams.showRepeats) {
params.push(['exclude_reblogs', 1])
}
return params
},
favorites () {
return this.$store.state.statuses.timelines.favorites
@ -118,16 +149,17 @@ const UserProfile = {
if (this.isUs) timelineTabMap['favorites'] = 'favorites'
const timeline = timelineTabMap[nextTab]
const fetchArgs = { timeline: timeline, userId: this.userId, params: this.fetchParams }
if (timeline) {
this.stopFetching()
this.$store.dispatch('startFetchingTimeline', { timeline: timeline, userId: this.userId })
this.$store.dispatch('startFetchingTimeline', fetchArgs)
}
},
load (userNameOrId) {
const loadById = (userId) => {
this.userId = userId
const timelines = ['user', 'favorites', 'replies', 'media']
const timelines = ['pinned', 'user', 'favorites', 'media']
timelines.forEach((timeline) => {
this.$store.commit('clearTimeline', { timeline: timeline })
})
@ -165,7 +197,6 @@ const UserProfile = {
},
stopFetching () {
this.$store.dispatch('stopFetchingTimeline', 'user')
this.$store.dispatch('stopFetchingTimeline', 'replies')
this.$store.dispatch('stopFetchingTimeline', 'favorites')
this.$store.dispatch('stopFetchingTimeline', 'media')
},
@ -198,6 +229,15 @@ const UserProfile = {
}, 1500)
},
watch: {
filterParams: {
handler () {
// Clear the user timeline if previously fetched posts may not be relevant anymore
this.$store.dispatch('stopFetchingTimeline', 'user')
this.$store.commit('clearTimeline', { timeline: 'user', excludeUserId: true })
this.onRouteChange(null, this.tab)
},
deep: true
},
'$route.params.id': function (newVal) {
if (isUserPage(this.$route) && newVal) {
this.switchUser(newVal)
@ -215,16 +255,17 @@ const UserProfile = {
}
},
components: {
Checkbox,
Conversation,
FollowCard,
FollowedTagCard,
UserCard,
Timeline,
FollowedTagList,
FollowerList,
FriendList,
FollowCard,
TabSwitcher,
Conversation,
RichContent,
FollowedTagList
TabSwitcher,
Timeline,
UserCard
}
}

View File

@ -75,31 +75,27 @@
:render-only-focused="true"
:on-switch="onTabSwitch"
>
<Timeline
key="statuses"
:label="$t('user_card.statuses')"
:count="user.statuses_count"
:embedded="true"
:title="$t('user_profile.timeline_title')"
:timeline="timeline"
timeline-name="user"
:user-id="userId"
:pinned-status-ids="user.pinnedStatusIds"
:in-profile="true"
:footer-slipgate="footerRef"
/>
<Timeline
key="replies"
:label="$t('user_card.replies')"
:count="user.statuses_count"
:embedded="true"
:title="$t('user_card.replies')"
:timeline="replies"
timeline-name="replies"
:user-id="userId"
:in-profile="true"
:footer-slipgate="footerRef"
/>
<div key="statuses" :label="$t('user_card.statuses')">
<div class="user-post-filters">
<Checkbox v-model="filterParams.showReplies">{{ $t('user_card.with_replies') }}</Checkbox>
<Checkbox v-model="filterParams.showRepeats">{{ $t('user_card.with_repeats') }}</Checkbox>
<Checkbox :disabled="!hasPinned" v-model="showPinned">{{ $t('user_card.with_pinned') }}</Checkbox>
</div>
<Timeline
key="statuses"
:label="$t('user_card.statuses')"
:count="user.statuses_count"
:embedded="true"
:title="$t('user_profile.timeline_title')"
:timeline="timeline"
timeline-name="user"
:user-id="userId"
:pinned-status-ids="user.pinnedStatusIds"
:in-profile="true"
:fetch-params="fetchParams"
:footer-slipgate="footerRef"
/>
</div>
<div
v-if="followsTabVisible"
key="followees"
@ -268,6 +264,14 @@
}
}
.user-post-filters {
display: flex;
flex-direction: row;
grid-gap: 1em;
justify-content: center;
padding: 0.75em;
}
.userlist-placeholder {
display: flex;
justify-content: center;

View File

@ -1179,10 +1179,13 @@
"per_day": "per day",
"remote_follow": "Remote follow",
"remove_follower": "Remove follower",
"replies": "With Replies",
"with_pinned": "With Pinned",
"with_replies": "With Replies",
"with_repeats": "With Repeats",
"report": "Report",
"requested_by": "Has requested to follow you",
"show_repeats": "Show repeats",
"pinned": "Pinned",
"statuses": "Posts",
"subscribe": "Subscribe",
"unblock": "Unblock",

View File

@ -208,12 +208,13 @@ const api = {
timeline = 'friends',
tag = false,
userId = false,
listId = false
listId = false,
params
}) {
if (store.state.fetchers[timeline]) return
const fetcher = store.state.backendInteractor.startFetchingTimeline({
timeline, store, userId, listId, tag
timeline, store, userId, listId, tag, params
})
store.commit('addFetcher', { fetcherName: timeline, fetcher })
},

View File

@ -65,7 +65,7 @@ export const defaultState = () => ({
bookmarks: emptyTl(),
list: emptyTl(),
bubble: emptyTl(),
replies: emptyTl()
pinned: emptyTl(),
}
})
@ -184,7 +184,7 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
// This makes sure that user timeline won't get data meant for other
// user. I.e. opening different user profiles makes request which could
// return data late after user already viewing different user profile
if ((timeline === 'user' || timeline === 'media' || timeline === 'replies') && timelineObject.userId !== userId) {
if ((timeline === 'user' || timeline === 'media') && timelineObject.userId !== userId) {
return
}
@ -641,7 +641,7 @@ const statuses = {
},
fetchPinnedStatuses ({ rootState, dispatch }, userId) {
rootState.api.backendInteractor.fetchPinnedStatuses({ id: userId })
.then(statuses => dispatch('addNewStatuses', { statuses, timeline: 'user', userId, showImmediately: true, noIdUpdate: true }))
.then(statuses => dispatch('addNewStatuses', { statuses, timeline: 'pinned', userId, showImmediately: true, noIdUpdate: true }))
},
pinStatus ({ rootState, dispatch }, statusId) {
return rootState.api.backendInteractor.pinOwnStatus({ id: statusId })

View File

@ -695,7 +695,8 @@ const fetchTimeline = ({
listId = false,
tag = false,
withMuted = false,
replyVisibility = 'all'
replyVisibility = 'all',
params: addtlParams,
}) => {
const timelineUrls = {
public: MASTODON_PUBLIC_TIMELINE,
@ -713,11 +714,11 @@ const fetchTimeline = ({
bookmarks: MASTODON_BOOKMARK_TIMELINE_URL
}
const isNotifications = timeline === 'notifications'
const params = []
let url = timelineUrls[timeline]
const params = addtlParams ? [...addtlParams] : []
if (timeline === 'user' || timeline === 'media' || timeline === 'replies') {
if (timeline === 'user' || timeline === 'media') {
url = url(userId)
}
@ -749,9 +750,6 @@ const fetchTimeline = ({
if (replyVisibility !== 'all') {
params.push(['reply_visibility', replyVisibility])
}
if (timeline === 'user') {
params.push(['exclude_replies', 1])
}
params.push(['limit', 20])

View File

@ -7,8 +7,8 @@ import configFetcher from '../config_fetcher/config_fetcher.service.js'
import reportsFetcher from '../reports_fetcher/reports_fetcher.service.js'
const backendInteractorService = credentials => ({
startFetchingTimeline ({ timeline, store, userId = false, listId = false, tag }) {
return timelineFetcher.startFetching({ timeline, store, credentials, userId, listId, tag })
startFetchingTimeline ({ timeline, store, userId = false, listId = false, tag, params }) {
return timelineFetcher.startFetching({ timeline, store, credentials, userId, listId, tag, params })
},
fetchTimeline (args) {

View File

@ -26,9 +26,10 @@ const fetchAndUpdate = ({
listId = false,
tag = false,
until,
since
since,
params
}) => {
const args = { timeline, credentials }
const args = { timeline, credentials, params }
const rootState = store.rootState || store.state
const { getters } = store
const timelineData = rootState.statuses.timelines[camelCase(timeline)]
@ -78,15 +79,15 @@ const fetchAndUpdate = ({
})
}
const startFetching = ({ timeline = 'friends', credentials, store, userId = false, listId = false, tag = false }) => {
const startFetching = ({ timeline = 'friends', credentials, store, userId = false, listId = false, tag = false, params }) => {
const rootState = store.rootState || store.state
const timelineData = rootState.statuses.timelines[camelCase(timeline)]
const showImmediately = timelineData.visibleStatuses.length === 0
timelineData.userId = userId
timelineData.listId = listId
fetchAndUpdate({ timeline, credentials, store, showImmediately, userId, listId, tag })
fetchAndUpdate({ timeline, credentials, store, showImmediately, userId, listId, tag, params })
const boundFetchAndUpdate = () =>
fetchAndUpdate({ timeline, credentials, store, userId, listId, tag })
fetchAndUpdate({ timeline, credentials, store, userId, listId, tag, params })
return promiseInterval(boundFetchAndUpdate, 20000)
}
const timelineFetcher = {