commit: b78ad8998dbba447796a62be945d6fdf2153506a
parent: b436e0dd12167719c0f918a27df3ab4f43113d4c
Author: HJ <30-hj@users.noreply.git.pleroma.social>
Date: Mon, 20 May 2019 20:54:05 +0000
Merge branch 'masto-remains' into 'develop'
Interactions 2.0, removing last bits of qvitter api. Only login/register and change background remains after that
See merge request pleroma/pleroma-fe!792
Diffstat:
15 files changed, 110 insertions(+), 36 deletions(-)
diff --git a/src/boot/routes.js b/src/boot/routes.js
@@ -3,7 +3,7 @@ import PublicAndExternalTimeline from 'components/public_and_external_timeline/p
import FriendsTimeline from 'components/friends_timeline/friends_timeline.vue'
import TagTimeline from 'components/tag_timeline/tag_timeline.vue'
import ConversationPage from 'components/conversation-page/conversation-page.vue'
-import Mentions from 'components/mentions/mentions.vue'
+import Interactions from 'components/interactions/interactions.vue'
import DMs from 'components/dm_timeline/dm_timeline.vue'
import UserProfile from 'components/user_profile/user_profile.vue'
import Settings from 'components/settings/settings.vue'
@@ -34,7 +34,7 @@ export default (store) => {
{ name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline },
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
{ name: 'external-user-profile', path: '/users/:id', component: UserProfile },
- { name: 'mentions', path: '/users/:username/mentions', component: Mentions },
+ { name: 'interactions', path: '/users/:username/interactions', component: Interactions },
{ name: 'dms', path: '/users/:username/dms', component: DMs },
{ name: 'settings', path: '/settings', component: Settings },
{ name: 'registration', path: '/registration', component: Registration },
diff --git a/src/components/interactions/interactions.js b/src/components/interactions/interactions.js
@@ -0,0 +1,25 @@
+import Notifications from '../notifications/notifications.vue'
+
+const tabModeDict = {
+ mentions: ['mention'],
+ 'likes+repeats': ['repeat', 'like'],
+ follows: ['follow']
+}
+
+const Interactions = {
+ data () {
+ return {
+ filterMode: tabModeDict['mentions']
+ }
+ },
+ methods: {
+ onModeSwitch (index, dataset) {
+ this.filterMode = tabModeDict[dataset.filter]
+ }
+ },
+ components: {
+ Notifications
+ }
+}
+
+export default Interactions
diff --git a/src/components/interactions/interactions.vue b/src/components/interactions/interactions.vue
@@ -0,0 +1,25 @@
+<template>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <div class="title">
+ Interactions
+ </div>
+ </div>
+ <tab-switcher
+ ref="tabSwitcher"
+ :onSwitch="onModeSwitch"
+ >
+ <span data-tab-dummy data-filter="mentions" :label="$t('nav.mentions')"/>
+ <span data-tab-dummy data-filter="likes+repeats" :label="$t('interactions.favs_repeats')"/>
+ <span data-tab-dummy data-filter="follows" :label="$t('interactions.follows')"/>
+ </tab-switcher>
+ <Notifications
+ ref="notifications"
+ :noHeading="true"
+ :minimalMode="true"
+ :filterMode="filterMode"
+ />
+ </div>
+</template>
+
+<script src="./interactions.js"></script>
diff --git a/src/components/mentions/mentions.vue b/src/components/mentions/mentions.vue
@@ -1,5 +1,5 @@
<template>
- <Timeline :title="$t('nav.mentions')" v-bind:timeline="timeline" v-bind:timeline-name="'mentions'"/>
+ <Timeline :title="$t('nav.interactions')" v-bind:timeline="timeline" v-bind:timeline-name="'mentions'"/>
</template>
<script src="./mentions.js"></script>
diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue
@@ -8,8 +8,8 @@
</router-link>
</li>
<li v-if='currentUser'>
- <router-link :to="{ name: 'mentions', params: { username: currentUser.screen_name } }">
- {{ $t("nav.mentions") }}
+ <router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }">
+ {{ $t("nav.interactions") }}
</router-link>
</li>
<li v-if='currentUser'>
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
@@ -7,15 +7,24 @@ import {
} from '../../services/notification_utils/notification_utils.js'
const Notifications = {
- props: [
- 'noHeading'
- ],
+ props: {
+ // Disables display of panel header
+ noHeading: Boolean,
+ // Disables panel styles, unread mark, potentially other notification-related actions
+ // meant for "Interactions" timeline
+ minimalMode: Boolean,
+ // Custom filter mode, an array of strings, possible values 'mention', 'repeat', 'like', 'follow', used to override global filter for use in "Interactions" timeline
+ filterMode: Array
+ },
data () {
return {
bottomedOut: false
}
},
computed: {
+ mainClass () {
+ return this.minimalMode ? '' : 'panel panel-default'
+ },
notifications () {
return notificationsFromStore(this.$store)
},
@@ -26,7 +35,8 @@ const Notifications = {
return unseenNotificationsFromStore(this.$store)
},
visibleNotifications () {
- return visibleNotificationsFromStore(this.$store)
+ console.log(this.filterMode)
+ return visibleNotificationsFromStore(this.$store, this.filterMode)
},
unseenCount () {
return this.unseenNotifications.length
diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss
@@ -1,8 +1,10 @@
@import '../../_variables.scss';
.notifications {
- // a bit of a hack to allow scrolling below notifications
- padding-bottom: 15em;
+ &:not(.minimal) {
+ // a bit of a hack to allow scrolling below notifications
+ padding-bottom: 15em;
+ }
.loadmore-error {
color: $fallback--text;
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
@@ -1,6 +1,6 @@
<template>
- <div class="notifications">
- <div class="panel panel-default">
+ <div :class="{ minimal: minimalMode }" class="notifications">
+ <div :class="mainClass">
<div v-if="!noHeading" class="panel-heading">
<div class="title">
{{$t('notifications.notifications')}}
@@ -12,7 +12,7 @@
<button v-if="unseenCount" @click.prevent="markAsSeen" class="read-button">{{$t('notifications.read')}}</button>
</div>
<div class="panel-body">
- <div v-for="notification in visibleNotifications" :key="notification.id" class="notification" :class='{"unseen": !notification.seen}'>
+ <div v-for="notification in visibleNotifications" :key="notification.id" class="notification" :class='{"unseen": !minimalMode && !notification.seen}'>
<div class="notification-overlay"></div>
<notification :notification="notification"></notification>
</div>
@@ -22,7 +22,9 @@
{{$t('notifications.no_more_notifications')}}
</div>
<a v-else-if="!loading" href="#" v-on:click.prevent="fetchOlderNotifications()">
- <div class="new-status-notification text-center panel-footer">{{$t('notifications.load_older')}}</div>
+ <div class="new-status-notification text-center panel-footer">
+ {{ minimalMode ? $t('interactions.load_older') : $t('notifications.load_older')}}
+ </div>
</a>
<div v-else class="new-status-notification text-center panel-footer">
<i class="icon-spin3 animate-spin"/>
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
@@ -26,6 +26,11 @@
{{ $t("nav.dms") }}
</router-link>
</li>
+ <li v-if="currentUser" @click="toggleDrawer">
+ <router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }">
+ {{ $t("nav.interactions") }}
+ </router-link>
+ </li>
</ul>
<ul>
<li v-if="currentUser" @click="toggleDrawer">
diff --git a/src/components/tab_switcher/tab_switcher.js b/src/components/tab_switcher/tab_switcher.js
@@ -4,15 +4,18 @@ import './tab_switcher.scss'
export default Vue.component('tab-switcher', {
name: 'TabSwitcher',
- props: ['renderOnlyFocused'],
+ props: ['renderOnlyFocused', 'onSwitch'],
data () {
return {
active: this.$slots.default.findIndex(_ => _.tag)
}
},
methods: {
- activateTab (index) {
+ activateTab (index, dataset) {
return () => {
+ if (typeof this.onSwitch === 'function') {
+ this.onSwitch.call(null, index, this.$slots.default[index].elm.dataset)
+ }
this.active = index
}
}
@@ -37,7 +40,11 @@ export default Vue.component('tab-switcher', {
return (
<div class={ classesWrapper.join(' ')}>
- <button disabled={slot.data.attrs.disabled} onClick={this.activateTab(index)} class={ classesTab.join(' ') }>{slot.data.attrs.label}</button>
+ <button
+ disabled={slot.data.attrs.disabled}
+ onClick={this.activateTab(index)}
+ class={classesTab.join(' ')}>
+ {slot.data.attrs.label}</button>
</div>
)
})
diff --git a/src/i18n/en.json b/src/i18n/en.json
@@ -60,6 +60,7 @@
"chat": "Local Chat",
"friend_requests": "Follow Requests",
"mentions": "Mentions",
+ "interactions": "Interactions",
"dms": "Direct Messages",
"public_tl": "Public Timeline",
"timeline": "Timeline",
@@ -78,6 +79,11 @@
"repeated_you": "repeated your status",
"no_more_notifications": "No more notifications"
},
+ "interactions": {
+ "favs_repeats": "Repeats and Favorites",
+ "follows": "New follows",
+ "load_older": "Load older interactions"
+ },
"post_status": {
"new_status": "Post new status",
"account_not_locked_warning": "Your account is not {0}. Anyone can follow you to view your follower-only posts.",
diff --git a/src/i18n/ru.json b/src/i18n/ru.json
@@ -23,6 +23,7 @@
"back": "Назад",
"chat": "Локальный чат",
"mentions": "Упоминания",
+ "interactions": "Взаимодействия",
"public_tl": "Публичная лента",
"timeline": "Лента",
"twkn": "Федеративная лента"
@@ -36,6 +37,11 @@
"read": "Прочесть",
"repeated_you": "повторил(а) ваш статус"
},
+ "interactions": {
+ "favs_repeats": "Повторы и фавориты",
+ "follows": "Новые подписки",
+ "load_older": "Загрузить старые взаимодействия"
+ },
"post_status": {
"account_not_locked_warning": "Ваш аккаунт не {0}. Кто угодно может зафоловить вас чтобы прочитать посты только для подписчиков",
"account_not_locked_warning_link": "залочен",
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
@@ -1,7 +1,5 @@
/* eslint-env browser */
const LOGIN_URL = '/api/account/verify_credentials.json'
-const ALL_FOLLOWING_URL = '/api/qvitter/allfollowing'
-const MENTIONS_URL = '/api/statuses/mentions.json'
const REGISTRATION_URL = '/api/account/register.json'
const BG_UPDATE_URL = '/api/qvitter/update_background_image.json'
const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json'
@@ -320,13 +318,6 @@ const fetchFollowers = ({id, maxId, sinceId, limit = 20, credentials}) => {
.then((data) => data.map(parseUser))
}
-const fetchAllFollowing = ({username, credentials}) => {
- const url = `${ALL_FOLLOWING_URL}/${username}.json`
- return fetch(url, { headers: authHeaders(credentials) })
- .then((data) => data.json())
- .then((data) => data.map(parseUser))
-}
-
const fetchFollowRequests = ({credentials}) => {
const url = FOLLOW_REQUESTS_URL
return fetch(url, { headers: authHeaders(credentials) })
@@ -446,7 +437,6 @@ const fetchTimeline = ({timeline, credentials, since = false, until = false, use
const timelineUrls = {
public: MASTODON_PUBLIC_TIMELINE,
friends: MASTODON_USER_HOME_TIMELINE_URL,
- mentions: MENTIONS_URL,
dms: MASTODON_DIRECT_MESSAGES_TIMELINE_URL,
notifications: MASTODON_USER_NOTIFICATIONS_URL,
'publicAndExternal': MASTODON_PUBLIC_TIMELINE,
@@ -747,7 +737,6 @@ const apiService = {
postStatus,
deleteStatus,
uploadMedia,
- fetchAllFollowing,
fetchMutes,
muteUser,
unmuteUser,
diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js
@@ -23,10 +23,6 @@ const backendInteractorService = (credentials) => {
return apiService.fetchFollowers({id, maxId, sinceId, limit, credentials})
}
- const fetchAllFollowing = ({username}) => {
- return apiService.fetchAllFollowing({username, credentials})
- }
-
const fetchUser = ({id}) => {
return apiService.fetchUser({id, credentials})
}
@@ -137,7 +133,6 @@ const backendInteractorService = (credentials) => {
unblockUser,
fetchUser,
fetchUserRelationship,
- fetchAllFollowing,
verifyCredentials: apiService.verifyCredentials,
startFetchingTimeline,
startFetchingNotifications,
diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js
@@ -25,11 +25,13 @@ const sortById = (a, b) => {
}
}
-export const visibleNotificationsFromStore = store => {
+export const visibleNotificationsFromStore = (store, types) => {
// map is just to clone the array since sort mutates it and it causes some issues
let sortedNotifications = notificationsFromStore(store).map(_ => _).sort(sortById)
sortedNotifications = sortBy(sortedNotifications, 'seen')
- return sortedNotifications.filter((notification) => visibleTypes(store).includes(notification.type))
+ return sortedNotifications.filter(
+ (notification) => (types || visibleTypes(store)).includes(notification.type)
+ )
}
export const unseenNotificationsFromStore = store =>