Merge branch 'notifications' into shigusegubu

* notifications:
  error display
  removed style for rounding bottom part of notifications because there's now always "load more" footer
  fix custom emoji in username, fix gif avatar not being animated when hovering on the notification
  Hide initial desktop notifications spam when FE is opened and there's a lot of unseen notifications.
  Updated localization files
  Drop the entire thing about hidden "own" timeline since it doesn't necessarily contain all of the users posts (it doesn't contain DMs) even though it's "us". Since this is a workaround anyway just fetch home timeline instead. It could end up making more queries if user doesn't post that often.
This commit is contained in:
Henry Jameson 2018-08-20 20:46:18 +03:00
commit 83b2964f7c
9 changed files with 54 additions and 25 deletions

View file

@ -14,6 +14,9 @@ const Notifications = {
notifications () {
return this.$store.state.statuses.notifications.data
},
error () {
return this.$store.state.statuses.notifications.error
},
unseenNotifications () {
return filter(this.notifications, ({seen}) => !seen)
},

View file

@ -4,6 +4,10 @@
// a bit of a hack to allow scrolling below notifications
padding-bottom: 15em;
.title {
display: inline-block;
}
.panel {
background: $fallback--bg;
background: var(--bg, $fallback--bg)
@ -22,6 +26,8 @@
background: var(--btn, $fallback--btn);
color: $fallback--fg;
color: var(--fg, $fallback--fg);
display: flex;
align-items: baseline;
.read-button {
position: absolute;
right: 0.7em;
@ -44,6 +50,19 @@
line-height: 1.3em;
}
.loadmore-error {
position: absolute;
right: 0.6em;
font-size: 14px;
min-width: 6em;
font-family: sans-serif;
text-align: center;
padding: 0 0.25em 0 0.25em;
margin: 0;
color: $fallback--fg;
color: var(--fg, $fallback--fg);
}
.unseen {
box-shadow: inset 4px 0 0 var(--cRed, $fallback--cRed);
padding-left: 0;
@ -79,7 +98,7 @@
}
}
&:hover .animated.avatar {
&:hover .animated.avatar-compact {
canvas {
display: none;
}
@ -155,6 +174,13 @@
max-width: 100%;
text-overflow: ellipsis;
white-space: nowrap;
img {
width: 14px;
height: 14px;
vertical-align: middle;
object-fit: contain
}
}
.timeago {
float: right;
@ -204,15 +230,4 @@
margin-bottom: 0.3em;
}
}
// ugly as heck
&:last-child {
border-bottom: none;
border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
.status-el {
border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
}
}
}

View file

@ -3,7 +3,10 @@
<div class="panel panel-default">
<div class="panel-heading">
<span class="unseen-count" v-if="unseenCount">{{unseenCount}}</span>
{{$t('notifications.notifications')}}
<div class="title"> {{$t('notifications.notifications')}}</div>
<div @click.prevent class="loadmore-error alert error" v-if="error">
{{$t('timeline.error_fetching')}}
</div>
<button v-if="unseenCount" @click.prevent="markAsSeen" class="read-button">{{$t('notifications.read')}}</button>
</div>
<div class="panel-body">

View file

@ -355,7 +355,8 @@ const en = {
followed_you: 'followed you',
favorited_you: 'favorited your status',
repeated_you: 'repeated your status',
broken_favorite: 'Unknown status, searching for it...'
broken_favorite: 'Unknown status, searching for it...',
load_older: 'Load older notifications'
},
login: {
login: 'Log in',
@ -1650,7 +1651,8 @@ const ru = {
followed_you: 'начал(а) читать вас',
favorited_you: 'нравится ваш статус',
repeated_you: 'повторил(а) ваш статус',
broken_favorite: 'Неизвестный статус, ищем...'
broken_favorite: 'Неизвестный статус, ищем...',
load_older: 'Загрузить старые уведомления'
},
login: {
login: 'Войти',

View file

@ -24,10 +24,12 @@ export const defaultState = {
allStatusesObject: {},
maxId: 0,
notifications: {
desktopNotificationSilence: true,
maxId: 0,
maxSavedId: 0,
minId: Number.POSITIVE_INFINITY,
data: [],
error: false,
brokenFavorites: {}
},
favorites: new Set(),
@ -36,7 +38,6 @@ export const defaultState = {
mentions: emptyTl(),
public: emptyTl(),
user: emptyTl(),
own: emptyTl(),
publicAndExternal: emptyTl(),
friends: emptyTl(),
tag: emptyTl()
@ -315,7 +316,7 @@ const addNewNotifications = (state, { dispatch, notifications, older }) => {
result.image = action.attachments[0].url
}
if (fresh) {
if (fresh && !state.notifications.desktopNotificationSilence) {
let notification = new window.Notification(title, result)
// Chrome is known for not closing notifications automatically
// according to MDN, anyway.
@ -364,7 +365,10 @@ export const mutations = {
state.error = value
},
setNotificationsError (state, { value }) {
state.notificationsError = value
state.notifications.error = value
},
setNotificationsSilence (state, { value }) {
state.notifications.desktopNotificationSilence = value
},
setProfileView (state, { v }) {
// load followers / friends only when needed
@ -402,6 +406,9 @@ const statuses = {
setNotificationsError ({ rootState, commit }, { value }) {
commit('setNotificationsError', { value })
},
setNotificationsSilence ({ rootState, commit }, { value }) {
commit('setNotificationsSilence', { value })
},
addFriends ({ rootState, commit }, { friends }) {
commit('addFriends', { friends })
},

View file

@ -107,8 +107,6 @@ const users = {
// Start getting fresh tweets.
store.dispatch('startFetching', 'friends')
// Start getting our own posts, only really needed for mitigating broken favorites
store.dispatch('startFetching', ['own', user.id])
// Get user mutes and follower info
store.rootState.api.backendInteractor.fetchMutes().then((mutedUsers) => {

View file

@ -306,9 +306,6 @@ const fetchTimeline = ({timeline, credentials, since = false, until = false, use
notifications: QVITTER_USER_NOTIFICATIONS_URL,
'publicAndExternal': PUBLIC_AND_EXTERNAL_TIMELINE_URL,
user: QVITTER_USER_TIMELINE_URL,
// separate timeline for own posts, so it won't break due to user timeline bugs
// really needed only for broken favorites
own: QVITTER_USER_TIMELINE_URL,
tag: TAG_TIMELINE_URL
}

View file

@ -54,11 +54,11 @@ const backendInteractorService = (credentials) => {
return timelineFetcherService.startFetching({timeline, store, credentials, userId})
}
const fetchOldPost = ({store, postId}) => {
const fetchOldPost = ({store, postId, timeline = 'friends'}) => {
return timelineFetcherService.fetchAndUpdate({
store,
credentials,
timeline: 'own',
timeline,
older: true,
until: postId + 1
})

View file

@ -30,6 +30,10 @@ const fetchAndUpdate = ({store, credentials, older = false}) => {
const startFetching = ({credentials, store}) => {
fetchAndUpdate({ credentials, store })
const boundFetchAndUpdate = () => fetchAndUpdate({ credentials, store })
// Initially there's set flag to silence all desktop notifications so
// that there won't spam of them when user just opened up the FE we
// reset that flag after a while to show new notifications once again.
setTimeout(() => store.dispatch('setNotificationsSilence', false), 10000)
return setInterval(boundFetchAndUpdate, 10000)
}