aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShpuld Shpludson <shp@cock.li>2020-05-08 08:20:03 +0000
committerShpuld Shpludson <shp@cock.li>2020-05-08 08:20:03 +0000
commitf4676e17d3ec15f7c8bad776a7c7799f83f679b0 (patch)
tree6d7a1ddb581a3879165828c059596847408638b3 /src
parentddc3b86d24249021cc1634dbdfb476684265f293 (diff)
parentf40de85b92f55903da39c5c0f1b8db6ca7cb88f6 (diff)
Merge branch 'develop' into 'feature/copy-link'
# Conflicts: # static/fontello.json
Diffstat (limited to 'src')
-rw-r--r--src/boot/after_store.js3
-rw-r--r--src/components/emoji_input/suggestor.js24
-rw-r--r--src/components/follow_request_card/follow_request_card.js22
-rw-r--r--src/components/notification/notification.js22
-rw-r--r--src/components/notification/notification.vue46
-rw-r--r--src/components/notifications/notifications.scss34
-rw-r--r--src/components/registration/registration.js25
-rw-r--r--src/components/status/status.js35
-rw-r--r--src/components/user_settings/user_settings.vue12
-rw-r--r--src/i18n/en.json8
-rw-r--r--src/i18n/pl.json320
-rw-r--r--src/modules/config.js3
-rw-r--r--src/modules/statuses.js37
-rw-r--r--src/services/api/api.service.js47
-rw-r--r--src/services/entity_normalizer/entity_normalizer.service.js5
-rw-r--r--src/services/notification_utils/notification_utils.js7
-rw-r--r--src/services/notifications_fetcher/notifications_fetcher.service.js3
17 files changed, 568 insertions, 85 deletions
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index d70e1058..9fb9a853 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -241,6 +241,9 @@ const getNodeInfo = async ({ store }) => {
: federation.enabled
})
+ const accountActivationRequired = metadata.accountActivationRequired
+ store.dispatch('setInstanceOption', { name: 'accountActivationRequired', value: accountActivationRequired })
+
const accounts = metadata.staffAccounts
resolveStaffAccounts({ store, accounts })
} else {
diff --git a/src/components/emoji_input/suggestor.js b/src/components/emoji_input/suggestor.js
index aec5c39d..15a71eff 100644
--- a/src/components/emoji_input/suggestor.js
+++ b/src/components/emoji_input/suggestor.js
@@ -29,17 +29,29 @@ export default data => input => {
export const suggestEmoji = emojis => input => {
const noPrefix = input.toLowerCase().substr(1)
return emojis
- .filter(({ displayText }) => displayText.toLowerCase().startsWith(noPrefix))
+ .filter(({ displayText }) => displayText.toLowerCase().match(noPrefix))
.sort((a, b) => {
let aScore = 0
let bScore = 0
- // Make custom emojis a priority
- aScore += a.imageUrl ? 10 : 0
- bScore += b.imageUrl ? 10 : 0
+ // An exact match always wins
+ aScore += a.displayText.toLowerCase() === noPrefix ? 200 : 0
+ bScore += b.displayText.toLowerCase() === noPrefix ? 200 : 0
- // Sort alphabetically
- const alphabetically = a.displayText > b.displayText ? 1 : -1
+ // Prioritize custom emoji a lot
+ aScore += a.imageUrl ? 100 : 0
+ bScore += b.imageUrl ? 100 : 0
+
+ // Prioritize prefix matches somewhat
+ aScore += a.displayText.toLowerCase().startsWith(noPrefix) ? 10 : 0
+ bScore += b.displayText.toLowerCase().startsWith(noPrefix) ? 10 : 0
+
+ // Sort by length
+ aScore -= a.displayText.length
+ bScore -= b.displayText.length
+
+ // Break ties alphabetically
+ const alphabetically = a.displayText > b.displayText ? 0.5 : -0.5
return bScore - aScore + alphabetically
})
diff --git a/src/components/follow_request_card/follow_request_card.js b/src/components/follow_request_card/follow_request_card.js
index a8931787..cbd75311 100644
--- a/src/components/follow_request_card/follow_request_card.js
+++ b/src/components/follow_request_card/follow_request_card.js
@@ -1,4 +1,5 @@
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
+import { notificationsFromStore } from '../../services/notification_utils/notification_utils.js'
const FollowRequestCard = {
props: ['user'],
@@ -6,13 +7,32 @@ const FollowRequestCard = {
BasicUserCard
},
methods: {
+ findFollowRequestNotificationId () {
+ const notif = notificationsFromStore(this.$store).find(
+ (notif) => notif.from_profile.id === this.user.id && notif.type === 'follow_request'
+ )
+ return notif && notif.id
+ },
approveUser () {
this.$store.state.api.backendInteractor.approveUser({ id: this.user.id })
this.$store.dispatch('removeFollowRequest', this.user)
+
+ const notifId = this.findFollowRequestNotificationId()
+ this.$store.dispatch('markSingleNotificationAsSeen', { id: notifId })
+ this.$store.dispatch('updateNotification', {
+ id: notifId,
+ updater: notification => {
+ notification.type = 'follow'
+ }
+ })
},
denyUser () {
+ const notifId = this.findFollowRequestNotificationId()
this.$store.state.api.backendInteractor.denyUser({ id: this.user.id })
- this.$store.dispatch('removeFollowRequest', this.user)
+ .then(() => {
+ this.$store.dispatch('dismissNotificationLocal', { id: notifId })
+ this.$store.dispatch('removeFollowRequest', this.user)
+ })
}
}
}
diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js
index e7bd769e..1ae81ce4 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,24 @@ 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('markSingleNotificationAsSeen', { id: this.notification.id })
+ this.$store.dispatch('updateNotification', {
+ id: this.notification.id,
+ updater: notification => {
+ notification.type = 'follow'
+ }
+ })
+ },
+ denyUser () {
+ this.$store.state.api.backendInteractor.denyUser({ id: this.user.id })
+ .then(() => {
+ this.$store.dispatch('dismissNotificationLocal', { id: this.notification.id })
+ this.$store.dispatch('removeFollowRequest', this.user)
+ })
}
},
computed: {
@@ -57,6 +76,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 411c0271..f6da07dd 100644
--- a/src/components/notification/notification.vue
+++ b/src/components/notification/notification.vue
@@ -47,7 +47,7 @@
<span class="notification-details">
<div class="name-and-action">
<!-- eslint-disable vue/no-v-html -->
- <span
+ <bdi
v-if="!!notification.from_profile.name_html"
class="username"
:title="'@'+notification.from_profile.screen_name"
@@ -74,6 +74,10 @@
<i class="fa icon-user-plus lit" />
<small>{{ $t('notifications.followed_you') }}</small>
</span>
+ <span v-if="notification.type === 'follow_request'">
+ <i class="fa icon-user lit" />
+ <small>{{ $t('notifications.follow_request') }}</small>
+ </span>
<span v-if="notification.type === 'move'">
<i class="fa icon-arrow-curved lit" />
<small>{{ $t('notifications.migrated_to') }}</small>
@@ -87,30 +91,30 @@
</span>
</div>
<div
- v-if="notification.type === 'follow' || notification.type === 'move'"
+ v-if="isStatusNotification"
class="timeago"
>
- <span class="faint">
+ <router-link
+ v-if="notification.status"
+ :to="{ name: 'conversation', params: { id: notification.status.id } }"
+ class="faint-link"
+ >
<Timeago
:time="notification.created_at"
:auto-update="240"
/>
- </span>
+ </router-link>
</div>
<div
v-else
class="timeago"
>
- <router-link
- v-if="notification.status"
- :to="{ name: 'conversation', params: { id: notification.status.id } }"
- class="faint-link"
- >
+ <span class="faint">
<Timeago
:time="notification.created_at"
:auto-update="240"
/>
- </router-link>
+ </span>
</div>
<a
v-if="needMute"
@@ -119,12 +123,30 @@
><i class="button-icon icon-eye-off" /></a>
</span>
<div
- v-if="notification.type === 'follow'"
+ v-if="notification.type === 'follow' || notification.type === 'follow_request'"
class="follow-text"
>
- <router-link :to="userProfileLink">
+ <router-link
+ :to="userProfileLink"
+ class="follow-name"
+ >
@{{ notification.from_profile.screen_name }}
</router-link>
+ <div
+ v-if="notification.type === 'follow_request'"
+ style="white-space: nowrap;"
+ >
+ <i
+ class="icon-ok button-icon follow-request-accept"
+ :title="$t('tool_tip.accept_follow_request')"
+ @click="approveUser()"
+ />
+ <i
+ class="icon-cancel button-icon follow-request-reject"
+ :title="$t('tool_tip.reject_follow_request')"
+ @click="denyUser()"
+ />
+ </div>
</div>
<div
v-else-if="notification.type === 'move'"
diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss
index a8f4430f..9efcfcf8 100644
--- a/src/components/notifications/notifications.scss
+++ b/src/components/notifications/notifications.scss
@@ -79,9 +79,38 @@
}
}
+ .follow-request-accept {
+ cursor: pointer;
+
+ &:hover {
+ color: $fallback--text;
+ color: var(--text, $fallback--text);
+ }
+ }
+
+ .follow-request-reject {
+ cursor: pointer;
+
+ &:hover {
+ color: $fallback--cRed;
+ color: var(--cRed, $fallback--cRed);
+ }
+ }
+
+
.follow-text, .move-text {
padding: 0.5em 0;
overflow-wrap: break-word;
+ display: flex;
+ justify-content: space-between;
+
+ .follow-name {
+ display: block;
+ max-width: 100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
}
.status-el {
@@ -143,6 +172,11 @@
color: var(--cGreen, $fallback--cGreen);
}
+ .icon-user.lit {
+ color: $fallback--cBlue;
+ color: var(--cBlue, $fallback--cBlue);
+ }
+
.icon-user-plus.lit {
color: $fallback--cBlue;
color: var(--cBlue, $fallback--cBlue);
diff --git a/src/components/registration/registration.js b/src/components/registration/registration.js
index ace8cc7c..dab06e1e 100644
--- a/src/components/registration/registration.js
+++ b/src/components/registration/registration.js
@@ -1,5 +1,5 @@
import { validationMixin } from 'vuelidate'
-import { required, sameAs } from 'vuelidate/lib/validators'
+import { required, requiredIf, sameAs } from 'vuelidate/lib/validators'
import { mapActions, mapState } from 'vuex'
const registration = {
@@ -14,15 +14,17 @@ const registration = {
},
captcha: {}
}),
- validations: {
- user: {
- email: { required },
- username: { required },
- fullname: { required },
- password: { required },
- confirm: {
- required,
- sameAsPassword: sameAs('password')
+ validations () {
+ return {
+ user: {
+ email: { required: requiredIf(() => this.accountActivationRequired) },
+ username: { required },
+ fullname: { required },
+ password: { required },
+ confirm: {
+ required,
+ sameAsPassword: sameAs('password')
+ }
}
}
},
@@ -43,7 +45,8 @@ const registration = {
signedIn: (state) => !!state.users.currentUser,
isPending: (state) => state.users.signUpPending,
serverValidationErrors: (state) => state.users.signUpErrors,
- termsOfService: (state) => state.instance.tos
+ termsOfService: (state) => state.instance.tos,
+ accountActivationRequired: (state) => state.instance.accountActivationRequired
})
},
methods: {
diff --git a/src/components/status/status.js b/src/components/status/status.js
index fc5956ec..61d66301 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -188,23 +188,22 @@ const Status = {
}
return this.status.attentions.length > 0
},
+
+ // When a status has a subject and is also tall, we should only have one show more/less button. If the default is to collapse statuses with subjects, we just treat it like a status with a subject; otherwise, we just treat it like a tall status.
+ mightHideBecauseSubject () {
+ return this.status.summary && (!this.tallStatus || this.localCollapseSubjectDefault)
+ },
+ mightHideBecauseTall () {
+ return this.tallStatus && (!this.status.summary || !this.localCollapseSubjectDefault)
+ },
hideSubjectStatus () {
- if (this.tallStatus && !this.localCollapseSubjectDefault) {
- return false
- }
- return !this.expandingSubject && this.status.summary
+ return this.mightHideBecauseSubject && !this.expandingSubject
},
hideTallStatus () {
- if (this.status.summary && this.localCollapseSubjectDefault) {
- return false
- }
- if (this.showingTall) {
- return false
- }
- return this.tallStatus
+ return this.mightHideBecauseTall && !this.showingTall
},
showingMore () {
- return (this.tallStatus && this.showingTall) || (this.status.summary && this.expandingSubject)
+ return (this.mightHideBecauseTall && this.showingTall) || (this.mightHideBecauseSubject && this.expandingSubject)
},
nsfwClickthrough () {
if (!this.status.nsfw) {
@@ -408,14 +407,10 @@ const Status = {
this.userExpanded = !this.userExpanded
},
toggleShowMore () {
- if (this.showingTall) {
- this.showingTall = false
- } else if (this.expandingSubject && this.status.summary) {
- this.expandingSubject = false
- } else if (this.hideTallStatus) {
- this.showingTall = true
- } else if (this.hideSubjectStatus && this.status.summary) {
- this.expandingSubject = true
+ if (this.mightHideBecauseTall) {
+ this.showingTall = !this.showingTall
+ } else if (this.mightHideBecauseSubject) {
+ this.expandingSubject = !this.expandingSubject
}
},
generateUserProfileLink (id, name) {
diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue
index 8b2336b4..ad184520 100644
--- a/src/components/user_settings/user_settings.vue
+++ b/src/components/user_settings/user_settings.vue
@@ -379,6 +379,7 @@
:label="$t('settings.notifications')"
>
<div class="setting-item">
+ <h2>{{ $t('settings.notification_setting_filters') }}</h2>
<div class="select-multiple">
<span class="label">{{ $t('settings.notification_setting') }}</span>
<ul class="option-list">
@@ -404,6 +405,17 @@
</li>
</ul>
</div>
+ </div>
+
+ <div class="setting-item">
+ <h2>{{ $t('settings.notification_setting_privacy') }}</h2>
+ <p>
+ <Checkbox v-model="notificationSettings.privacy_option">
+ {{ $t('settings.notification_setting_privacy_option') }}
+ </Checkbox>
+ </p>
+ </div>
+ <div class="setting-item">
<p>{{ $t('settings.notification_mutes') }}</p>
<p>{{ $t('settings.notification_blocks') }}</p>
<button
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 3a16585d..d5748719 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -124,6 +124,7 @@
"broken_favorite": "Unknown status, searching for it...",
"favorited_you": "favorited your status",
"followed_you": "followed you",
+ "follow_request": "wants to follow you",
"load_older": "Load older notifications",
"notifications": "Notifications",
"read": "Read!",
@@ -404,11 +405,14 @@
"fun": "Fun",
"greentext": "Meme arrows",
"notifications": "Notifications",
+ "notification_setting_filters": "Filters",
"notification_setting": "Receive notifications from:",
"notification_setting_follows": "Users you follow",
"notification_setting_non_follows": "Users you do not follow",
"notification_setting_followers": "Users who follow you",
"notification_setting_non_followers": "Users who do not follow you",
+ "notification_setting_privacy": "Privacy",
+ "notification_setting_privacy_option": "Hide the sender and contents of push notifications",
"notification_mutes": "To stop receiving notifications from a specific user, use a mute.",
"notification_blocks": "Blocking a user stops all notifications as well as unsubscribes them.",
"enable_web_push_notifications": "Enable web push notifications",
@@ -698,7 +702,9 @@
"reply": "Reply",
"favorite": "Favorite",
"add_reaction": "Add Reaction",
- "user_settings": "User Settings"
+ "user_settings": "User Settings",
+ "accept_follow_request": "Accept follow request",
+ "reject_follow_request": "Reject follow request"
},
"upload":{
"error": {
diff --git a/src/i18n/pl.json b/src/i18n/pl.json
index 51cadfb6..4a4b1e31 100644
--- a/src/i18n/pl.json
+++ b/src/i18n/pl.json
@@ -1,7 +1,47 @@
{
+ "about": {
+ "mrf": {
+ "federation": "Federacja",
+ "keyword": {
+ "keyword_policies": "Zasady słów kluczowych",
+ "ftl_removal": "Usunięcie z \"Całej znanej sieci\"",
+ "reject": "Odrzucanie",
+ "replace": "Zastąpienie",
+ "is_replaced_by": "→"
+ },
+ "mrf_policies": "Włączone zasady MRF",
+ "mrf_policies_desc": "Zasady MRF zmieniają zachowanie federowania instancji. Następujące zasady są włączone:",
+ "simple": {
+ "simple_policies": "Zasady specyficzne dla instancji",
+ "accept": "Akceptowanie",
+ "accept_desc": "Ta instancja akceptuje tylko posty z wymienionych instancji:",
+ "reject": "Odrzucanie",
+ "reject_desc": "Ta instancja odrzuca posty z wymienionych instancji:",
+ "quarantine": "Kwarantanna",
+ "quarantine_desc": "Ta instancja wysyła tylko publiczne posty do wymienionych instancji:",
+ "ftl_removal": "Usunięcie z \"Całej znanej sieci\"",
+ "ftl_removal_desc": "Ta instancja usuwa te instancje z \"Całej znanej sieci\"",
+ "media_removal": "Usuwanie multimediów",
+ "media_removal_desc": "Ta instancja usuwa multimedia z postów od wymienionych instancji:",
+ "media_nsfw": "Multimedia ustawione jako wrażliwe",
+ "media_nsfw_desc": "Ta instancja wymusza, by multimedia z wymienionych instancji były ustawione jako wrażliwe:"
+ }
+ },
+ "staff": "Obsługa"
+ },
"chat": {
"title": "Czat"
},
+ "domain_mute_card": {
+ "mute": "Wycisz",
+ "mute_progress": "Wyciszam...",
+ "unmute": "Odcisz",
+ "unmute_progress": "Odciszam..."
+ },
+ "exporter": {
+ "export": "Eksportuj",
+ "processing": "Przetwarzam, za chwilę zostaniesz zapytany o ściągnięcie pliku"
+ },
"features_panel": {
"chat": "Czat",
"gopher": "Gopher",
@@ -20,7 +60,15 @@
"submit": "Wyślij",
"more": "Więcej",
"generic_error": "Wystąpił błąd",
- "optional": "nieobowiązkowe"
+ "optional": "nieobowiązkowe",
+ "show_more": "Pokaż więcej",
+ "show_less": "Pokaż mniej",
+ "dismiss": "Odrzuć",
+ "cancel": "Anuluj",
+ "disable": "Wyłącz",
+ "enable": "Włącz",
+ "confirm": "Potwierdź",
+ "verify": "Zweryfikuj"
},
"image_cropper": {
"crop_picture": "Przytnij obrazek",
@@ -28,6 +76,11 @@
"save_without_cropping": "Zapisz bez przycinania",
"cancel": "Anuluj"
},
+ "importer": {
+ "submit": "Wyślij",
+ "success": "Zaimportowano pomyślnie",
+ "error": "Wystąpił błąd podczas importowania pliku."
+ },
"login": {
"login": "Zaloguj",
"description": "Zaloguj używając OAuth",
@@ -36,7 +89,15 @@
"placeholder": "n.p. lain",
"register": "Zarejestruj",
"username": "Użytkownik",
- "hint": "Zaloguj się, aby dołączyć do dyskusji"
+ "hint": "Zaloguj się, aby dołączyć do dyskusji",
+ "authentication_code": "Kod weryfikacyjny",
+ "enter_recovery_code": "Wprowadź kod zapasowy",
+ "enter_two_factor_code": "Wprowadź kod weryfikacyjny",
+ "recovery_code": "Kod zapasowy",
+ "heading" : {
+ "totp" : "Weryfikacja dwuetapowa",
+ "recovery" : "Zapasowa weryfikacja dwuetapowa"
+ }
},
"media_modal": {
"previous": "Poprzednie",
@@ -44,15 +105,18 @@
},
"nav": {
"about": "O nas",
+ "administration": "Administracja",
"back": "Wróć",
"chat": "Lokalny czat",
"friend_requests": "Prośby o możliwość obserwacji",
"mentions": "Wzmianki",
+ "interactions": "Interakcje",
"dms": "Wiadomości prywatne",
"public_tl": "Publiczna oś czasu",
"timeline": "Oś czasu",
"twkn": "Cała znana sieć",
"user_search": "Wyszukiwanie użytkowników",
+ "search": "Wyszukiwanie",
"who_to_follow": "Sugestie obserwacji",
"preferences": "Preferencje"
},
@@ -64,7 +128,40 @@
"notifications": "Powiadomienia",
"read": "Przeczytane!",
"repeated_you": "powtórzył(-a) twój status",
- "no_more_notifications": "Nie masz więcej powiadomień"
+ "no_more_notifications": "Nie masz więcej powiadomień",
+ "migrated_to": "wyemigrował do",
+ "reacted_with": "zareagował z {0}"
+ },
+ "polls": {
+ "add_poll": "Dodaj ankietę",
+ "add_option": "Dodaj opcję",
+ "option": "Opcja",
+ "votes": "głosów",
+ "vote": "Głosuj",
+ "type": "Typ ankiety",
+ "single_choice": "jednokrotnego wyboru",
+ "multiple_choices": "wielokrotnego wyboru",
+ "expiry": "Czas trwania ankiety",
+ "expires_in": "Ankieta kończy się za{0}",
+ "expired": "Ankieta skończyła się {0} temu",
+ "not_enough_options": "Zbyt mało unikalnych opcji w ankiecie"
+ },
+ "emoji": {
+ "stickers": "Naklejki",
+ "emoji": "Emoji",
+ "keep_open": "Zostaw selektor otwarty",
+ "search_emoji": "Wyszukaj emoji",
+ "add_emoji": "Wstaw emoji",
+ "custom": "Niestandardowe emoji",
+ "unicode": "Emoji unicode",
+ "load_all_hint": "Załadowano pierwsze {saneAmount} emoji, Załadowanie wszystkich emoji może spowodować problemy z wydajnością.",
+ "load_all": "Ładuję wszystkie {emojiAmount} emoji"
+ },
+ "interactions": {
+ "favs_repeats": "Powtórzenia i ulubione",
+ "follows": "Nowi obserwujący",
+ "moves": "Użytkownik migruje",
+ "load_older": "Załaduj starsze interakcje"
},
"post_status": {
"new_status": "Dodaj nowy status",
@@ -79,8 +176,14 @@
},
"content_warning": "Temat (nieobowiązkowy)",
"default": "Właśnie wróciłem z kościoła",
- "direct_warning": "Ten wpis zobaczą tylko osoby, o których wspomniałeś(-aś).",
+ "direct_warning_to_all": "Ten wpis zobaczą wszystkie osoby, o których wspomniałeś(-aś).",
+ "direct_warning_to_first_only": "Ten wpis zobaczą tylko te osoby, o których wspomniałeś(-aś) na początku wiadomości.",
"posting": "Wysyłanie",
+ "scope_notice": {
+ "public": "Ten post będzie widoczny dla każdego",
+ "private": "Ten post będzie widoczny tylko dla twoich obserwujących",
+ "unlisted": "Ten post nie będzie widoczny na publicznej osi czasu i całej znanej sieci"
+ },
"scope": {
"direct": "Bezpośredni – Tylko dla wspomnianych użytkowników",
"private": "Tylko dla obserwujących – Umieść dla osób, które cię obserwują",
@@ -109,8 +212,40 @@
"password_confirmation_match": "musi być takie jak hasło"
}
},
+ "remote_user_resolver": {
+ "remote_user_resolver": "Wyszukiwarka użytkowników nietutejszych",
+ "searching_for": "Szukam",
+ "error": "Nie znaleziono."
+ },
+ "selectable_list": {
+ "select_all": "Zaznacz wszystko"
+ },
"settings": {
"app_name": "Nazwa aplikacji",
+ "security": "Bezpieczeństwo",
+ "enter_current_password_to_confirm": "Wprowadź obecne hasło, by potwierdzić twoją tożsamość",
+ "mfa": {
+ "otp" : "OTP",
+ "setup_otp" : "Ustaw OTP",
+ "wait_pre_setup_otp" : "początkowe ustawianie OTP",
+ "confirm_and_enable" : "Potwierdź i włącz OTP",
+ "title": "Weryfikacja dwuetapowa",
+ "generate_new_recovery_codes" : "Wygeneruj nowe kody zapasowe",
+ "warning_of_generate_new_codes" : "Po tym gdy generujesz nowe kody zapasowe, stare przestaną działać.",
+ "recovery_codes" : "Kody zapasowe.",
+ "waiting_a_recovery_codes": "Otrzymuję kody zapasowe...",
+ "recovery_codes_warning" : "Spisz kody na kartce papieru, albo zapisz je w bezpiecznym miejscu - inaczej nie zobaczysz ich już nigdy. Jeśli stracisz dostęp do twojej aplikacji 2FA i kodów zapasowych, nie będziesz miał dostępu do swojego konta.",
+ "authentication_methods" : "Metody weryfikacji",
+ "scan": {
+ "title": "Skanuj",
+ "desc": "Zeskanuj ten kod QR używając twojej aplikacji 2FA albo wpisz ten klucz:",
+ "secret_code": "Klucz"
+ },
+ "verify": {
+ "desc": "By włączyć weryfikację dwuetapową, wpisz kod z twojej aplikacji 2FA:"
+ }
+ },
+ "allow_following_move": "Zezwalaj na automatyczną obserwację gdy obserwowane konto migruje",
"attachmentRadius": "Załączniki",
"attachments": "Załączniki",
"autoload": "Włącz automatyczne ładowanie po przewinięciu do końca strony",
@@ -119,12 +254,20 @@
"avatarRadius": "Awatary",
"background": "Tło",
"bio": "Bio",
+ "block_export": "Eksport blokad",
+ "block_export_button": "Eksportuj twoje blokady do pliku .csv",
+ "block_import": "Import blokad",
+ "block_import_error": "Wystąpił błąd podczas importowania blokad",
+ "blocks_imported": "Zaimportowano blokady, przetwarzanie może zająć trochę czasu.",
"blocks_tab": "Bloki",
"btnRadius": "Przyciski",
"cBlue": "Niebieski (odpowiedz, obserwuj)",
"cGreen": "Zielony (powtórzenia)",
"cOrange": "Pomarańczowy (ulubione)",
"cRed": "Czerwony (anuluj)",
+ "change_email": "Zmień email",
+ "change_email_error": "Wystąpił problem podczas zmiany emaila.",
+ "changed_email": "Pomyślnie zmieniono email!",
"change_password": "Zmień hasło",
"change_password_error": "Podczas zmiany hasła wystąpił problem.",
"changed_password": "Pomyślnie zmieniono hasło!",
@@ -140,16 +283,20 @@
"delete_account_description": "Trwale usuń konto i wszystkie posty.",
"delete_account_error": "Wystąpił problem z usuwaniem twojego konta. Jeżeli problem powtarza się, poinformuj administratora swojej instancji.",
"delete_account_instructions": "Wprowadź swoje hasło w poniższe pole aby potwierdzić usunięcie konta.",
+ "discoverable": "Zezwól na odkrywanie tego konta w wynikach wyszukiwania i innych usługa.",
+ "domain_mutes": "Domeny",
"avatar_size_instruction": "Zalecany minimalny rozmiar awatarów to 150x150 pikseli.",
+ "pad_emoji": "Dodaj odstęp z obu stron emoji podczas dodawania selektorem",
+ "emoji_reactions_on_timeline": "Pokaż reakcje emoji na osi czasu",
"export_theme": "Zapisz motyw",
"filtering": "Filtrowanie",
"filtering_explanation": "Wszystkie statusy zawierające te słowa będą wyciszone. Jedno słowo na linijkę.",
"follow_export": "Eksport obserwowanych",
"follow_export_button": "Eksportuj swoją listę obserwowanych do pliku CSV",
- "follow_export_processing": "Przetwarzanie, wkrótce twój plik zacznie się ściągać.",
"follow_import": "Import obserwowanych",
"follow_import_error": "Błąd przy importowaniu obserwowanych",
"follows_imported": "Obserwowani zaimportowani! Przetwarzanie może trochę potrwać.",
+ "accent": "Akcent",
"foreground": "Pierwszy plan",
"general": "Ogólne",
"hide_attachments_in_convo": "Ukrywaj załączniki w rozmowach",
@@ -162,6 +309,7 @@
"hide_post_stats": "Ukrywaj statysyki postów (np. liczbę polubień)",
"hide_user_stats": "Ukrywaj statysyki użytkowników (np. liczbę obserwujących)",
"hide_filtered_statuses": "Ukrywaj filtrowane statusy",
+ "import_blocks_from_a_csv_file": "Importuj blokady z pliku CSV",
"import_followers_from_a_csv_file": "Importuj obserwowanych z pliku CSV",
"import_theme": "Załaduj motyw",
"inputRadius": "Pola tekstowe",
@@ -181,17 +329,22 @@
"use_contain_fit": "Nie przycinaj załączników na miniaturach",
"name": "Imię",
"name_bio": "Imię i bio",
+ "new_email": "Nowy email",
"new_password": "Nowe hasło",
"notification_visibility": "Rodzaje powiadomień do wyświetlania",
"notification_visibility_follows": "Obserwacje",
"notification_visibility_likes": "Ulubione",
"notification_visibility_mentions": "Wzmianki",
"notification_visibility_repeats": "Powtórzenia",
+ "notification_visibility_moves": "Użytkownik migruje",
+ "notification_visibility_emoji_reactions": "Reakcje",
"no_rich_text_description": "Usuwaj formatowanie ze wszystkich postów",
"no_blocks": "Bez blokad",
"no_mutes": "Bez wyciszeń",
"hide_follows_description": "Nie pokazuj kogo obserwuję",
"hide_followers_description": "Nie pokazuj kto mnie obserwuje",
+ "hide_follows_count_description": "Nie pokazuj licznika obserwowanych",
+ "hide_followers_count_description": "Nie pokazuj licznika obserwujących",
"show_admin_badge": "Pokazuj odznakę Administrator na moim profilu",
"show_moderator_badge": "Pokazuj odznakę Moderator na moim profilu",
"nsfw_clickthrough": "Włącz domyślne ukrywanie załączników o treści nieprzyzwoitej (NSFW)",
@@ -212,10 +365,14 @@
"reply_visibility_all": "Pokazuj wszystkie odpowiedzi",
"reply_visibility_following": "Pokazuj tylko odpowiedzi skierowane do mnie i osób które obserwuję",
"reply_visibility_self": "Pokazuj tylko odpowiedzi skierowane do mnie",
+ "autohide_floating_post_button": "Ukryj automatycznie przycisk \"Nowy post\" (mobile)",
"saving_err": "Nie udało się zapisać ustawień",
"saving_ok": "Zapisano ustawienia",
+ "search_user_to_block": "Wyszukaj kogo chcesz zablokować",
+ "search_user_to_mute": "Wyszukaj kogo chcesz wyciszyć",
"security_tab": "Bezpieczeństwo",
"scope_copy": "Kopiuj zakres podczas odpowiadania (DM-y zawsze są kopiowane)",
+ "minimal_scopes_mode": "Zminimalizuj opcje wyboru zakresu postów",
"set_new_avatar": "Ustaw nowy awatar",
"set_new_profile_background": "Ustaw nowe tło profilu",
"set_new_profile_banner": "Ustaw nowy banner profilu",
@@ -228,19 +385,32 @@
"post_status_content_type": "Post status content type",
"stop_gifs": "Odtwarzaj GIFy po najechaniu kursorem",
"streaming": "Włącz automatycznie strumieniowanie nowych postów gdy jesteś na początku strony",
+ "user_mutes": "Users",
+ "useStreamingApi": "Otrzymuj posty i powiadomienia w czasie rzeczywistym",
+ "useStreamingApiWarning": "(Niezalecane, eksperymentalne, pomija posty)",
"text": "Tekst",
"theme": "Motyw",
"theme_help": "Użyj kolorów w notacji szesnastkowej (#rrggbb), by stworzyć swój motyw.",
"theme_help_v2_1": "Możesz też zastąpić kolory i widoczność poszczególnych komponentów przełączając pola wyboru, użyj „Wyczyść wszystko” aby usunąć wszystkie zastąpienia.",
"theme_help_v2_2": "Ikony pod niektórych wpisami są wskaźnikami kontrastu pomiędzy tłem a tekstem, po najechaniu na nie otrzymasz szczegółowe informacje. Zapamiętaj, że jeżeli używasz przezroczystości, wskaźniki pokazują najgorszy możliwy przypadek.",
"tooltipRadius": "Etykiety/alerty",
+ "type_domains_to_mute": "Wpisz domeny, które chcesz wyciszyć",
"upload_a_photo": "Wyślij zdjęcie",
"user_settings": "Ustawienia użytkownika",
"values": {
"false": "nie",
"true": "tak"
},
+ "fun": "Zabawa",
+ "greentext": "Memiczne strzałki",
"notifications": "Powiadomienia",
+ "notification_setting": "Otrzymuj powiadomienia od:",
+ "notification_setting_follows": "Ludzi których obserwujesz",
+ "notification_setting_non_follows": "Ludzi których nie obserwujesz",
+ "notification_setting_followers": "Ludzi którzy obserwują ciebie",
+ "notification_setting_non_followers": "Ludzi którzy nie obserwują ciebie",
+ "notification_mutes": "By przestać otrzymywać powiadomienia od jednego użytkownika, wycisz go",
+ "notification_blocks": "Blokowanie uzytkownika zatrzymuje wszystkie powiadomienia i odsubskrybowuje go.",
"enable_web_push_notifications": "Włącz powiadomienia push",
"style": {
"switcher": {
@@ -252,7 +422,24 @@
"save_load_hint": "Opcje „zachowaj” pozwalają na pozostanie przy obecnych opcjach po wybraniu lub załadowaniu motywu, jak i przechowywanie ich podczas eksportowania motywu. Jeżeli wszystkie są odznaczone, eksportowanie motywu spowoduje zapisanie wszystkiego.",
"reset": "Wyzeruj",
"clear_all": "Wyczyść wszystko",
- "clear_opacity": "Wyczyść widoczność"
+ "clear_opacity": "Wyczyść widoczność",
+ "load_theme": "Załaduj motyw",
+ "keep_as_is": "Zostaw po staremu",
+ "use_snapshot": "Stara wersja",
+ "use_source": "Nowa wersja",
+ "help": {
+ "upgraded_from_v2": "PleromaFE zostało zaaktualizowane, motyw może wyglądać nieco inaczej niż sobie zapamiętałeś.",
+ "v2_imported": "Plik który zaimportowałeś został stworzony dla starszego FE. Próbujemy zwiększyć kompatybiliność, lecz wciąż mogą występować rozbieżności.",
+ "future_version_imported": "Plik który zaimportowałeś został stworzony w nowszej wersji FE.",
+ "older_version_imported": "Plik który zaimportowałeś został stworzony w starszej wersji FE.",
+ "snapshot_present": "Migawka motywu jest załadowana, więc wszystkie wartości zostały nadpisane. Zamiast tego, możesz załadować właściwe dane motywu",
+ "snapshot_missing": "Nie znaleziono migawki motywu w pliku, więc motyw może wyglądać inaczej niż pierwotnie zaplanowano.",
+ "fe_upgraded": "Silnik motywów PleromaFE został zaaktualizowany.",
+ "fe_downgraded": "Wersja PleromaFE została cofnięta.",
+ "migration_snapshot_ok": "Żeby być bezpiecznym, migawka motywu została załadowana. Możesz spróbować załadować dane motywu.",
+ "migration_napshot_gone": "Z jakiegoś powodu migawka zniknęła, niektóre rzeczy mogą wyglądać inaczej niż sobie zapamiętałeś.",
+ "snapshot_source_mismatch": "Konflikt wersji: najprawdopodobniej FE zostało cofnięte do poprzedniej wersji i zaaktualizowane ponownie, jeśli zmieniłeś motyw używając starszej wersji FE, najprawdopodobniej chcesz używać starszej wersji, w przeciwnym razie użyj nowej wersji."
+ }
},
"common": {
"color": "Kolor",
@@ -280,14 +467,28 @@
"_tab_label": "Zaawansowane",
"alert": "Tło alertu",
"alert_error": "Błąd",
+ "alert_warning": "Ostrzeżenie",
+ "alert_neutral": "Neutralne",
+ "post": "Posty/Bio użytkowników",
"badge": "Tło odznaki",
+ "popover": "Etykiety, menu, popovery",
"badge_notification": "Powiadomienie",
"panel_header": "Nagłówek panelu",
"top_bar": "Górny pasek",
"borders": "Granice",
"buttons": "Przyciski",
"inputs": "Pola wejścia",
- "faint_text": "Zanikający tekst"
+ "faint_text": "Zanikający tekst",
+ "underlay": "Podkład",
+ "poll": "Wykres ankiety",
+ "icons": "Ikony",
+ "highlight": "Podświetlone elementy",
+ "pressed": "Naciśnięte",
+ "selectedPost": "Wybrany post",
+ "selectedMenu": "Wybrany element menu",
+ "disabled": "Wyłączone",
+ "toggled": "Przełączone",
+ "tabs": "Karty"
},
"radii": {
"_tab_label": "Zaokrąglenie"
@@ -300,7 +501,7 @@
"blur": "Rozmycie",
"spread": "Szerokość",
"inset": "Inset",
- "hint": "Możesz też używać --zmiennych jako kolorów, aby wykorzystać zmienne CSS3. Pamiętaj, że ustawienie widoczności nie będzie wtedy działać.",
+ "hintV3": "Dla cieni możesz również użyć notacji {0} by użyć inny slot koloru.",
"filter_hint": {
"always_drop_shadow": "Ostrzeżenie, ten cień zawsze używa {0} jeżeli to obsługiwane przez przeglądarkę.",
"drop_shadow_syntax": "{0} nie obsługuje parametru {1} i słowa kluczowego {2}.",
@@ -357,6 +558,40 @@
"frontend_version": "Wersja front-endu"
}
},
+ "time": {
+ "day": "{0} dzień",
+ "days": "{0} dni",
+ "day_short": "{0}d",
+ "days_short": "{0}d",
+ "hour": "{0} godzina",
+ "hours": "{0} godzin",
+ "hour_short": "{0} godz.",
+ "hours_short": "{0} godz.",
+ "in_future": "za {0}",
+ "in_past": "{0} temu",
+ "minute": "{0} minuta",
+ "minutes": "{0} minut",
+ "minute_short": "{0}min",
+ "minutes_short": "{0}min",
+ "month": "{0} miesiąc",
+ "months": "{0} miesięcy",
+ "month_short": "{0} mies.",
+ "months_short": "{0} mies.",
+ "now": "teraz",
+ "now_short": "teraz",
+ "second": "{0} sekunda",
+ "seconds": "{0} sekund",
+ "second_short": "{0}s",
+ "seconds_short": "{0}s",
+ "week": "{0} tydzień",
+ "weeks": "{0} tygodni",
+ "week_short": "{0} tydz.",
+ "weeks_short": "{0} tyg.",
+ "year": "{0} rok",
+ "years": "{0} lata",
+ "year_short": "{0} r.",
+ "years_short": "{0} lata"
+ },
"timeline": {
"collapse": "Zwiń",
"conversation": "Rozmowa",
@@ -370,8 +605,17 @@
"no_statuses": "Brak statusów"
},
"status": {
+ "favorites": "Ulubione",
+ "repeats": "Powtórzenia",
+ "delete": "Usuń status",
+ "pin": "Przypnij na profilu",
+ "unpin": "Odepnij z profilu",
+ "pinned": "Przypnięte",
+ "delete_confirm": "Czy naprawdę chcesz usunąć ten status?",
"reply_to": "Odpowiedź dla",
- "replies_list": "Odpowiedzi:"
+ "replies_list": "Odpowiedzi:",
+ "mute_conversation": "Wycisz konwersację",
+ "unmute_conversation": "Odcisz konwersację"
},
"user_card": {
"approve": "Przyjmij",
@@ -388,25 +632,60 @@
"followers": "Obserwujący",
"following": "Obserwowany!",
"follows_you": "Obserwuje cię!",
+ "hidden": "Ukryte",
"its_you": "To ty!",
"media": "Media",
+ "mention": "Wspomnienie",
"mute": "Wycisz",
"muted": "Wyciszony(-a)",
"per_day": "dziennie",
"remote_follow": "Zdalna obserwacja",
+ "report": "Raportuj",
"statuses": "Statusy",
+ "subscribe": "Subskrybuj",
+ "unsubscribe": "Odsubskrybuj",
"unblock": "Odblokuj",
"unblock_progress": "Odblokowuję…",
"block_progress": "Blokuję…",
"unmute": "Cofnij wyciszenie",
"unmute_progress": "Cofam wyciszenie…",
- "mute_progress": "Wyciszam…"
+ "mute_progress": "Wyciszam…",
+ "hide_repeats": "Ukryj powtórzenia",
+ "show_repeats": "Pokaż powtórzenia",
+ "admin_menu": {
+ "moderation": "Moderacja",
+ "grant_admin": "Przyznaj admina",
+ "revoke_admin": "Odwołaj admina",
+ "grant_moderator": "Przyznaj moderatora",
+ "revoke_moderator": "Odwołaj moderatora",
+ "activate_account": "Aktywuj konto",
+ "deactivate_account": "Dezaktywuj konto",
+ "delete_account": "Usuń konto",
+ "force_nsfw": "Oznacz wszystkie posty jako NSFW",
+ "strip_media": "Usuń multimedia z postów",
+ "force_unlisted": "Wymuś posty na niepubliczne",
+ "sandbox": "Wymuś by posty były tylko dla obserwujących",
+ "disable_remote_subscription": "Zakaż obserwowania użytkownika ze zdalnych instancji",
+ "disable_any_subscription": "Zakaż całkowicie obserwowania użytkownika",
+ "quarantine": "Zakaż federowania postów od tego użytkownika",
+ "delete_user": "Usuń użytkownika",
+ "delete_user_confirmation": "Czy jesteś absolutnie pewny? Ta operacja nie może być cofnięta."
+ }
},
"user_profile": {
"timeline_title": "Oś czasu użytkownika",
"profile_does_not_exist": "Przepraszamy, ten profil nie istnieje.",
"profile_loading_error": "Przepraszamy, wystąpił błąd podczas ładowania tego profilu."
},
+ "user_reporting": {
+ "title": "Raportowanie {0}",
+ "add_comment_description": "Raport zostanie wysłany do moderatorów instancji. Możesz dodać powód dlaczego raportujesz to konto poniżej:",
+ "additional_comments": "Dodatkowe komentarze",
+ "forward_description": "To konto jest z innego serwera. Wysłać również tam kopię raportu?",
+ "forward_to": "Przekaż do{0}",
+ "submit": "Wyślij",
+ "generic_error": "Wystąpił błąd podczas przetwarzania twojej prośby."
+ },
"who_to_follow": {
"more": "Więcej",
"who_to_follow": "Propozycje obserwacji"
@@ -416,6 +695,7 @@
"repeat": "Powtórz",
"reply": "Odpowiedz",
"favorite": "Dodaj do ulubionych",
+ "add_reaction": "Dodaj reakcję",
"user_settings": "Ustawienia użytkownika"
},
"upload":{
@@ -431,5 +711,25 @@
"GiB": "GiB",
"TiB": "TiB"
}
+ },
+ "search": {
+ "people": "Ludzie",
+ "hashtags": "Hasztagi",
+ "person_talking": "{count} osoba rozmawia o tym",
+ "people_talking": "{count} osób rozmawia o tym",
+ "no_results": "Brak wyników"
+ },
+ "password_reset": {
+ "forgot_password": "Zapomniałeś hasła?",
+ "password_reset": "Reset hasła",
+ "instruction": "Wprowadź swój adres email lub nazwę użytkownika. Wyślemy ci link z którym możesz zresetować hasło.",
+ "placeholder": "Twój email lub nazwa użytkownika",
+ "check_email": "Sprawdź pocztę, aby uzyskać link do zresetowania hasła.",
+ "return_home": "Wróć do strony głównej",
+ "not_found": "Nie mogliśmy znaleźć tego emaila lub nazwy użytkownika.",
+ "too_many_requests": "Przekroczyłeś limit prób, spróbuj ponownie później.",
+ "password_reset_disabled": "Resetowanie hasła jest wyłączone. Proszę skontaktuj się z administratorem tej instancji.",
+ "password_reset_required": "Musisz zresetować hasło, by się zalogować.",
+ "password_reset_required_but_mailer_is_disabled": "Musisz zresetować hasło, ale resetowanie hasła jest wyłączone. Proszę skontaktuj się z administratorem tej instancji."
}
}
diff --git a/src/modules/config.js b/src/modules/config.js
index 7997521d..8f4638f5 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -34,7 +34,8 @@ export const defaultState = {
likes: true,
repeats: true,
moves: true,
- emojiReactions: false
+ emojiReactions: false,
+ followRequest: true
},
webPushNotifications: false,
muteWords: [],
diff --git a/src/modules/statuses.js b/src/modules/statuses.js
index f1b7dcbd..cd8c1dba 100644
--- a/src/modules/statuses.js
+++ b/src/modules/statuses.js
@@ -13,6 +13,7 @@ import {
omitBy
} from 'lodash'
import { set } from 'vue'
+import { isStatusNotification } from '../services/notification_utils/notification_utils.js'
import apiService from '../services/api/api.service.js'
// import parse from '../services/status_parser/status_parser.js'
@@ -321,7 +322,7 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters }) => {
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,17 @@ export const mutations = {
notification.seen = true
})
},
+ markSingleNotificationAsSeen (state, { id }) {
+ const notification = find(state.notifications.data, n => n.id === id)
+ if (notification) 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 +695,24 @@ const statuses = {
credentials: rootState.users.currentUser.credentials
})
},
+ markSingleNotificationAsSeen ({ rootState, commit }, { id }) {
+ commit('markSingleNotificationAsSeen', { id })
+ apiService.markNotificationsAsSeen({
+ single: true,
+ id,
+ credentials: rootState.users.currentUser.credentials
+ })
+ },
+ dismissNotificationLocal ({ rootState, commit }, { id }) {
+ commit('dismissNotification', { id })
+ },
+ dismissNotification ({ rootState, commit }, { id }) {
+ commit('dismissNotification', { id })
+ rootState.api.backendInteractor.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 03e88ae2..72c8874f 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -4,7 +4,6 @@ import 'whatwg-fetch'
import { RegistrationError, StatusCodeError } from '../errors/errors'
/* eslint-env browser */
-const QVITTER_USER_NOTIFICATIONS_READ_URL = '/api/qvitter/statuses/notifications/read.json'
const BLOCKS_IMPORT_URL = '/api/pleroma/blocks_import'
const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import'
const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account'
@@ -17,6 +16,7 @@ const DEACTIVATE_USER_URL = '/api/pleroma/admin/users/deactivate'
const ADMIN_USERS_URL = '/api/pleroma/admin/users'
const SUGGESTIONS_URL = '/api/v1/suggestions'
const NOTIFICATION_SETTINGS_URL = '/api/pleroma/notification_settings'
+const NOTIFICATION_READ_URL = '/api/v1/pleroma/notifications/read'
const MFA_SETTINGS_URL = '/api/pleroma/accounts/mfa'
const MFA_BACKUP_CODES_URL = '/api/pleroma/accounts/mfa/backup_codes'
@@ -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`
@@ -495,8 +496,7 @@ const fetchTimeline = ({
until = false,
userId = false,
tag = false,
- withMuted = false,
- withMove = false
+ withMuted = false
}) => {
const timelineUrls = {
public: MASTODON_PUBLIC_TIMELINE,
@@ -536,11 +536,8 @@ const fetchTimeline = ({
if (timeline === 'public' || timeline === 'publicAndExternal') {
params.push(['only_media', false])
}
- if (timeline === 'notifications') {
- params.push(['with_move', withMove])
- }
- params.push(['count', 20])
+ params.push(['limit', 20])
params.push(['with_muted', withMuted])
const queryString = map(params, (param) => `${param[0]}=${param[1]}`).join('&')
@@ -844,12 +841,16 @@ const suggestions = ({ credentials }) => {
}).then((data) => data.json())
}
-const markNotificationsAsSeen = ({ id, credentials }) => {
+const markNotificationsAsSeen = ({ id, credentials, single = false }) => {
const body = new FormData()
- body.append('latest_id', id)
+ if (single) {
+ body.append('id', id)
+ } else {
+ body.append('max_id', id)
+ }
- return fetch(QVITTER_USER_NOTIFICATIONS_READ_URL, {
+ return fetch(NOTIFICATION_READ_URL, {
body,
headers: authHeaders(credentials),
method: 'POST'
@@ -880,12 +881,20 @@ const fetchPoll = ({ pollId, credentials }) => {
)
}
-const fetchFavoritedByUsers = ({ id }) => {
- return promisedRequest({ url: MASTODON_STATUS_FAVORITEDBY_URL(id) }).then((users) => users.map(parseUser))
+const fetchFavoritedByUsers = ({ id, credentials }) => {
+ return promisedRequest({
+ url: MASTODON_STATUS_FAVORITEDBY_URL(id),
+ method: 'GET',
+ credentials
+ }).then((users) => users.map(parseUser))
}
-const fetchRebloggedByUsers = ({ id }) => {
- return promisedRequest({ url: MASTODON_STATUS_REBLOGGEDBY_URL(id) }).then((users) => users.map(parseUser))
+const fetchRebloggedByUsers = ({ id, credentials }) => {
+ return promisedRequest({
+ url: MASTODON_STATUS_REBLOGGEDBY_URL(id),
+ method: 'GET',
+ credentials
+ }).then((users) => users.map(parseUser))
}
const fetchEmojiReactions = ({ id, credentials }) => {
@@ -1002,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
@@ -1157,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/src/services/notifications_fetcher/notifications_fetcher.service.js b/src/services/notifications_fetcher/notifications_fetcher.service.js
index 864e32f8..64499a1b 100644
--- a/src/services/notifications_fetcher/notifications_fetcher.service.js
+++ b/src/services/notifications_fetcher/notifications_fetcher.service.js
@@ -11,12 +11,9 @@ const fetchAndUpdate = ({ store, credentials, older = false }) => {
const rootState = store.rootState || store.state
const timelineData = rootState.statuses.notifications
const hideMutedPosts = getters.mergedConfig.hideMutedPosts
- const allowFollowingMove = rootState.users.currentUser.allow_following_move
args['withMuted'] = !hideMutedPosts
- args['withMove'] = !allowFollowingMove
-
args['timeline'] = 'notifications'
if (older) {
if (timelineData.minId !== Number.POSITIVE_INFINITY) {