+
+
+
+ {{ themeWarningHelp }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('settings.presets') }}
+
r.name === emoji)
+ if (existingReaction && existingReaction.me) {
+ this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji })
+ } else {
+ this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
+ }
this.closeReactionSelect()
}
},
diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue
index c925dd71..fb43ebaf 100644
--- a/src/components/react_button/react_button.vue
+++ b/src/components/react_button/react_button.vue
@@ -54,6 +54,10 @@
.reaction-picker-filter {
padding: 0.5em;
+ display: flex;
+ input {
+ flex: 1;
+ }
}
.reaction-picker-divider {
diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue
index cef492f3..60cb8a87 100644
--- a/src/components/settings/settings.vue
+++ b/src/components/settings/settings.vue
@@ -92,6 +92,11 @@
{{ $t('settings.reply_link_preview') }}
+
+
+ {{ $t('settings.emoji_reactions_on_timeline') }}
+
+
@@ -328,6 +333,11 @@
{{ $t('settings.notification_visibility_moves') }}
+
+
+ {{ $t('settings.notification_visibility_emoji_reactions') }}
+
+
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 0a82dcbe..83f07dac 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -369,6 +369,7 @@
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 74e71fc8..d0d654d3 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -126,7 +126,8 @@
"read": "Read!",
"repeated_you": "repeated your status",
"no_more_notifications": "No more notifications",
- "migrated_to": "migrated to"
+ "migrated_to": "migrated to",
+ "reacted_with": "reacted with {0}"
},
"polls": {
"add_poll": "Add Poll",
@@ -283,6 +284,7 @@
"domain_mutes": "Domains",
"avatar_size_instruction": "The recommended minimum size for avatar images is 150x150 pixels.",
"pad_emoji": "Pad emoji with spaces when adding from picker",
+ "emoji_reactions_on_timeline": "Show emoji reactions on timeline",
"export_theme": "Save preset",
"filtering": "Filtering",
"filtering_explanation": "All statuses containing these words will be muted, one per line",
@@ -331,6 +333,7 @@
"notification_visibility_mentions": "Mentions",
"notification_visibility_repeats": "Repeats",
"notification_visibility_moves": "User Migrates",
+ "notification_visibility_emoji_reactions": "Reactions",
"no_rich_text_description": "Strip rich text formatting from all posts",
"no_blocks": "No blocks",
"no_mutes": "No mutes",
diff --git a/src/i18n/fi.json b/src/i18n/fi.json
index e7ed5408..ac8b2ac9 100644
--- a/src/i18n/fi.json
+++ b/src/i18n/fi.json
@@ -53,7 +53,8 @@
"notifications": "Ilmoitukset",
"read": "Lue!",
"repeated_you": "toisti viestisi",
- "no_more_notifications": "Ei enempää ilmoituksia"
+ "no_more_notifications": "Ei enempää ilmoituksia",
+ "reacted_with": "lisäsi reaktion {0}"
},
"polls": {
"add_poll": "Lisää äänestys",
@@ -140,6 +141,7 @@
"delete_account_description": "Poista tilisi ja viestisi pysyvästi.",
"delete_account_error": "Virhe poistaessa tiliäsi. Jos virhe jatkuu, ota yhteyttä palvelimesi ylläpitoon.",
"delete_account_instructions": "Syötä salasanasi vahvistaaksesi tilin poiston.",
+ "emoji_reactions_on_timeline": "Näytä emojireaktiot aikajanalla",
"export_theme": "Tallenna teema",
"filtering": "Suodatus",
"filtering_explanation": "Kaikki viestit, jotka sisältävät näitä sanoja, suodatetaan. Yksi sana per rivi.",
@@ -183,6 +185,7 @@
"notification_visibility_likes": "Tykkäykset",
"notification_visibility_mentions": "Maininnat",
"notification_visibility_repeats": "Toistot",
+ "notification_visibility_emoji_reactions": "Reaktiot",
"no_rich_text_description": "Älä näytä tekstin muotoilua.",
"hide_network_description": "Älä näytä seurauksiani tai seuraajiani",
"nsfw_clickthrough": "Piilota NSFW liitteet klikkauksen taakse",
diff --git a/src/modules/config.js b/src/modules/config.js
index de9f041b..8381fa53 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -20,6 +20,7 @@ export const defaultState = {
autoLoad: true,
streaming: false,
hoverPreview: true,
+ emojiReactionsOnTimeline: true,
autohideFloatingPostButton: false,
pauseOnUnfocused: true,
stopGifs: false,
@@ -29,7 +30,8 @@ export const defaultState = {
mentions: true,
likes: true,
repeats: true,
- moves: true
+ moves: true,
+ emojiReactions: false
},
webPushNotifications: false,
muteWords: [],
diff --git a/src/modules/statuses.js b/src/modules/statuses.js
index ea0c1749..25b62ac7 100644
--- a/src/modules/statuses.js
+++ b/src/modules/statuses.js
@@ -81,7 +81,8 @@ const visibleNotificationTypes = (rootState) => {
rootState.config.notificationVisibility.mentions && 'mention',
rootState.config.notificationVisibility.repeats && 'repeat',
rootState.config.notificationVisibility.follows && 'follow',
- rootState.config.notificationVisibility.moves && 'move'
+ rootState.config.notificationVisibility.moves && 'move',
+ rootState.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reactions'
].filter(_ => _)
}
@@ -325,6 +326,10 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
notification.status = notification.status && addStatusToGlobalStorage(state, notification.status).item
}
+ if (notification.type === 'pleroma:emoji_reaction') {
+ dispatch('fetchEmojiReactionsBy', notification.status.id)
+ }
+
// Only add a new notification if we don't have one for the same action
if (!state.notifications.idStore.hasOwnProperty(notification.id)) {
state.notifications.maxId = notification.id > state.notifications.maxId
@@ -358,7 +363,9 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
break
}
- if (i18nString) {
+ if (notification.type === 'pleroma:emoji_reaction') {
+ notifObj.body = rootGetters.i18n.t('notifications.reacted_with', [notification.emoji])
+ } else if (i18nString) {
notifObj.body = rootGetters.i18n.t('notifications.' + i18nString)
} else {
notifObj.body = notification.status.text
@@ -371,10 +378,10 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
}
if (!notification.seen && !state.notifications.desktopNotificationSilence && visibleNotificationTypes.includes(notification.type)) {
- let notification = new window.Notification(title, notifObj)
+ let desktopNotification = new window.Notification(title, notifObj)
// Chrome is known for not closing notifications automatically
// according to MDN, anyway.
- setTimeout(notification.close.bind(notification), 5000)
+ setTimeout(desktopNotification.close.bind(desktopNotification), 5000)
}
}
} else if (notification.seen) {
@@ -537,12 +544,13 @@ export const mutations = {
},
addOwnReaction (state, { id, emoji, currentUser }) {
const status = state.allStatusesObject[id]
- const reactionIndex = findIndex(status.emoji_reactions, { emoji })
- const reaction = status.emoji_reactions[reactionIndex] || { emoji, count: 0, accounts: [] }
+ const reactionIndex = findIndex(status.emoji_reactions, { name: emoji })
+ const reaction = status.emoji_reactions[reactionIndex] || { name: emoji, count: 0, accounts: [] }
const newReaction = {
...reaction,
count: reaction.count + 1,
+ me: true,
accounts: [
...reaction.accounts,
currentUser
@@ -558,21 +566,23 @@ export const mutations = {
},
removeOwnReaction (state, { id, emoji, currentUser }) {
const status = state.allStatusesObject[id]
- const reactionIndex = findIndex(status.emoji_reactions, { emoji })
+ const reactionIndex = findIndex(status.emoji_reactions, { name: emoji })
if (reactionIndex < 0) return
const reaction = status.emoji_reactions[reactionIndex]
+ const accounts = reaction.accounts || []
const newReaction = {
...reaction,
count: reaction.count - 1,
- accounts: reaction.accounts.filter(acc => acc.id === currentUser.id)
+ me: false,
+ accounts: accounts.filter(acc => acc.id !== currentUser.id)
}
if (newReaction.count > 0) {
set(status.emoji_reactions, reactionIndex, newReaction)
} else {
- set(status, 'emoji_reactions', status.emoji_reactions.filter(r => r.emoji !== emoji))
+ set(status, 'emoji_reactions', status.emoji_reactions.filter(r => r.name !== emoji))
}
},
updateStatusWithPoll (state, { id, poll }) {
@@ -681,18 +691,22 @@ const statuses = {
},
reactWithEmoji ({ rootState, dispatch, commit }, { id, emoji }) {
const currentUser = rootState.users.currentUser
+ if (!currentUser) return
+
commit('addOwnReaction', { id, emoji, currentUser })
rootState.api.backendInteractor.reactWithEmoji({ id, emoji }).then(
- status => {
+ ok => {
dispatch('fetchEmojiReactionsBy', id)
}
)
},
unreactWithEmoji ({ rootState, dispatch, commit }, { id, emoji }) {
const currentUser = rootState.users.currentUser
+ if (!currentUser) return
+
commit('removeOwnReaction', { id, emoji, currentUser })
rootState.api.backendInteractor.unreactWithEmoji({ id, emoji }).then(
- status => {
+ ok => {
dispatch('fetchEmojiReactionsBy', id)
}
)
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index b794fd58..20eaa9a0 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -74,9 +74,9 @@ const MASTODON_SEARCH_2 = `/api/v2/search`
const MASTODON_USER_SEARCH_URL = '/api/v1/accounts/search'
const MASTODON_DOMAIN_BLOCKS_URL = '/api/v1/domain_blocks'
const MASTODON_STREAMING = '/api/v1/streaming'
-const PLEROMA_EMOJI_REACTIONS_URL = id => `/api/v1/pleroma/statuses/${id}/emoji_reactions_by`
-const PLEROMA_EMOJI_REACT_URL = id => `/api/v1/pleroma/statuses/${id}/react_with_emoji`
-const PLEROMA_EMOJI_UNREACT_URL = id => `/api/v1/pleroma/statuses/${id}/unreact_with_emoji`
+const PLEROMA_EMOJI_REACTIONS_URL = id => `/api/v1/pleroma/statuses/${id}/reactions`
+const PLEROMA_EMOJI_REACT_URL = (id, emoji) => `/api/v1/pleroma/statuses/${id}/reactions/${emoji}`
+const PLEROMA_EMOJI_UNREACT_URL = (id, emoji) => `/api/v1/pleroma/statuses/${id}/reactions/${emoji}`
const oldfetch = window.fetch
@@ -888,25 +888,27 @@ const fetchRebloggedByUsers = ({ id }) => {
return promisedRequest({ url: MASTODON_STATUS_REBLOGGEDBY_URL(id) }).then((users) => users.map(parseUser))
}
-const fetchEmojiReactions = ({ id }) => {
- return promisedRequest({ url: PLEROMA_EMOJI_REACTIONS_URL(id) })
+const fetchEmojiReactions = ({ id, credentials }) => {
+ return promisedRequest({ url: PLEROMA_EMOJI_REACTIONS_URL(id), credentials })
+ .then((reactions) => reactions.map(r => {
+ r.accounts = r.accounts.map(parseUser)
+ return r
+ }))
}
const reactWithEmoji = ({ id, emoji, credentials }) => {
return promisedRequest({
- url: PLEROMA_EMOJI_REACT_URL(id),
- method: 'POST',
- credentials,
- payload: { emoji }
+ url: PLEROMA_EMOJI_REACT_URL(id, emoji),
+ method: 'PUT',
+ credentials
}).then(parseStatus)
}
const unreactWithEmoji = ({ id, emoji, credentials }) => {
return promisedRequest({
- url: PLEROMA_EMOJI_UNREACT_URL(id),
- method: 'POST',
- credentials,
- payload: { emoji }
+ url: PLEROMA_EMOJI_UNREACT_URL(id, emoji),
+ method: 'DELETE',
+ credentials
}).then(parseStatus)
}
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index 0a8abbbd..84169a7b 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -354,6 +354,7 @@ export const parseNotification = (data) => {
? null
: parseUser(data.target)
output.from_profile = parseUser(data.account)
+ output.emoji = data.emoji
} else {
const parsedNotice = parseStatus(data.notice)
output.type = data.ntype
diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js
index 860620fc..b17bd7bf 100644
--- a/src/services/notification_utils/notification_utils.js
+++ b/src/services/notification_utils/notification_utils.js
@@ -7,7 +7,8 @@ export const visibleTypes = store => ([
store.state.config.notificationVisibility.mentions && 'mention',
store.state.config.notificationVisibility.repeats && 'repeat',
store.state.config.notificationVisibility.follows && 'follow',
- store.state.config.notificationVisibility.moves && 'move'
+ store.state.config.notificationVisibility.moves && 'move',
+ store.state.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reaction'
].filter(_ => _))
const sortById = (a, b) => {
diff --git a/test/unit/specs/modules/statuses.spec.js b/test/unit/specs/modules/statuses.spec.js
index e53aa388..fe42e85b 100644
--- a/test/unit/specs/modules/statuses.spec.js
+++ b/test/unit/specs/modules/statuses.spec.js
@@ -245,11 +245,12 @@ describe('Statuses module', () => {
it('increments count in existing reaction', () => {
const state = defaultState()
const status = makeMockStatus({ id: '1' })
- status.emoji_reactions = [ { emoji: '😂', count: 1, accounts: [] } ]
+ status.emoji_reactions = [ { name: '😂', count: 1, accounts: [] } ]
mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
mutations.addOwnReaction(state, { id: '1', emoji: '😂', currentUser: { id: 'me' } })
expect(state.allStatusesObject['1'].emoji_reactions[0].count).to.eql(2)
+ expect(state.allStatusesObject['1'].emoji_reactions[0].me).to.eql(true)
expect(state.allStatusesObject['1'].emoji_reactions[0].accounts[0].id).to.eql('me')
})
@@ -261,27 +262,29 @@ describe('Statuses module', () => {
mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
mutations.addOwnReaction(state, { id: '1', emoji: '😂', currentUser: { id: 'me' } })
expect(state.allStatusesObject['1'].emoji_reactions[0].count).to.eql(1)
+ expect(state.allStatusesObject['1'].emoji_reactions[0].me).to.eql(true)
expect(state.allStatusesObject['1'].emoji_reactions[0].accounts[0].id).to.eql('me')
})
it('decreases count in existing reaction', () => {
const state = defaultState()
const status = makeMockStatus({ id: '1' })
- status.emoji_reactions = [ { emoji: '😂', count: 2, accounts: [{ id: 'me' }] } ]
+ status.emoji_reactions = [ { name: '😂', count: 2, accounts: [{ id: 'me' }] } ]
mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
- mutations.removeOwnReaction(state, { id: '1', emoji: '😂', currentUser: {} })
+ mutations.removeOwnReaction(state, { id: '1', emoji: '😂', currentUser: { id: 'me' } })
expect(state.allStatusesObject['1'].emoji_reactions[0].count).to.eql(1)
+ expect(state.allStatusesObject['1'].emoji_reactions[0].me).to.eql(false)
expect(state.allStatusesObject['1'].emoji_reactions[0].accounts).to.eql([])
})
it('removes a reaction', () => {
const state = defaultState()
const status = makeMockStatus({ id: '1' })
- status.emoji_reactions = [{ emoji: '😂', count: 1, accounts: [{ id: 'me' }] }]
+ status.emoji_reactions = [{ name: '😂', count: 1, accounts: [{ id: 'me' }] }]
mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
- mutations.removeOwnReaction(state, { id: '1', emoji: '😂', currentUser: {} })
+ mutations.removeOwnReaction(state, { id: '1', emoji: '😂', currentUser: { id: 'me' } })
expect(state.allStatusesObject['1'].emoji_reactions.length).to.eql(0)
})
})
--
cgit v1.2.3-70-g09d2
From 0702934f4f05595194c73cc463b2e72a27e3b1e2 Mon Sep 17 00:00:00 2001
From: Henry Jameson
Date: Wed, 4 Mar 2020 00:23:14 +0200
Subject: fix trasparency problems in some cases (purple headers)
---
src/modules/config.js | 1 +
src/services/theme_data/theme_data.service.js | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
(limited to 'src/modules/config.js')
diff --git a/src/modules/config.js b/src/modules/config.js
index e6b373b4..7997521d 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -102,6 +102,7 @@ const config = {
setPreset(value)
break
case 'customTheme':
+ case 'customThemeSource':
applyTheme(value)
}
}
diff --git a/src/services/theme_data/theme_data.service.js b/src/services/theme_data/theme_data.service.js
index e6ff82e6..de6561cd 100644
--- a/src/services/theme_data/theme_data.service.js
+++ b/src/services/theme_data/theme_data.service.js
@@ -352,7 +352,8 @@ export const getColors = (sourceColors, sourceOpacity) => SLOT_ORDERED.reduce(({
}
const opacitySlot = getOpacitySlot(key)
const ownOpacitySlot = value.opacity
- if (opacitySlot && (outputColor.a === undefined || ownOpacitySlot)) {
+ const opacityOverriden = ownOpacitySlot && sourceOpacity[opacitySlot] !== undefined
+ if (opacitySlot && (outputColor.a === undefined || opacityOverriden)) {
const dependencySlot = deps[0]
if (dependencySlot && colors[dependencySlot] === 'transparent') {
outputColor.a = 0
--
cgit v1.2.3-70-g09d2
From 01b07f01e9340935faf51e5a3c8034cc90423989 Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Sat, 25 Apr 2020 07:04:39 +0300
Subject: Add support for follow request notifications
---
CHANGELOG.md | 3 ++
src/components/notification/notification.js | 19 ++++++++++
src/components/notification/notification.vue | 44 ++++++++++++++++------
src/components/notifications/notifications.scss | 15 ++++++++
src/i18n/en.json | 5 ++-
src/modules/config.js | 3 +-
src/modules/statuses.js | 22 ++++++++++-
src/services/api/api.service.js | 11 ++++++
.../entity_normalizer/entity_normalizer.service.js | 5 +--
.../notification_utils/notification_utils.js | 7 +++-
static/fontello.json | 14 ++++++-
11 files changed, 128 insertions(+), 20 deletions(-)
(limited to 'src/modules/config.js')
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f45561d0..685fe629 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed
- Emoji autocomplete will match any part of the word and not just start, for example :drool will now helpfully suggest :blobcatdrool: and :blobcatdroolreach:
+### Add
+- Follow request notification support
+
## [2.0.2] - 2020-04-08
### Fixed
- Favorite/Repeat avatars not showing up on private instances/non-public posts
diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js
index e7bd769e..6deee7d5 100644
--- a/src/components/notification/notification.js
+++ b/src/components/notification/notification.js
@@ -2,6 +2,7 @@ import Status from '../status/status.vue'
import UserAvatar from '../user_avatar/user_avatar.vue'
import UserCard from '../user_card/user_card.vue'
import Timeago from '../timeago/timeago.vue'
+import { isStatusNotification } from '../../services/notification_utils/notification_utils.js'
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
@@ -32,6 +33,21 @@ const Notification = {
},
toggleMute () {
this.unmuted = !this.unmuted
+ },
+ approveUser () {
+ this.$store.state.api.backendInteractor.approveUser({ id: this.user.id })
+ this.$store.dispatch('removeFollowRequest', this.user)
+ this.$store.dispatch('updateNotification', {
+ id: this.notification.id,
+ updater: notification => {
+ notification.type = 'follow'
+ }
+ })
+ },
+ denyUser () {
+ this.$store.state.api.backendInteractor.denyUser({ id: this.user.id })
+ this.$store.dispatch('removeFollowRequest', this.user)
+ this.$store.dispatch('dismissNotification', { id: this.notification.id })
}
},
computed: {
@@ -57,6 +73,9 @@ const Notification = {
},
needMute () {
return this.user.muted
+ },
+ isStatusNotification () {
+ return isStatusNotification(this.notification.type)
}
}
}
diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue
index 51875747..02802776 100644
--- a/src/components/notification/notification.vue
+++ b/src/components/notification/notification.vue
@@ -74,6 +74,10 @@
{{ $t('notifications.followed_you') }}
+
+
+ {{ $t('notifications.follow_request') }}
+
{{ $t('notifications.migrated_to') }}
@@ -87,30 +91,30 @@
-
+
-
+
-
+
-
+
-
+
@{{ notification.from_profile.screen_name }}
+
+
+
+
{
each(notifications, (notification) => {
- if (notification.type !== 'follow' && notification.type !== 'move') {
+ if (isStatusNotification(notification.type)) {
notification.action = addStatusToGlobalStorage(state, notification.action).item
notification.status = notification.status && addStatusToGlobalStorage(state, notification.status).item
}
@@ -361,13 +362,16 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
case 'move':
i18nString = 'migrated_to'
break
+ case 'follow_request':
+ i18nString = 'follow_request'
+ break
}
if (notification.type === 'pleroma:emoji_reaction') {
notifObj.body = rootGetters.i18n.t('notifications.reacted_with', [notification.emoji])
} else if (i18nString) {
notifObj.body = rootGetters.i18n.t('notifications.' + i18nString)
- } else {
+ } else if (isStatusNotification(notification.type)) {
notifObj.body = notification.status.text
}
@@ -521,6 +525,13 @@ export const mutations = {
notification.seen = true
})
},
+ dismissNotification (state, { id }) {
+ state.notifications.data = state.notifications.data.filter(n => n.id !== id)
+ },
+ updateNotification (state, { id, updater }) {
+ const notification = find(state.notifications.data, n => n.id === id)
+ notification && updater(notification)
+ },
queueFlush (state, { timeline, id }) {
state.timelines[timeline].flushMarker = id
},
@@ -680,6 +691,13 @@ const statuses = {
credentials: rootState.users.currentUser.credentials
})
},
+ dismissNotification ({ rootState, commit }, { id }) {
+ rootState.api.backendInteractor.dismissNotification({ id })
+ .then(() => commit('dismissNotification', { id }))
+ },
+ updateNotification ({ rootState, commit }, { id, updater }) {
+ commit('updateNotification', { id, updater })
+ },
fetchFavsAndRepeats ({ rootState, commit }, id) {
Promise.all([
rootState.api.backendInteractor.fetchFavoritedByUsers({ id }),
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index ad2b2ad5..cda61ee2 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -29,6 +29,7 @@ const MASTODON_LOGIN_URL = '/api/v1/accounts/verify_credentials'
const MASTODON_REGISTRATION_URL = '/api/v1/accounts'
const MASTODON_USER_FAVORITES_TIMELINE_URL = '/api/v1/favourites'
const MASTODON_USER_NOTIFICATIONS_URL = '/api/v1/notifications'
+const MASTODON_DISMISS_NOTIFICATION_URL = id => `/api/v1/notifications/${id}/dismiss`
const MASTODON_FAVORITE_URL = id => `/api/v1/statuses/${id}/favourite`
const MASTODON_UNFAVORITE_URL = id => `/api/v1/statuses/${id}/unfavourite`
const MASTODON_RETWEET_URL = id => `/api/v1/statuses/${id}/reblog`
@@ -1010,6 +1011,15 @@ const unmuteDomain = ({ domain, credentials }) => {
})
}
+const dismissNotification = ({ credentials, id }) => {
+ return promisedRequest({
+ url: MASTODON_DISMISS_NOTIFICATION_URL(id),
+ method: 'POST',
+ payload: { id },
+ credentials
+ })
+}
+
export const getMastodonSocketURI = ({ credentials, stream, args = {} }) => {
return Object.entries({
...(credentials
@@ -1165,6 +1175,7 @@ const apiService = {
denyUser,
suggestions,
markNotificationsAsSeen,
+ dismissNotification,
vote,
fetchPoll,
fetchFavoritedByUsers,
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index 84169a7b..6cacd0b8 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -1,4 +1,5 @@
import escape from 'escape-html'
+import { isStatusNotification } from '../notification_utils/notification_utils.js'
const qvitterStatusType = (status) => {
if (status.is_post_verb) {
@@ -346,9 +347,7 @@ export const parseNotification = (data) => {
if (masto) {
output.type = mastoDict[data.type] || data.type
output.seen = data.pleroma.is_seen
- output.status = output.type === 'follow' || output.type === 'move'
- ? null
- : parseStatus(data.status)
+ output.status = isStatusNotification(output.type) ? parseStatus(data.status) : null
output.action = output.status // TODO: Refactor, this is unneeded
output.target = output.type !== 'move'
? null
diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js
index b17bd7bf..eb479227 100644
--- a/src/services/notification_utils/notification_utils.js
+++ b/src/services/notification_utils/notification_utils.js
@@ -1,4 +1,4 @@
-import { filter, sortBy } from 'lodash'
+import { filter, sortBy, includes } from 'lodash'
export const notificationsFromStore = store => store.state.statuses.notifications.data
@@ -7,10 +7,15 @@ export const visibleTypes = store => ([
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(_ => _))
+const statusNotifications = ['like', 'mention', 'repeat', 'pleroma:emoji_reaction']
+
+export const isStatusNotification = (type) => includes(statusNotifications, type)
+
const sortById = (a, b) => {
const seqA = Number(a.id)
const seqB = Number(b.id)
diff --git a/static/fontello.json b/static/fontello.json
index 5a7086a2..5963b68b 100755
--- a/static/fontello.json
+++ b/static/fontello.json
@@ -345,6 +345,18 @@
"css": "link",
"code": 59427,
"src": "fontawesome"
+ },
+ {
+ "uid": "8b80d36d4ef43889db10bc1f0dc9a862",
+ "css": "user",
+ "code": 59428,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "12f4ece88e46abd864e40b35e05b11cd",
+ "css": "ok",
+ "code": 59431,
+ "src": "fontawesome"
}
]
-}
+}
\ No newline at end of file
--
cgit v1.2.3-70-g09d2
From 5187b37aca4d6ca177c254f999e6acb637db5532 Mon Sep 17 00:00:00 2001
From: Henry Jameson
Date: Tue, 26 May 2020 22:50:37 +0300
Subject: moved multiChoiceProperties where it fits better
---
.../settings_modal/tabs/helpers/shared_computed_object.js | 11 +++++------
src/modules/config.js | 10 ++++++++++
2 files changed, 15 insertions(+), 6 deletions(-)
(limited to 'src/modules/config.js')
diff --git a/src/components/settings_modal/tabs/helpers/shared_computed_object.js b/src/components/settings_modal/tabs/helpers/shared_computed_object.js
index 61643e3b..b6a18e9c 100644
--- a/src/components/settings_modal/tabs/helpers/shared_computed_object.js
+++ b/src/components/settings_modal/tabs/helpers/shared_computed_object.js
@@ -1,10 +1,9 @@
import { filter, trim } from 'lodash'
-import { instanceDefaultProperties, defaultState as configDefaultState } from 'src/modules/config.js'
-
-const multiChoiceProperties = [
- 'postContentType',
- 'subjectLineBehavior'
-]
+import {
+ instanceDefaultProperties,
+ multiChoiceProperties,
+ defaultState as configDefaultState
+} from 'src/modules/config.js'
const SharedComputedObject = () => ({
user () {
diff --git a/src/modules/config.js b/src/modules/config.js
index 8f4638f5..b6b1b241 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -3,6 +3,16 @@ import { setPreset, applyTheme } from '../services/style_setter/style_setter.js'
const browserLocale = (window.navigator.language || 'en').split('-')[0]
+/* TODO this is a bit messy.
+ * We need to declare settings with their types and also deal with
+ * instance-default settings in some way, hopefully try to avoid copy-pasta
+ * in general.
+ */
+export const multiChoiceProperties = [
+ 'postContentType',
+ 'subjectLineBehavior'
+]
+
export const defaultState = {
colors: {},
theme: undefined,
--
cgit v1.2.3-70-g09d2
From 99eaec85478f384ddb0ea45a9d9c95c4dce646f5 Mon Sep 17 00:00:00 2001
From: lain
Date: Mon, 8 Jun 2020 17:22:07 +0200
Subject: Messages: Load languages asynchronously.
Reduces the size of the initial app bundle by about half.
---
src/App.js | 3 +-
.../interface_language_switcher.vue | 3 +-
src/i18n/messages.js | 95 ++++++++++++++++------
src/main.js | 6 +-
src/modules/config.js | 5 ++
5 files changed, 80 insertions(+), 32 deletions(-)
(limited to 'src/modules/config.js')
diff --git a/src/App.js b/src/App.js
index 6445335a..040138c9 100644
--- a/src/App.js
+++ b/src/App.js
@@ -47,7 +47,8 @@ export default {
}),
created () {
// Load the locale from the storage
- this.$i18n.locale = this.$store.getters.mergedConfig.interfaceLanguage
+ const val = this.$store.getters.mergedConfig.interfaceLanguage
+ this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val })
window.addEventListener('resize', this.updateMobileState)
},
destroyed () {
diff --git a/src/components/interface_language_switcher/interface_language_switcher.vue b/src/components/interface_language_switcher/interface_language_switcher.vue
index f5ace0cc..dd6800a3 100644
--- a/src/components/interface_language_switcher/interface_language_switcher.vue
+++ b/src/components/interface_language_switcher/interface_language_switcher.vue
@@ -32,7 +32,7 @@ import _ from 'lodash'
export default {
computed: {
languageCodes () {
- return Object.keys(languagesObject)
+ return languagesObject.languages
},
languageNames () {
@@ -43,7 +43,6 @@ export default {
get: function () { return this.$store.getters.mergedConfig.interfaceLanguage },
set: function (val) {
this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val })
- this.$i18n.locale = val
}
}
},
diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index c56ae205..a257486f 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -7,34 +7,75 @@
// sed -i -e "s/'//gm" -e 's/"/\\"/gm' -re 's/^( +)(.+?): ((.+?))?(,?)(\{?)$/\1"\2": "\4"/gm' -e 's/\"\{\"/{/g' -e 's/,"$/",/g' file.json
// There's only problem that apostrophe character ' gets replaced by \\ so you have to fix it manually, sorry.
+const loaders = {
+ ar: () => import('./ar.json'),
+ ca: () => import('./ca.json'),
+ cs: () => import('./cs.json'),
+ de: () => import('./de.json'),
+ eo: () => import('./eo.json'),
+ es: () => import('./es.json'),
+ et: () => import('./et.json'),
+ eu: () => import('./eu.json'),
+ fi: () => import('./fi.json'),
+ fr: () => import('./fr.json'),
+ ga: () => import('./ga.json'),
+ he: () => import('./he.json'),
+ hu: () => import('./hu.json'),
+ it: () => import('./it.json'),
+ ja: () => import('./ja_pedantic.json'),
+ ja_easy: () => import('./ja_easy.json'),
+ ko: () => import('./ko.json'),
+ nb: () => import('./nb.json'),
+ nl: () => import('./nl.json'),
+ oc: () => import('./oc.json'),
+ pl: () => import('./pl.json'),
+ pt: () => import('./pt.json'),
+ ro: () => import('./ro.json'),
+ ru: () => import('./ru.json'),
+ te: () => import('./te.json'),
+ zh: () => import('./zh.json')
+}
+
const messages = {
- ar: require('./ar.json'),
- ca: require('./ca.json'),
- cs: require('./cs.json'),
- de: require('./de.json'),
- en: require('./en.json'),
- eo: require('./eo.json'),
- es: require('./es.json'),
- et: require('./et.json'),
- eu: require('./eu.json'),
- fi: require('./fi.json'),
- fr: require('./fr.json'),
- ga: require('./ga.json'),
- he: require('./he.json'),
- hu: require('./hu.json'),
- it: require('./it.json'),
- ja: require('./ja_pedantic.json'),
- ja_easy: require('./ja_easy.json'),
- ko: require('./ko.json'),
- nb: require('./nb.json'),
- nl: require('./nl.json'),
- oc: require('./oc.json'),
- pl: require('./pl.json'),
- pt: require('./pt.json'),
- ro: require('./ro.json'),
- ru: require('./ru.json'),
- te: require('./te.json'),
- zh: require('./zh.json')
+ languages: [
+ 'ar',
+ 'ca',
+ 'cs',
+ 'de',
+ 'en',
+ 'eo',
+ 'es',
+ 'et',
+ 'eu',
+ 'fi',
+ 'fr',
+ 'ga',
+ 'he',
+ 'hu',
+ 'it',
+ 'ja',
+ 'ja_easy',
+ 'ko',
+ 'nb',
+ 'nl',
+ 'oc',
+ 'pl',
+ 'pt',
+ 'ro',
+ 'ru',
+ 'te',
+ 'zh'
+ ],
+ default: {
+ en: require('./en.json')
+ },
+ setLanguage: async (i18n, language) => {
+ if (loaders[language]) {
+ let messages = await loaders[language]()
+ i18n.setLocaleMessage(language, messages)
+ }
+ i18n.locale = language
+ }
}
export default messages
diff --git a/src/main.js b/src/main.js
index be4213fa..9a201e4f 100644
--- a/src/main.js
+++ b/src/main.js
@@ -46,11 +46,13 @@ Vue.use(VBodyScrollLock)
const i18n = new VueI18n({
// By default, use the browser locale, we will update it if neccessary
- locale: currentLocale,
+ locale: 'en',
fallbackLocale: 'en',
- messages
+ messages: messages.default
})
+messages.setLanguage(i18n, currentLocale)
+
const persistedStateOptions = {
paths: [
'config',
diff --git a/src/modules/config.js b/src/modules/config.js
index b6b1b241..47b24d77 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -1,5 +1,6 @@
import { set, delete as del } from 'vue'
import { setPreset, applyTheme } from '../services/style_setter/style_setter.js'
+import messages from '../i18n/messages'
const browserLocale = (window.navigator.language || 'en').split('-')[0]
@@ -115,6 +116,10 @@ const config = {
case 'customTheme':
case 'customThemeSource':
applyTheme(value)
+ break
+ case 'interfaceLanguage':
+ messages.setLanguage(this.getters.i18n, value)
+ break
}
}
}
--
cgit v1.2.3-70-g09d2