diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index 55a9b0ab9..b24250b07 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -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) }, diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index 2bc71bfe4..5b09685b6 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -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); - } - } } diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue index 859730ed8..a0b0e5f58 100644 --- a/src/components/notifications/notifications.vue +++ b/src/components/notifications/notifications.vue @@ -3,7 +3,10 @@
{{unseenCount}} - {{$t('notifications.notifications')}} +
{{$t('notifications.notifications')}}
+
+ {{$t('timeline.error_fetching')}} +
diff --git a/src/i18n/messages.js b/src/i18n/messages.js index d0fc50137..00c562548 100644 --- a/src/i18n/messages.js +++ b/src/i18n/messages.js @@ -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: 'Войти', diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 45dd3afac..8e1e7fe7d 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -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 }) }, diff --git a/src/modules/users.js b/src/modules/users.js index c592fe4e9..ba5487655 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -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) => { diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 1cb5e0b8f..4f6af06dd 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -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 } diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index c84373acf..5742441cf 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -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 }) diff --git a/src/services/notifications_fetcher/notifications_fetcher.service.js b/src/services/notifications_fetcher/notifications_fetcher.service.js index 5aedc4fbc..74a4bcda1 100644 --- a/src/services/notifications_fetcher/notifications_fetcher.service.js +++ b/src/services/notifications_fetcher/notifications_fetcher.service.js @@ -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) }