logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe
commit: 2bc261afbaf9377450999e49a5fe46dcbcc8b180
parent: 5a1ad8409244ca7deb224b172ceb2b4acf7b8614
Author: Shpuld Shpuldson <shpuld@gmail.com>
Date:   Wed, 23 Aug 2017 12:40:39 -0400

Merge branch 'feature/follow-lists' into 'develop'

Feature/follow lists

See merge request !106

Diffstat:

Msrc/components/status/status.vue2+-
Msrc/components/timeline/timeline.js31+++++++++++++++++++++++++++++--
Msrc/components/timeline/timeline.vue33++++++++++++++++++++++++++++++++-
Asrc/components/user_card/user_card.js23+++++++++++++++++++++++
Asrc/components/user_card/user_card.vue61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/components/user_card_content/user_card_content.vue29++++++++++++++++++++---------
Msrc/components/user_panel/user_panel.vue2+-
Msrc/components/user_profile/user_profile.vue2+-
Msrc/modules/statuses.js46++++++++++++++++++++++++++++++++++++++++------
Msrc/services/api/api.service.js14+++++++++++---
Msrc/services/backend_interactor_service/backend_interactor_service.js9+++++++--
11 files changed, 226 insertions(+), 26 deletions(-)

diff --git a/src/components/status/status.vue b/src/components/status/status.vue @@ -40,7 +40,7 @@ </div> <div class="media-body"> <div class="base05 base05=border usercard" v-if="userExpanded"> - <user-card-content :user="status.user"></user-card-content> + <user-card-content :user="status.user" :switcher="false"></user-card-content> </div> <div class="user-content"> <div class="media-heading"> diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js @@ -1,6 +1,7 @@ import Status from '../status/status.vue' import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js' import StatusOrConversation from '../status_or_conversation/status_or_conversation.vue' +import UserCard from '../user_card/user_card.vue' const Timeline = { props: [ @@ -10,11 +11,21 @@ const Timeline = { 'userId' ], computed: { - timelineError () { return this.$store.state.statuses.error } + timelineError () { return this.$store.state.statuses.error }, + followers () { + return this.timeline.followers + }, + friends () { + return this.timeline.friends + }, + viewing () { + return this.timeline.viewing + } }, components: { Status, - StatusOrConversation + StatusOrConversation, + UserCard }, created () { const store = this.$store @@ -30,6 +41,12 @@ const Timeline = { showImmediately, userId: this.userId }) + + // don't fetch followers for public, friend, twkn + if (this.timelineName === 'user') { + this.fetchFriends() + this.fetchFollowers() + } }, methods: { showNewStatuses () { @@ -48,6 +65,16 @@ const Timeline = { userId: this.userId }).then(() => store.commit('setLoading', { timeline: this.timelineName, value: false })) }, + fetchFollowers () { + const id = this.userId + this.$store.state.api.backendInteractor.fetchFollowers({ id }) + .then((followers) => this.$store.dispatch('addFollowers', { followers })) + }, + fetchFriends () { + const id = this.userId + this.$store.state.api.backendInteractor.fetchFriends({ id }) + .then((friends) => this.$store.dispatch('addFriends', { friends })) + }, scrollLoad (e) { let height = Math.max(document.body.offsetHeight, document.body.scrollHeight) if (this.timeline.loading === false && this.$store.state.config.autoLoad && (window.innerHeight + window.pageYOffset) >= (height - 750)) { diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue @@ -1,5 +1,5 @@ <template> - <div class="timeline panel panel-default"> + <div class="timeline panel panel-default" v-if="viewing == 'statuses'"> <div class="panel-heading timeline-heading base01-background base04"> <div class="title"> {{title}} @@ -24,6 +24,30 @@ </div> </div> </div> + <div class="timeline panel panel-default" v-else-if="viewing == 'followers'"> + <div class="panel-heading timeline-heading base01-background base04"> + <div class="title"> + Followers + </div> + </div> + <div class="panel-body"> + <div class="timeline"> + <user-card v-for="follower in followers" :user="follower" :showFollows="false"></user-card> + </div> + </div> + </div> + <div class="timeline panel panel-default" v-else-if="viewing == 'friends'"> + <div class="panel-heading timeline-heading base01-background base04"> + <div class="title"> + Following + </div> + </div> + <div class="panel-body"> + <div class="timeline"> + <user-card v-for="friend in friends" :user="friend" :showFollows="true"></user-card> + </div> + </div> + </div> </template> <script src="./timeline.js"></script> @@ -65,6 +89,13 @@ } } + .avatar { + padding-top: 0.3em; + width:32px; + height: 32px; + border-radius: 50%; + } + .new-status-notification { position:relative; diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js @@ -0,0 +1,23 @@ +import UserCardContent from '../user_card_content/user_card_content.vue' + +const UserCard = { + props: [ + 'user', + 'showFollows' + ], + data () { + return { + userExpanded: false + } + }, + components: { + UserCardContent + }, + methods: { + toggleUserExpanded () { + this.userExpanded = !this.userExpanded + } + } +} + +export default UserCard diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue @@ -0,0 +1,61 @@ +<template> + <div class="card base00-background base03-border"> + <a href="#"> + <img @click.prevent="toggleUserExpanded" class="avatar" :src="user.profile_image_url"> + </a> + <div class="base05 base05=border usercard" v-if="userExpanded"> + <user-card-content :user="user" :switcher="false"></user-card-content> + </div> + <div class="name-and-screen-name" v-else> + <div class="user-name">{{ user.name }}</div> + <a href="user.statusnet_profile_url"><div class="user-screen-name">@{{ user.screen_name }}</div></a> + </div> + <span class="follows-you" v-if="!userExpanded && showFollows"> + <div class="follows" v-if="user.follows_you"> + Follows you! + </div> + </span> + </div> +</template> + +<script src="./user_card.js"></script> + +<style lang="scss"> + .name-and-screen-name { + margin-left: 0.7em; + min-width: 16em; + display:block; + margin-top:0.0em; + margin-right: 2em; + text-align: left; + } + + .follows-you { + margin-left: 2em; + width:-webkit-fill-available; + width: -moz-webkit-fill-available; + } + + .follows { + float: right; + } + + .card { + display: flex; + flex: 1 0; + padding-top: 0.6em; + padding-right: 1em; + padding-bottom: 0.6em; + padding-left: 1em; + border-bottom: 1px solid; + margin: 0; + border-bottom-color: inherit; + } + + .usercard { + width: -webkit-fill-available; + width: -moz-webkit-fill-available; + stretch: fill; + margin-left: 0.7em; + } +</style> diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue @@ -47,17 +47,20 @@ </div> <div class="panel-body profile-panel-body" :style="bodyStyle"> <div class="user-counts"> - <div class="user-count"> - <h5>Statuses</h5> - <span>{{user.statuses_count}} <br><span class="dailyAvg">{{dailyAvg}} per day</span></span> + <div class="user-count base04"> + <a href="#" v-on:click.prevent="setProfileView('statuses')" v-if="switcher"><h5 class="base05">Statuses</h5></a> + <h5 v-else>Statuses</h5> + <span class="base05">{{user.statuses_count}} <br><span class="dailyAvg">{{dailyAvg}} per day</span></span> </div> <div class="user-count"> - <h5>Following</h5> - <span>{{user.friends_count}}</span> + <a href="#" v-on:click.prevent="setProfileView('friends')" v-if="switcher"><h5 class="base05">Following</h5></a> + <h5 v-else>Following</h5> + <span class="base05">{{user.friends_count}}</span> </div> <div class="user-count"> - <h5>Followers</h5> - <span>{{user.followers_count}}</span> + <a href="#" v-on:click.prevent="setProfileView('followers')" v-if="switcher"><h5 class="base05">Followers</h5></a> + <h5 v-else>Followers</h5> + <span class="base05">{{user.followers_count}}</span> </div> </div> <p>{{user.description}}</p> @@ -67,7 +70,7 @@ <script> export default { - props: [ 'user' ], + props: [ 'user', 'switcher' ], computed: { headingStyle () { let color = this.$store.state.config.colors['base00'] @@ -110,13 +113,18 @@ const store = this.$store store.commit('setMuted', {user: this.user, muted: !this.user.muted}) store.state.api.backendInteractor.setUserMute(this.user) + }, + setProfileView (v) { + const store = this.$store + store.commit('setProfileView', { v }) } } } </script> <style lang="scss"> - +@import '../../_variables.scss'; + .profile-panel-background { background-size: cover; border-radius: 10px; @@ -242,6 +250,9 @@ font-weight: bolder; margin: 0 0 0.25em; } + a { + text-decoration: none; + } } .dailyAvg { diff --git a/src/components/user_panel/user_panel.vue b/src/components/user_panel/user_panel.vue @@ -2,7 +2,7 @@ <div class="user-panel"> <div v-if='user' class="panel panel-default"> - <user-card-content :user="user"></user-card-content> + <user-card-content :user="user" :switcher="false"></user-card-content> <div class="panel-footer base00-background"> <post-status-form v-if='user'></post-status-form> diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue @@ -1,7 +1,7 @@ <template> <div> <div v-if="user" class="user-profile panel panel-default base00-background"> - <user-card-content :user="user"></user-card-content> + <user-card-content :user="user" :switcher="true"></user-card-content> </div> <Timeline :title="'User Timeline'" v-bind:timeline="timeline" v-bind:timeline-name="'user'" :user-id="userId"/> </div> diff --git a/src/modules/statuses.js b/src/modules/statuses.js @@ -19,7 +19,10 @@ export const defaultState = { newStatusCount: 0, maxId: 0, minVisibleId: 0, - loading: false + loading: false, + followers: [], + friends: [], + viewing: 'statuses' }, public: { statuses: [], @@ -30,7 +33,10 @@ export const defaultState = { newStatusCount: 0, maxId: 0, minVisibleId: 0, - loading: false + loading: false, + followers: [], + friends: [], + viewing: 'statuses' }, user: { statuses: [], @@ -41,7 +47,10 @@ export const defaultState = { newStatusCount: 0, maxId: 0, minVisibleId: 0, - loading: false + loading: false, + followers: [], + friends: [], + viewing: 'statuses' }, publicAndExternal: { statuses: [], @@ -52,7 +61,10 @@ export const defaultState = { newStatusCount: 0, maxId: 0, minVisibleId: 0, - loading: false + loading: false, + followers: [], + friends: [], + viewing: 'statuses' }, friends: { statuses: [], @@ -63,7 +75,10 @@ export const defaultState = { newStatusCount: 0, maxId: 0, minVisibleId: 0, - loading: false + loading: false, + followers: [], + friends: [], + viewing: 'statuses' } } } @@ -320,7 +335,10 @@ export const mutations = { newStatusCount: 0, maxId: 0, minVisibleId: 0, - loading: false + loading: false, + followers: [], + friends: [], + viewing: 'statuses' } state.timelines[timeline] = emptyTimeline @@ -347,6 +365,16 @@ export const mutations = { setError (state, { value }) { state.error = value }, + setProfileView (state, { v }) { + // load followers / friends only when needed + state.timelines['user'].viewing = v + }, + addFriends (state, { friends }) { + state.timelines['user'].friends = friends + }, + addFollowers (state, { followers }) { + state.timelines['user'].followers = followers + }, markNotificationsAsSeen (state, notifications) { each(notifications, (notification) => { notification.seen = true @@ -363,6 +391,12 @@ const statuses = { setError ({ rootState, commit }, { value }) { commit('setError', { value }) }, + addFriends ({ rootState, commit }, { friends }) { + commit('addFriends', { friends }) + }, + addFollowers ({ rootState, commit }, { followers }) { + commit('addFollowers', { followers }) + }, deleteStatus ({ rootState, commit }, status) { commit('setDeleted', { status }) apiService.deleteStatus({ id: status.id, credentials: rootState.users.currentUser.credentials }) diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js @@ -13,6 +13,7 @@ const STATUS_URL = '/api/statuses/show' const MEDIA_UPLOAD_URL = '/api/statusnet/media/upload' const CONVERSATION_URL = '/api/statusnet/conversation' const MENTIONS_URL = '/api/statuses/mentions.json' +const FOLLOWERS_URL = '/api/statuses/followers.json' const FRIENDS_URL = '/api/statuses/friends.json' const FOLLOWING_URL = '/api/friendships/create.json' const UNFOLLOWING_URL = '/api/friendships/destroy.json' @@ -179,8 +180,15 @@ const unfollowUser = ({id, credentials}) => { }).then((data) => data.json()) } -const fetchFriends = ({credentials}) => { - return fetch(FRIENDS_URL, { headers: authHeaders(credentials) }) +const fetchFriends = ({id, credentials}) => { + let url = `${FRIENDS_URL}?user_id=${id}` + return fetch(url, { headers: authHeaders(credentials) }) + .then((data) => data.json()) +} + +const fetchFollowers = ({id, credentials}) => { + let url = `${FOLLOWERS_URL}?user_id=${id}` + return fetch(url, { headers: authHeaders(credentials) }) .then((data) => data.json()) } @@ -234,7 +242,6 @@ const fetchTimeline = ({timeline, credentials, since = false, until = false, use if (since) { params.push(['since_id', since]) } - if (until) { params.push(['max_id', until]) } @@ -326,6 +333,7 @@ const apiService = { fetchConversation, fetchStatus, fetchFriends, + fetchFollowers, followUser, unfollowUser, favorite, diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js @@ -10,8 +10,12 @@ const backendInteractorService = (credentials) => { return apiService.fetchConversation({id, credentials}) } - const fetchFriends = () => { - return apiService.fetchFriends({credentials}) + const fetchFriends = ({id}) => { + return apiService.fetchFriends({id, credentials}) + } + + const fetchFollowers = ({id}) => { + return apiService.fetchFollowers({id, credentials}) } const fetchAllFollowing = ({username}) => { @@ -48,6 +52,7 @@ const backendInteractorService = (credentials) => { fetchStatus, fetchConversation, fetchFriends, + fetchFollowers, followUser, unfollowUser, fetchAllFollowing,