diff options
| -rw-r--r-- | CHANGELOG.md | 5 | ||||
| -rw-r--r-- | src/components/chat/chat.js | 15 | ||||
| -rw-r--r-- | src/components/chat/chat.scss | 10 | ||||
| -rw-r--r-- | src/components/chat_new/chat_new.scss | 6 | ||||
| -rw-r--r-- | src/components/timeline/timeline.js | 19 | ||||
| -rw-r--r-- | src/components/timeline/timeline.vue | 8 | ||||
| -rw-r--r-- | src/i18n/eo.json | 79 | ||||
| -rw-r--r-- | src/i18n/zh.json | 6 | ||||
| -rw-r--r-- | src/i18n/zh_Hant.json | 2 | ||||
| -rw-r--r-- | src/services/chat_utils/chat_utils.js | 2 | ||||
| -rw-r--r-- | src/services/promise_interval/promise_interval.js | 9 |
11 files changed, 113 insertions, 48 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 99f601a5..1257cd75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fixed chats list not updating its order when new messages come in - Fixed chat messages sometimes getting lost when you receive a message at the same time - Fixed clicking NSFW hider through status popover +- Fixed chat-view back button being hard to click +- Fixed fresh chat notifications being cleared immediately while leaving the chat view and not having time to actually see the messages + +### Changed +- Clicking immediately when timeline shifts is now blocked to prevent misclicks ### Added - Import/export a muted users diff --git a/src/components/chat/chat.js b/src/components/chat/chat.js index 083f850f..c0c9ad6c 100644 --- a/src/components/chat/chat.js +++ b/src/components/chat/chat.js @@ -21,6 +21,7 @@ library.add( const BOTTOMED_OUT_OFFSET = 10 const JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET = 150 const SAFE_RESIZE_TIME_OFFSET = 100 +const MARK_AS_READ_DELAY = 1500 const Chat = { components: { @@ -104,7 +105,7 @@ const Chat = { const bottomedOutBeforeUpdate = this.bottomedOut(BOTTOMED_OUT_OFFSET) this.$nextTick(() => { if (bottomedOutBeforeUpdate) { - this.scrollDown({ forceRead: !document.hidden }) + this.scrollDown() } }) }, @@ -210,7 +211,7 @@ const Chat = { this.$nextTick(() => { scrollable.scrollTo({ top: scrollable.scrollHeight, left: 0, behavior }) }) - if (forceRead || this.newMessageCount > 0) { + if (forceRead) { this.readChat() } }, @@ -235,12 +236,18 @@ const Chat = { } else if (this.bottomedOut(JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET)) { this.jumpToBottomButtonVisible = false if (this.newMessageCount > 0) { - this.readChat() + // Use a delay before marking as read to prevent situation where new messages + // arrive just as you're leaving the view and messages that you didn't actually + // get to see get marked as read. + window.setTimeout(() => { + // Don't mark as read if the element doesn't exist, user has left chat view + if (this.$el) this.readChat() + }, MARK_AS_READ_DELAY) } } else { this.jumpToBottomButtonVisible = true } - }, 100), + }, 200), handleScrollUp (positionBeforeLoading) { const positionAfterLoading = getScrollPosition(this.$refs.scrollable) this.$refs.scrollable.scrollTo({ diff --git a/src/components/chat/chat.scss b/src/components/chat/chat.scss index b7b0d377..787514c8 100644 --- a/src/components/chat/chat.scss +++ b/src/components/chat/chat.scss @@ -25,7 +25,7 @@ min-height: 100%; margin: 0 0 0 0; border-radius: 10px 10px 0 0; - border-radius: var(--panelRadius, 10px) var(--panelRadius, 10px) 0 0 ; + border-radius: var(--panelRadius, 10px) var(--panelRadius, 10px) 0 0; &::after { border-radius: 0; @@ -58,8 +58,10 @@ .go-back-button { cursor: pointer; - margin-right: 1.7em; - margin-left: 0.3em; + width: 28px; + text-align: center; + padding: 0.6em; + margin: -0.6em 0.6em -0.6em -0.6em; } .jump-to-bottom-button { @@ -74,7 +76,7 @@ display: flex; justify-content: center; align-items: center; - box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.3), 0px 2px 4px rgba(0, 0, 0, 0.3); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3), 0 2px 4px rgba(0, 0, 0, 0.3); z-index: 10; transition: 0.35s all; transition-timing-function: cubic-bezier(0, 1, 0.5, 1); diff --git a/src/components/chat_new/chat_new.scss b/src/components/chat_new/chat_new.scss index 716172b0..5506143d 100644 --- a/src/components/chat_new/chat_new.scss +++ b/src/components/chat_new/chat_new.scss @@ -23,7 +23,9 @@ .go-back-button { cursor: pointer; - margin-right: 1.7em; - margin-left: 0.3em; + width: 28px; + text-align: center; + padding: 0.6em; + margin: -0.6em 0.6em -0.6em -0.6em; } } diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js index a443340f..368ee81b 100644 --- a/src/components/timeline/timeline.js +++ b/src/components/timeline/timeline.js @@ -2,7 +2,7 @@ import Status from '../status/status.vue' import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js' import Conversation from '../conversation/conversation.vue' import TimelineMenu from '../timeline_menu/timeline_menu.vue' -import { throttle, keyBy } from 'lodash' +import { debounce, throttle, keyBy } from 'lodash' import { library } from '@fortawesome/fontawesome-svg-core' import { faCircleNotch } from '@fortawesome/free-solid-svg-icons' @@ -40,7 +40,8 @@ const Timeline = { paused: false, unfocused: false, bottomedOut: false, - virtualScrollIndex: 0 + virtualScrollIndex: 0, + blockingClicks: false } }, components: { @@ -70,8 +71,10 @@ const Timeline = { } }, classes () { + let rootClasses = !this.embedded ? ['panel', 'panel-default'] : [] + if (this.blockingClicks) rootClasses = rootClasses.concat(['-blocked']) return { - root: ['timeline'].concat(!this.embedded ? ['panel', 'panel-default'] : []), + root: rootClasses, header: ['timeline-heading'].concat(!this.embedded ? ['panel-heading'] : []), body: ['timeline-body'].concat(!this.embedded ? ['panel-body'] : []), footer: ['timeline-footer'].concat(!this.embedded ? ['panel-footer'] : []) @@ -130,6 +133,15 @@ const Timeline = { this.$store.commit('setLoading', { timeline: this.timelineName, value: false }) }, methods: { + stopBlockingClicks: debounce(function () { + this.blockingClicks = false + }, 1000), + blockClicksTemporarily () { + if (!this.blockingClicks) { + this.blockingClicks = true + } + this.stopBlockingClicks() + }, handleShortKey (e) { // Ignore when input fields are focused if (['textarea', 'input'].includes(e.target.tagName.toLowerCase())) return @@ -141,6 +153,7 @@ const Timeline = { this.$store.commit('queueFlush', { timeline: this.timelineName, id: 0 }) this.fetchOlderStatuses() } else { + this.blockClicksTemporarily() this.$store.commit('showNewStatuses', { timeline: this.timelineName }) this.paused = false } diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue index aaf0349c..373b946f 100644 --- a/src/components/timeline/timeline.vue +++ b/src/components/timeline/timeline.vue @@ -1,5 +1,5 @@ <template> - <div :class="[classes.root, 'timeline']"> + <div :class="[classes.root, 'Timeline']"> <div :class="classes.header"> <TimelineMenu v-if="!embedded" /> <div @@ -107,10 +107,14 @@ <style lang="scss"> @import '../../_variables.scss'; -.timeline { +.Timeline { .loadmore-text { opacity: 1; } + + &.-blocked { + pointer-events: none; + } } .timeline-heading { diff --git a/src/i18n/eo.json b/src/i18n/eo.json index e73ac2f8..1247d50d 100644 --- a/src/i18n/eo.json +++ b/src/i18n/eo.json @@ -5,7 +5,7 @@ "features_panel": { "chat": "Babilejo", "gopher": "Gopher", - "media_proxy": "Vidaŭdaĵa prokurilo", + "media_proxy": "Vidaŭdaĵa retperilo", "scope_options": "Agordoj de amplekso", "text_limit": "Limo de teksto", "title": "Funkcioj", @@ -33,7 +33,8 @@ "show_more": "Montri plion", "retry": "Reprovi", "error_retry": "Bonvolu reprovi", - "loading": "Enlegante…" + "loading": "Enlegante…", + "peek": "Antaŭmontri" }, "image_cropper": { "crop_picture": "Tondi bildon", @@ -70,9 +71,9 @@ "friend_requests": "Petoj pri abono", "mentions": "Mencioj", "dms": "Rektaj mesaĝoj", - "public_tl": "Publika tempolinio", - "timeline": "Tempolinio", - "twkn": "La tuta konata reto", + "public_tl": "Publika historio", + "timeline": "Historio", + "twkn": "Konata reto", "user_search": "Serĉi uzantojn", "who_to_follow": "Kiun aboni", "preferences": "Agordoj", @@ -80,7 +81,8 @@ "search": "Serĉi", "interactions": "Interagoj", "administration": "Administrado", - "bookmarks": "Legosignoj" + "bookmarks": "Legosignoj", + "timelines": "Historioj" }, "notifications": { "broken_favorite": "Nekonata stato, serĉante ĝin…", @@ -107,14 +109,14 @@ "text/html": "HTML" }, "content_warning": "Temo (malnepra)", - "default": "Ĵus alvenis al la Universala Kongreso!", + "default": "Ĵus alvenis Esperantujon!", "direct_warning": "Ĉi tiu afiŝo estos videbla nur por ĉiuj menciitaj uzantoj.", "posting": "Afiŝante", "scope": { "direct": "Rekta – Afiŝi nur al menciitaj uzantoj", "private": "Nur abonantoj – Afiŝi nur al abonantoj", - "public": "Publika – Afiŝi al publikaj tempolinioj", - "unlisted": "Nelistigita – Ne afiŝi al publikaj tempolinioj" + "public": "Publika – Afiŝi al publikaj historioj", + "unlisted": "Nelistigita – Ne afiŝi al publikaj historioj" }, "scope_notice": { "unlisted": "Ĉi tiu afiŝo ne estos videbla en la Publika historio kaj La tuta konata reto", @@ -193,7 +195,7 @@ "foreground": "Malfono", "general": "Ĝenerala", "hide_attachments_in_convo": "Kaŝi kunsendaĵojn en interparoloj", - "hide_attachments_in_tl": "Kaŝi kunsendaĵojn en tempolinio", + "hide_attachments_in_tl": "Kaŝi kunsendaĵojn en historioj", "max_thumbnails": "Maksimuma nombro da bildetoj en afiŝo", "hide_isp": "Kaŝi breton propran al nodo", "preload_images": "Antaŭ-enlegi bildojn", @@ -246,7 +248,7 @@ "profile_banner": "Rubando de profilo", "profile_tab": "Profilo", "radii_help": "Agordi fasadan rondigon de randoj (bildere)", - "replies_in_timeline": "Respondoj en tempolinio", + "replies_in_timeline": "Respondoj en historioj", "reply_visibility_all": "Montri ĉiujn respondojn", "reply_visibility_following": "Montri nur respondojn por mi aŭ miaj abonatoj", "reply_visibility_self": "Montri nur respondojn por mi", @@ -297,7 +299,12 @@ "older_version_imported": "La enportita dosiero estis farita per pli malnova versio de PleromaFE.", "future_version_imported": "La enportita dosiero estis farita per pli nova versio de PleromaFE.", "v2_imported": "La dosiero, kiun vi enportis, estis farita por malnova versio de PleromaFE. Ni provas maksimumigi interkonformecon, sed tamen eble montriĝos misoj.", - "upgraded_from_v2": "PleromaFE estis ĝisdatigita; la haŭto eble aspektos malsame ol kiel vi ĝin memoras." + "upgraded_from_v2": "PleromaFE estis ĝisdatigita; la haŭto eble aspektos malsame ol kiel vi ĝin memoras.", + "snapshot_missing": "Neniu momentokopio de haŭto estis en la dosiero, ĝi povas aspekti iom malsame ol oni intencis.", + "snapshot_present": "Ĉiuj valoroj estas transpasataj, ĉar momentokopio de haŭto estas enlegita. Vi povas enlegi anstataŭe la aktualajn datumojn de haŭto.", + "snapshot_source_mismatch": "Versioj konfliktas: plej probable la fasado estis reirigita kaj ree ĝisdatigita; se vi ŝanĝis la haŭton per pli malnova versio de la fasado, vi probable volas uzi la malnovan version. Alie uzu la novan.", + "migration_napshot_gone": "Ial mankis momentokopio; io povus aspekti malsame ol en via memoro.", + "migration_snapshot_ok": "Certige, momentokopio de la haŭto enlegiĝis. Vi povas provi enlegi datumojn de la haŭto." }, "use_source": "Nova versio", "use_snapshot": "Malnova versio", @@ -352,10 +359,11 @@ "icons": "Bildsimboloj", "poll": "Grafo de enketo", "underlay": "Subtavolo", - "popover": "Ŝpruchelpiloj, menuoj", + "popover": "Ŝprucaĵoj, menuoj", "post": "Afiŝoj/Priskriboj de uzantoj", "alert_neutral": "Neŭtrala", - "alert_warning": "Averto" + "alert_warning": "Averto", + "toggled": "Ŝaltita" }, "radii": { "_tab_label": "Rondeco" @@ -388,7 +396,8 @@ "buttonPressed": "Butono (premita)", "buttonPressedHover": "Butono (premita kaj je ŝvebo)", "input": "Eniga kampo" - } + }, + "hintV3": "Kolorojn de ombroj vi ankaŭ povas skribi per la sistemo {0}." }, "fonts": { "_tab_label": "Tiparoj", @@ -411,7 +420,7 @@ "button": "Butono", "text": "Kelko da pliaj {0} kaj {1}", "mono": "enhavo", - "input": "Ĵus alvenis al la Universala Kongreso!", + "input": "Ĵus alvenis Esperantujon!", "faint_link": "helpan manlibron", "fine_print": "Legu nian {0} por nenion utilan ekscii!", "header_faint": "Tio estas en ordo", @@ -420,7 +429,7 @@ } }, "discoverable": "Permesi trovon de ĉi tiu konto en serĉrezultoj kaj aliaj servoj", - "mutes_and_blocks": "Silentigitoj kaj blokitoj", + "mutes_and_blocks": "Blokado kaj silentigoj", "chatMessageRadius": "Babileja mesaĝo", "changed_email": "Retpoŝtadreso sukcese ŝanĝiĝis!", "change_email_error": "Eraris ŝanĝo de via retpoŝtadreso.", @@ -448,7 +457,10 @@ "warning_of_generate_new_codes": "Kiam vi estigos novajn rehavajn kodojn, viaj malnovaj ne plu funkcios.", "generate_new_recovery_codes": "Estigi novajn rehavajn kodojn", "title": "Duobla aŭtentikigo", - "otp": "OTP" + "otp": "OTP", + "wait_pre_setup_otp": "antaŭagordante OTP", + "setup_otp": "Agordi OTP", + "confirm_and_enable": "Konfirmi kaj ŝalti OTP" }, "enter_current_password_to_confirm": "Enigu vian pasvorton por konfirmi vian identecon", "security": "Sekureco", @@ -480,11 +492,11 @@ }, "import_blocks_from_a_csv_file": "Enporti blokitojn el CSV-dosiero", "hide_muted_posts": "Kaŝi afiŝojn de silentigitaj uzantoj", - "emoji_reactions_on_timeline": "Montri bildosignajn reagojn en la tempolinio", + "emoji_reactions_on_timeline": "Montri bildosignajn reagojn en historioj", "pad_emoji": "Meti spacetojn ĉirkaŭ bildosigno post ties elekto", "domain_mutes": "Retnomoj", "notification_blocks": "Blokinte uzanton vi malabonos ĝin kaj haltigos ĉiujn sciigojn.", - "notification_mutes": "Por ne plu ricevi sciigojn de certa uzanto, silentigu.", + "notification_mutes": "Por ne plu ricevi sciigojn de certa uzanto, silentigu ĝin.", "notification_setting_hide_notification_contents": "Kaŝi la sendinton kaj la enhavojn de pasivaj sciigoj", "notification_setting_privacy": "Privateco", "notification_setting_block_from_strangers": "Bloki sciigojn de uzantoj, kiujn vi ne abonas", @@ -495,7 +507,14 @@ "backend_version": "Versio de internaĵo", "title": "Versio" }, - "accent": "Emfazo" + "accent": "Emfazo", + "virtual_scrolling": "Optimumigi bildigon de historioj", + "import_mutes_from_a_csv_file": "Enporti silentigojn el CSV-dosiero", + "mutes_imported": "Silentigoj enportiĝis! Traktado daŭros iom da tempo.", + "mute_import_error": "Eraris enporto de silentigoj", + "mute_import": "Enporto de silentigoj", + "mute_export_button": "Elportu viajn silentigojn al CSV-dosiero", + "mute_export": "Elporto de silentigoj" }, "timeline": { "collapse": "Maletendi", @@ -503,7 +522,7 @@ "error_fetching": "Eraris ĝisdatigo", "load_older": "Montri pli malnovajn statojn", "no_retweet_hint": "Afiŝo estas markita kiel rekta aŭ nur por abonantoj, kaj ne eblas ĝin ripeti", - "repeated": "ripetita", + "repeated": "ripetis", "show_new": "Montri novajn", "up_to_date": "Ĝisdata", "no_more_statuses": "Neniuj pliaj statoj", @@ -648,21 +667,22 @@ "media_nsfw": "Devige marki vidaŭdaĵojn konsternaj", "media_removal_desc": "Ĉi tiu nodo forigas vidaŭdaĵojn de afiŝoj el la jenaj nodoj:", "media_removal": "Forigo de vidaŭdaĵoj", - "ftl_removal": "Forigo de la historio de «La tuta konata reto»", + "ftl_removal": "Forigo el la historio de «La tuta konata reto»", "quarantine_desc": "Ĉi tiu nodo sendos nur publikajn afiŝojn al la jenaj nodoj:", "quarantine": "Kvaranteno", "reject_desc": "Ĉi tiu nodo ne akceptos mesaĝojn de la jenaj nodoj:", "reject": "Rifuzi", "accept_desc": "Ĉi tiu nodo nur akceptas mesaĝojn de la jenaj nodoj:", "accept": "Akcepti", - "simple_policies": "Specialaj politikoj de la nodo" + "simple_policies": "Specialaj politikoj de la nodo", + "ftl_removal_desc": "Ĉi tiu nodo forigas la jenajn nodojn el la historio de «La tuta konata reto»:" }, "mrf_policies": "Ŝaltis politikon de Mesaĝa ŝanĝilaro (MRF)", "keyword": { "is_replaced_by": "→", "replace": "Anstataŭigi", "reject": "Rifuzi", - "ftl_removal": "Forigo de la historio de «La tuta konata reto»", + "ftl_removal": "Forigo el la historio de «La tuta konata reto»", "keyword_policies": "Politiko pri ŝlosilvortoj" }, "federation": "Federado", @@ -707,7 +727,8 @@ "pin": "Fiksi al profilo", "delete": "Forigi staton", "repeats": "Ripetoj", - "favorites": "Ŝatataj" + "favorites": "Ŝatoj", + "status_deleted": "Ĉi tiu afiŝo foriĝis" }, "time": { "years_short": "{0}j", @@ -769,7 +790,8 @@ "new": "Nova babilo", "chats": "Babiloj", "delete": "Forigi", - "you": "Vi:" + "you": "Vi:", + "message_user": "Mesaĝi al {nickname}" }, "password_reset": { "password_reset_required_but_mailer_is_disabled": "Vi devas restarigi vian pasvorton, sed restarigado de pasvortoj estas malŝaltita. Bonvolu kontakti la administranton de via nodo.", @@ -791,5 +813,8 @@ "additional_comments": "Aldonaj komentoj", "add_comment_description": "Ĉi tiu raporto sendiĝos al reguligistoj de via nodo. Vi povas komprenigi kial vi raportas ĉi tiun konton sube:", "title": "Raportante {0}" + }, + "shoutbox": { + "title": "Kriujo" } } diff --git a/src/i18n/zh.json b/src/i18n/zh.json index 60204aa1..09e2ab0d 100644 --- a/src/i18n/zh.json +++ b/src/i18n/zh.json @@ -103,7 +103,7 @@ "repeated_you": "转发了你的状态", "no_more_notifications": "没有更多的通知", "reacted_with": "作出了 {0} 的反应", - "migrated_to": "迁移到", + "migrated_to": "迁移到了", "follow_request": "想要关注你" }, "polls": { @@ -165,7 +165,7 @@ "registration": { "bio": "简介", "email": "电子邮箱", - "fullname": "全名", + "fullname": "显示名称", "password_confirm": "确认密码", "registration": "注册", "token": "邀请码", @@ -322,7 +322,7 @@ "search_user_to_mute": "搜索你想要隐藏的用户", "security_tab": "安全", "scope_copy": "回复时的复制范围(私信是总是复制的)", - "minimal_scopes_mode": "最小发文范围", + "minimal_scopes_mode": "使发文可见范围的选项最少化", "set_new_avatar": "设置新头像", "set_new_profile_background": "设置新的个人资料背景", "set_new_profile_banner": "设置新的横幅图片", diff --git a/src/i18n/zh_Hant.json b/src/i18n/zh_Hant.json index 79a992fc..f2625116 100644 --- a/src/i18n/zh_Hant.json +++ b/src/i18n/zh_Hant.json @@ -680,7 +680,7 @@ "fullname": "顯示名稱", "bio_placeholder": "例如:\n你好,我是玲音。\n我是一個住在日本郊區的動畫少女。你可能在 Wired 見過我。", "fullname_placeholder": "例如:岩倉玲音", - "username_placeholder": "例如:玲音", + "username_placeholder": "例如:lain", "new_captcha": "點擊圖片獲取新的驗證碼", "captcha": "CAPTCHA", "token": "邀請碼", diff --git a/src/services/chat_utils/chat_utils.js b/src/services/chat_utils/chat_utils.js index 583438f7..86fe1af9 100644 --- a/src/services/chat_utils/chat_utils.js +++ b/src/services/chat_utils/chat_utils.js @@ -3,7 +3,7 @@ import { showDesktopNotification } from '../desktop_notification_utils/desktop_n export const maybeShowChatNotification = (store, chat) => { if (!chat.lastMessage) return if (store.rootState.chats.currentChatId === chat.id && !document.hidden) return - if (store.rootState.users.currentUser.id === chat.lastMessage.account.id) return + if (store.rootState.users.currentUser.id === chat.lastMessage.account_id) return const opts = { tag: chat.lastMessage.id, diff --git a/src/services/promise_interval/promise_interval.js b/src/services/promise_interval/promise_interval.js index cf17970d..0c0a66a0 100644 --- a/src/services/promise_interval/promise_interval.js +++ b/src/services/promise_interval/promise_interval.js @@ -10,7 +10,14 @@ export const promiseInterval = (promiseCall, interval) => { let timeout = null const func = () => { - promiseCall().finally(() => { + const promise = promiseCall() + // something unexpected happened and promiseCall did not + // return a promise, abort the loop. + if (!(promise && promise.finally)) { + console.warn('promiseInterval: promise call did not return a promise, stopping interval.') + return + } + promise.finally(() => { if (stopped) return timeout = window.setTimeout(func, interval) }) |
