Merge branch 'develop' of git.pleroma.social:pleroma/pleroma-fe into develop

This commit is contained in:
sadposter 2020-08-01 19:41:12 +01:00
commit 66c44b4260
62 changed files with 1206 additions and 595 deletions

View file

@ -632,7 +632,8 @@ const postStatus = ({
mediaIds = [],
inReplyToStatusId,
contentType,
preview
preview,
idempotencyKey
}) => {
const form = new FormData()
const pollOptions = poll.options || []
@ -666,10 +667,15 @@ const postStatus = ({
form.append('preview', 'true')
}
let postHeaders = authHeaders(credentials)
if (idempotencyKey) {
postHeaders['idempotency-key'] = idempotencyKey
}
return fetch(MASTODON_POST_STATUS_URL, {
body: form,
method: 'POST',
headers: authHeaders(credentials)
headers: postHeaders
})
.then((response) => {
return response.json()

View file

@ -0,0 +1,19 @@
import { showDesktopNotification } from '../desktop_notification_utils/desktop_notification_utils.js'
export const maybeShowChatNotification = (store, chat) => {
if (!chat.lastMessage) return
if (store.rootState.chats.currentChatId === chat.id && !document.hidden) return
const opts = {
tag: chat.lastMessage.id,
title: chat.account.name,
icon: chat.account.profile_image_url,
body: chat.lastMessage.content
}
if (chat.lastMessage.attachment && chat.lastMessage.attachment.type === 'image') {
opts.image = chat.lastMessage.attachment.preview_url
}
showDesktopNotification(store.rootState, opts)
}

View file

@ -0,0 +1,9 @@
export const showDesktopNotification = (rootState, desktopNotificationOpts) => {
if (!('Notification' in window && window.Notification.permission === 'granted')) return
if (rootState.statuses.notifications.desktopNotificationSilence) { return }
const desktopNotification = new window.Notification(desktopNotificationOpts.title, desktopNotificationOpts)
// Chrome is known for not closing notifications automatically
// according to MDN, anyway.
setTimeout(desktopNotification.close.bind(desktopNotification), 5000)
}

View file

@ -79,6 +79,7 @@ export const parseUser = (data) => {
const relationship = data.pleroma.relationship
output.background_image = data.pleroma.background_image
output.favicon = data.pleroma.favicon
output.token = data.pleroma.chat_token
if (relationship) {

View file

@ -1,16 +1,22 @@
import { filter, sortBy, includes } from 'lodash'
import { muteWordHits } from '../status_parser/status_parser.js'
import { showDesktopNotification } from '../desktop_notification_utils/desktop_notification_utils.js'
export const notificationsFromStore = store => store.state.statuses.notifications.data
export const visibleTypes = store => ([
store.state.config.notificationVisibility.likes && 'like',
store.state.config.notificationVisibility.mentions && 'mention',
store.state.config.notificationVisibility.repeats && 'repeat',
store.state.config.notificationVisibility.follows && 'follow',
store.state.config.notificationVisibility.followRequest && 'follow_request',
store.state.config.notificationVisibility.moves && 'move',
store.state.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reaction'
].filter(_ => _))
export const visibleTypes = store => {
const rootState = store.rootState || store.state
return ([
rootState.config.notificationVisibility.likes && 'like',
rootState.config.notificationVisibility.mentions && 'mention',
rootState.config.notificationVisibility.repeats && 'repeat',
rootState.config.notificationVisibility.follows && 'follow',
rootState.config.notificationVisibility.followRequest && 'follow_request',
rootState.config.notificationVisibility.moves && 'move',
rootState.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reaction'
].filter(_ => _))
}
const statusNotifications = ['like', 'mention', 'repeat', 'pleroma:emoji_reaction']
@ -32,6 +38,22 @@ const sortById = (a, b) => {
}
}
const isMutedNotification = (store, notification) => {
if (!notification.status) return
return notification.status.muted || muteWordHits(notification.status, store.rootGetters.mergedConfig.muteWords).length > 0
}
export const maybeShowNotification = (store, notification) => {
const rootState = store.rootState || store.state
if (notification.seen) return
if (!visibleTypes(store).includes(notification.type)) return
if (notification.type === 'mention' && isMutedNotification(store, notification)) return
const notificationObject = prepareNotificationObject(notification, store.rootGetters.i18n)
showDesktopNotification(rootState, notificationObject)
}
export const filteredNotificationsFromStore = (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)

View file

@ -35,7 +35,7 @@ const fetchAndUpdate = ({ store, credentials, older = false }) => {
const notifications = timelineData.data
const readNotifsIds = notifications.filter(n => n.seen).map(n => n.id)
const numUnseenNotifs = notifications.length - readNotifsIds.length
if (numUnseenNotifs > 0) {
if (numUnseenNotifs > 0 && readNotifsIds.length > 0) {
args['since'] = Math.max(...readNotifsIds)
fetchNotifications({ store, args, older })
}

View file

@ -11,7 +11,8 @@ const postStatus = ({
media = [],
inReplyToStatusId = undefined,
contentType = 'text/plain',
preview = false
preview = false,
idempotencyKey = ''
}) => {
const mediaIds = map(media, 'id')
@ -25,7 +26,8 @@ const postStatus = ({
inReplyToStatusId,
contentType,
poll,
preview
preview,
idempotencyKey
})
.then((data) => {
if (!data.error && !preview) {

View file

@ -675,23 +675,22 @@ export const SLOT_INHERITANCE = {
depends: ['bg']
},
chatMessage: {
depends: ['chatBg']
},
chatMessageIncomingBg: {
depends: ['chatMessage'],
layer: 'chatMessage'
depends: ['chatBg']
},
chatMessageIncomingText: {
depends: ['text'],
layer: 'text'
layer: 'chatMessage',
variant: 'chatMessageIncomingBg',
textColor: true
},
chatMessageIncomingLink: {
depends: ['link'],
layer: 'link'
layer: 'chatMessage',
variant: 'chatMessageIncomingBg',
textColor: 'preserve'
},
chatMessageIncomingBorder: {
@ -701,22 +700,27 @@ export const SLOT_INHERITANCE = {
},
chatMessageOutgoingBg: {
depends: ['chatMessage'],
depends: ['chatMessageIncomingBg'],
color: (mod, chatMessage) => brightness(5 * mod, chatMessage).rgb
},
chatMessageOutgoingText: {
depends: ['text'],
layer: 'text'
layer: 'chatMessage',
variant: 'chatMessageOutgoingBg',
textColor: true
},
chatMessageOutgoingLink: {
depends: ['link'],
layer: 'link'
layer: 'chatMessage',
variant: 'chatMessageOutgoingBg',
textColor: 'preserve'
},
chatMessageOutgoingBorder: {
depends: ['chatMessage'],
opacity: 'chatMessage'
depends: ['chatMessageOutgoingBg'],
opacity: 'border',
color: (mod, border) => brightness(2 * mod, border).rgb
}
}

View file

@ -128,14 +128,17 @@ export const topoSort = (
while (unprocessed.length > 0) {
step(unprocessed.pop())
}
return output.sort((a, b) => {
// The index thing is to make sorting stable on browsers
// where Array.sort() isn't stable
return output.map((data, index) => ({ data, index })).sort(({ data: a, index: ai }, { data: b, index: bi }) => {
const depsA = getDeps(a, inheritance).length
const depsB = getDeps(b, inheritance).length
if (depsA === depsB || (depsB !== 0 && depsA !== 0)) return 0
if (depsA === depsB || (depsB !== 0 && depsA !== 0)) return ai - bi
if (depsA === 0 && depsB !== 0) return -1
if (depsB === 0 && depsA !== 0) return 1
})
}).map(({ data }) => data)
}
const expandSlotValue = (value) => {

View file

@ -43,7 +43,9 @@ const fetchAndUpdate = ({
args['userId'] = userId
args['tag'] = tag
args['withMuted'] = !hideMutedPosts
if (loggedIn) args['replyVisibility'] = replyVisibility
if (loggedIn && ['friends', 'public', 'publicAndExternal'].includes(timeline)) {
args['replyVisibility'] = replyVisibility
}
const numStatusesBeforeFetch = timelineData.statuses.length