From babd82d09a8341117fa16bcb6cab11d97de6503a Mon Sep 17 00:00:00 2001 From: Jose Delvani Date: Wed, 17 Apr 2024 21:00:45 +0000 Subject: [PATCH 01/12] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (827 of 827 strings) Translation: FreeTube/Translations Translate-URL: https://hosted.weblate.org/projects/free-tube/translations/pt_BR/ --- static/locales/pt-BR.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/static/locales/pt-BR.yaml b/static/locales/pt-BR.yaml index 415e076b5..133034db9 100644 --- a/static/locales/pt-BR.yaml +++ b/static/locales/pt-BR.yaml @@ -218,7 +218,7 @@ User Playlists: History: # On History Page History: 'Histórico' - Watch History: 'Histórico de visualizações' + Watch History: 'Histórico de exibição' Your history list is currently empty.: 'Seu histórico está vazio no momento.' Search bar placeholder: Pesquisar no histórico Empty Search Message: Não há vídeos em seu histórico que correspondam à sua pesquisa @@ -436,15 +436,15 @@ Settings: #& No Privacy Settings: - Watch history has been cleared: Histórico de visualizações foi apagado + Watch history has been cleared: O histórico de exibição foi apagado Are you sure you want to remove your entire watch history?: Tem certeza de que - deseja remover todo o seu histórico de visualizações? - Remove Watch History: Remover histórico + deseja remover todo o seu histórico de exibição? + Remove Watch History: Remover histórico de exibição Search cache has been cleared: Cache de pesquisas foi apagado Are you sure you want to clear out your search cache?: Tem certeza de que deseja limpar o cache de pesquisa? Clear Search Cache: Limpar cache de buscas - Save Watched Progress: Salvar progresso de visualização + Save Watched Progress: Salvar progresso de exibição Remember History: Lembrar histórico Privacy Settings: Configurações de privacidade Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: Tem @@ -483,10 +483,10 @@ Settings: Unknown data key: Chave de dados desconhecida Unable to write file: O arquivo não pôde ser salvo Unable to read file: O arquivo não pôde ser lido - All watched history has been successfully exported: Todo o histórico de visualizações - foi exportado com sucesso - All watched history has been successfully imported: Todo o histórico de visualizações - foi importado com sucesso + All watched history has been successfully exported: O histórico de exibição foi + exportado com sucesso + All watched history has been successfully imported: O histórico de exibição foi + importado com sucesso History object has insufficient data, skipping item: O histórico tem dados insuficientes, pulando item This might take a while, please wait: Este processo pode demorar, por favor espere From a1067327e2d191a0b3d44642024c4c9bf6e867ec Mon Sep 17 00:00:00 2001 From: Rex_sa Date: Wed, 17 Apr 2024 19:45:23 +0000 Subject: [PATCH 02/12] Translated using Weblate (Arabic) Currently translated at 100.0% (827 of 827 strings) Translation: FreeTube/Translations Translate-URL: https://hosted.weblate.org/projects/free-tube/translations/ar/ --- static/locales/ar.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/static/locales/ar.yaml b/static/locales/ar.yaml index 8dc39cee0..7d3f4dff9 100644 --- a/static/locales/ar.yaml +++ b/static/locales/ar.yaml @@ -265,6 +265,9 @@ Settings: Ask Before Opening Link: اسأل قبل فتح الرابط Open Link: افتح الرابط External Link Handling: معالجة الارتباط الخارجي + Auto Load Next Page: + Label: تحميل تلقائي للصفحة التالية + Tooltip: قم بتحميل الصفحات والتعليقات الإضافية تلقائيًا. Theme Settings: Theme Settings: 'إعدادات السِمة' Match Top Bar with Main Color: 'طابق الشريط العلوي مع اللون الأساسي' @@ -950,6 +953,15 @@ Playlist: #* Published #& Views Playlist: قائمة التشغيل + Sort By: + Sort By: ترتيب حسب + DateAddedNewest: آخر مضاف أولا + DateAddedOldest: الأقدم إضافتا أولا + AuthorAscending: الكاتب (A-Z) + AuthorDescending: الكاتب (Z-A) + VideoTitleAscending: العنوان (A-Z) + VideoTitleDescending: العنوان (Z-A) + Custom: مُخصّص Toggle Theatre Mode: 'تمكين وضع المسرح' Change Format: Change Media Formats: 'تغيير تنسيقات الفيديو' From 8483c8e3f85e9915de201259179bfb95c893405c Mon Sep 17 00:00:00 2001 From: Milo Ivir Date: Wed, 17 Apr 2024 20:27:22 +0000 Subject: [PATCH 03/12] Translated using Weblate (Croatian) Currently translated at 99.1% (820 of 827 strings) Translation: FreeTube/Translations Translate-URL: https://hosted.weblate.org/projects/free-tube/translations/hr/ --- static/locales/hr.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/static/locales/hr.yaml b/static/locales/hr.yaml index efc568729..a3557c353 100644 --- a/static/locales/hr.yaml +++ b/static/locales/hr.yaml @@ -266,6 +266,9 @@ Settings: Ask Before Opening Link: Pitaj prije otvaranja poveznice Open Link: Otvori poveznicu External Link Handling: Rukovanje vanjskim poveznicama + Auto Load Next Page: + Label: Automatski učitaj sljedeću stranicu + Tooltip: Automatski učitaj dodatne stranice i komentare. Theme Settings: Theme Settings: 'Postavke teme' Match Top Bar with Main Color: 'Koristi glavnu boju u gornjoj traci' @@ -961,6 +964,8 @@ Playlist: #* Published #& Views Playlist: Zbirka + Sort By: + Sort By: Redoslijed Toggle Theatre Mode: 'Uključi/isključi kazališni modus' Change Format: Change Media Formats: 'Promijeni videoformate' From 2bc44cd66b0c5e6e3f9716fdac572bee4f054d47 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Wed, 17 Apr 2024 17:50:23 -0400 Subject: [PATCH 04/12] Define emits before using them (#4973) Co-authored-by: absidue <48293849+absidue@users.noreply.github.com> --- .eslintrc.js | 2 ++ .../ft-auto-load-next-page-wrapper.js | 1 + src/renderer/components/ft-channel-bubble/ft-channel-bubble.js | 1 + src/renderer/components/ft-icon-button/ft-icon-button.js | 1 + src/renderer/components/ft-input-tags/ft-input-tags.js | 1 + src/renderer/components/ft-input/ft-input.js | 1 + src/renderer/components/ft-list-video/ft-list-video.js | 1 + .../components/ft-notification-banner/ft-notification-banner.js | 1 + .../components/ft-playlist-selector/ft-playlist-selector.js | 1 + src/renderer/components/ft-profile-edit/ft-profile-edit.js | 1 + src/renderer/components/ft-prompt/ft-prompt.js | 1 + src/renderer/components/ft-search-filters/ft-search-filters.js | 1 + .../components/ft-timestamp-catcher/ft-timestamp-catcher.js | 1 + src/renderer/components/ft-video-player/ft-video-player.js | 1 + src/renderer/components/playlist-info/playlist-info.js | 1 + .../components/subscriptions-tab-ui/subscriptions-tab-ui.js | 1 + .../components/watch-video-chapters/watch-video-chapters.js | 1 + .../components/watch-video-comments/watch-video-comments.js | 1 + .../watch-video-description/watch-video-description.js | 1 + src/renderer/components/watch-video-info/watch-video-info.js | 1 + 20 files changed, 21 insertions(+) diff --git a/.eslintrc.js b/.eslintrc.js index 1846e7791..f342b62dd 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -112,6 +112,8 @@ module.exports = { ignoreText: ['-', '•', '/', 'YouTube', 'Invidious', 'FreeTube'] } ], + 'vue/require-explicit-emits': 'error', + 'vue/no-unused-emit-declarations': 'error', }, settings: { 'vue-i18n': { diff --git a/src/renderer/components/ft-auto-load-next-page-wrapper/ft-auto-load-next-page-wrapper.js b/src/renderer/components/ft-auto-load-next-page-wrapper/ft-auto-load-next-page-wrapper.js index aca042948..4b26e8866 100644 --- a/src/renderer/components/ft-auto-load-next-page-wrapper/ft-auto-load-next-page-wrapper.js +++ b/src/renderer/components/ft-auto-load-next-page-wrapper/ft-auto-load-next-page-wrapper.js @@ -2,6 +2,7 @@ import { defineComponent } from 'vue' export default defineComponent({ name: 'FtAutoLoadNextPageWrapper', + emits: ['load-next-page'], computed: { generalAutoLoadMorePaginatedItemsEnabled() { return this.$store.getters.getGeneralAutoLoadMorePaginatedItemsEnabled diff --git a/src/renderer/components/ft-channel-bubble/ft-channel-bubble.js b/src/renderer/components/ft-channel-bubble/ft-channel-bubble.js index c9854b34d..dbff93d28 100644 --- a/src/renderer/components/ft-channel-bubble/ft-channel-bubble.js +++ b/src/renderer/components/ft-channel-bubble/ft-channel-bubble.js @@ -20,6 +20,7 @@ export default defineComponent({ default: false } }, + emits: ['click'], data: function () { return { selected: false diff --git a/src/renderer/components/ft-icon-button/ft-icon-button.js b/src/renderer/components/ft-icon-button/ft-icon-button.js index fb6b4a3a9..97062b495 100644 --- a/src/renderer/components/ft-icon-button/ft-icon-button.js +++ b/src/renderer/components/ft-icon-button/ft-icon-button.js @@ -61,6 +61,7 @@ export default defineComponent({ default: false } }, + emits: ['click'], data: function () { return { dropdownShown: false, diff --git a/src/renderer/components/ft-input-tags/ft-input-tags.js b/src/renderer/components/ft-input-tags/ft-input-tags.js index e139db3b7..281b35171 100644 --- a/src/renderer/components/ft-input-tags/ft-input-tags.js +++ b/src/renderer/components/ft-input-tags/ft-input-tags.js @@ -53,6 +53,7 @@ export default defineComponent({ default: (_) => ({ preferredName: '', icon: '' }), } }, + emits: ['already-exists', 'change', 'error-find-tag-info', 'invalid-name'], methods: { updateTags: async function (text, _e) { if (this.areChannelTags) { diff --git a/src/renderer/components/ft-input/ft-input.js b/src/renderer/components/ft-input/ft-input.js index dc4c945c2..9c3bfc197 100644 --- a/src/renderer/components/ft-input/ft-input.js +++ b/src/renderer/components/ft-input/ft-input.js @@ -64,6 +64,7 @@ export default defineComponent({ default: '' } }, + emits: ['clear', 'click', 'input'], data: function () { let actionIcon = ['fas', 'search'] if (this.forceActionButtonIconName !== null) { diff --git a/src/renderer/components/ft-list-video/ft-list-video.js b/src/renderer/components/ft-list-video/ft-list-video.js index 8745a2483..becb7185d 100644 --- a/src/renderer/components/ft-list-video/ft-list-video.js +++ b/src/renderer/components/ft-list-video/ft-list-video.js @@ -84,6 +84,7 @@ export default defineComponent({ default: false, }, }, + emits: ['pause-player'], data: function () { return { id: '', diff --git a/src/renderer/components/ft-notification-banner/ft-notification-banner.js b/src/renderer/components/ft-notification-banner/ft-notification-banner.js index 9973993cb..75c7c4c87 100644 --- a/src/renderer/components/ft-notification-banner/ft-notification-banner.js +++ b/src/renderer/components/ft-notification-banner/ft-notification-banner.js @@ -8,6 +8,7 @@ export default defineComponent({ required: true } }, + emits: ['click'], methods: { handleClick: function (response) { this.$emit('click', response) diff --git a/src/renderer/components/ft-playlist-selector/ft-playlist-selector.js b/src/renderer/components/ft-playlist-selector/ft-playlist-selector.js index 61c2551f2..dbb64c271 100644 --- a/src/renderer/components/ft-playlist-selector/ft-playlist-selector.js +++ b/src/renderer/components/ft-playlist-selector/ft-playlist-selector.js @@ -25,6 +25,7 @@ export default defineComponent({ required: true, }, }, + emits: ['selected'], data: function () { return { title: '', diff --git a/src/renderer/components/ft-profile-edit/ft-profile-edit.js b/src/renderer/components/ft-profile-edit/ft-profile-edit.js index 4cf9029c9..f89b449f1 100644 --- a/src/renderer/components/ft-profile-edit/ft-profile-edit.js +++ b/src/renderer/components/ft-profile-edit/ft-profile-edit.js @@ -32,6 +32,7 @@ export default defineComponent({ required: true } }, + emits: ['new-profile-created', 'profile-deleted'], data: function () { return { showDeletePrompt: false, diff --git a/src/renderer/components/ft-prompt/ft-prompt.js b/src/renderer/components/ft-prompt/ft-prompt.js index 060a4a006..45296bbfd 100644 --- a/src/renderer/components/ft-prompt/ft-prompt.js +++ b/src/renderer/components/ft-prompt/ft-prompt.js @@ -38,6 +38,7 @@ export default defineComponent({ default: false } }, + emits: ['click'], data: function () { return { promptButtons: [], diff --git a/src/renderer/components/ft-search-filters/ft-search-filters.js b/src/renderer/components/ft-search-filters/ft-search-filters.js index 3fe6da742..bebeafcdc 100644 --- a/src/renderer/components/ft-search-filters/ft-search-filters.js +++ b/src/renderer/components/ft-search-filters/ft-search-filters.js @@ -8,6 +8,7 @@ export default defineComponent({ 'ft-flex-box': FtFlexBox, 'ft-radio-button': FtRadioButton }, + emits: ['filterValueUpdated'], data: function () { return { sortByValues: [ diff --git a/src/renderer/components/ft-timestamp-catcher/ft-timestamp-catcher.js b/src/renderer/components/ft-timestamp-catcher/ft-timestamp-catcher.js index 1006ea594..fb60e08a2 100644 --- a/src/renderer/components/ft-timestamp-catcher/ft-timestamp-catcher.js +++ b/src/renderer/components/ft-timestamp-catcher/ft-timestamp-catcher.js @@ -8,6 +8,7 @@ export default defineComponent({ default: '' } }, + emits: ['timestamp-event'], methods: { catchTimestampClick: function (event) { this.$emit('timestamp-event', event.detail) diff --git a/src/renderer/components/ft-video-player/ft-video-player.js b/src/renderer/components/ft-video-player/ft-video-player.js index afe83aff3..4cacc6a19 100644 --- a/src/renderer/components/ft-video-player/ft-video-player.js +++ b/src/renderer/components/ft-video-player/ft-video-player.js @@ -117,6 +117,7 @@ export default defineComponent({ default: false } }, + emits: ['ended', 'error', 'ready', 'store-caption-list', 'timeupdate', 'toggle-theatre-mode'], data: function () { return { powerSaveBlocker: null, diff --git a/src/renderer/components/playlist-info/playlist-info.js b/src/renderer/components/playlist-info/playlist-info.js index 082462405..30801bd6f 100644 --- a/src/renderer/components/playlist-info/playlist-info.js +++ b/src/renderer/components/playlist-info/playlist-info.js @@ -96,6 +96,7 @@ export default defineComponent({ required: true, }, }, + emits: ['enter-edit-mode', 'exit-edit-mode', 'search-video-query-change'], data: function () { return { searchVideoMode: false, diff --git a/src/renderer/components/subscriptions-tab-ui/subscriptions-tab-ui.js b/src/renderer/components/subscriptions-tab-ui/subscriptions-tab-ui.js index 1c72b620b..73e6e40fc 100644 --- a/src/renderer/components/subscriptions-tab-ui/subscriptions-tab-ui.js +++ b/src/renderer/components/subscriptions-tab-ui/subscriptions-tab-ui.js @@ -47,6 +47,7 @@ export default defineComponent({ default: 100 } }, + emits: ['refresh'], data: function () { return { dataLimit: 100, diff --git a/src/renderer/components/watch-video-chapters/watch-video-chapters.js b/src/renderer/components/watch-video-chapters/watch-video-chapters.js index 74885cbdf..dd49f2e95 100644 --- a/src/renderer/components/watch-video-chapters/watch-video-chapters.js +++ b/src/renderer/components/watch-video-chapters/watch-video-chapters.js @@ -16,6 +16,7 @@ export default defineComponent({ required: true } }, + emits: ['timestamp-event'], data: function () { return { showChapters: false, diff --git a/src/renderer/components/watch-video-comments/watch-video-comments.js b/src/renderer/components/watch-video-comments/watch-video-comments.js index b0e3bc9e5..6db944bf3 100644 --- a/src/renderer/components/watch-video-comments/watch-video-comments.js +++ b/src/renderer/components/watch-video-comments/watch-video-comments.js @@ -37,6 +37,7 @@ export default defineComponent({ default: null, }, }, + emits: ['timestamp-event'], data: function () { return { isLoading: false, diff --git a/src/renderer/components/watch-video-description/watch-video-description.js b/src/renderer/components/watch-video-description/watch-video-description.js index 7bab5214a..7d96f86e5 100644 --- a/src/renderer/components/watch-video-description/watch-video-description.js +++ b/src/renderer/components/watch-video-description/watch-video-description.js @@ -19,6 +19,7 @@ export default defineComponent({ default: '' } }, + emits: ['timestamp-event'], data: function () { return { shownDescription: '' diff --git a/src/renderer/components/watch-video-info/watch-video-info.js b/src/renderer/components/watch-video-info/watch-video-info.js index 7bc33dc09..506998459 100644 --- a/src/renderer/components/watch-video-info/watch-video-info.js +++ b/src/renderer/components/watch-video-info/watch-video-info.js @@ -104,6 +104,7 @@ export default defineComponent({ required: true } }, + emits: ['set-info-area-sticky', 'scroll-to-info-area', 'pause-player'], computed: { hideSharingActions: function() { return this.$store.getters.getHideSharingActions From ab3c1b9b29e93685a9c353451bc269334da2793c Mon Sep 17 00:00:00 2001 From: Jason <84899178+jasonhenriquez@users.noreply.github.com> Date: Wed, 17 Apr 2024 21:54:46 +0000 Subject: [PATCH 05/12] Show when Subscriptions / Trending / Most Popular were last updated (#4380) * Implement first draft of last subscription refresh timestamp * Update styling to be a top bar * Update styling to be banner-compatible, & increase banner X button size on mobile * Update subscription refresh timestamp to be relative * Implement refresh timestamps for Shorts, Live, and Community tabs * Extract refresh widget to its own component * Add Trending and Popular refresh widgets with timestamps * Fix justifying when no timestamp exists * Move timestamps to utils store * Remove unneeded ref classes and currentLocale computed property * Add page-specific titles for each feed type * Implement showing least recent cache date per profile * Update styling property placement & match top nav box shadow on ft-refresh-widget * Implement showing timestamp for profile only if all channel subscriptions can be found in cache * Disable refresh button instead of removing it or the widget from the DOM * Increase top banner's top margin * Update channel caching calls to provide timestamps * Modify updateCacheByChannel functions to have default timestamp of new Date() * Fix 30-day month relative date calculation scenarios through new optional parameter * Rectify Case 3 (see https://github.com/FreeTubeApp/FreeTube/pull/3668) * Add back missing line in Popular.js --- src/renderer/App.css | 10 ++- .../ft-icon-button/ft-icon-button.js | 6 ++ .../ft-icon-button/ft-icon-button.scss | 6 ++ .../ft-icon-button/ft-icon-button.vue | 3 +- .../components/ft-list-video/ft-list-video.js | 55 ++------------ .../ft-notification-banner.css | 8 +++ .../ft-notification-banner.vue | 2 +- .../ft-refresh-widget/ft-refresh-widget.css | 36 ++++++++++ .../ft-refresh-widget/ft-refresh-widget.js | 29 ++++++++ .../ft-refresh-widget/ft-refresh-widget.vue | 27 +++++++ .../subscriptions-community.js | 28 ++++++-- .../subscriptions-community.vue | 2 + .../subscriptions-live/subscriptions-live.js | 21 +++++- .../subscriptions-live/subscriptions-live.vue | 2 + .../subscriptions-shorts.js | 22 +++++- .../subscriptions-shorts.vue | 2 + .../subscriptions-tab-ui.css | 12 ---- .../subscriptions-tab-ui.js | 14 +++- .../subscriptions-tab-ui.vue | 11 ++- .../subscriptions-videos.js | 25 ++++++- .../subscriptions-videos.vue | 2 + src/renderer/helpers/utils.js | 57 +++++++++++++++ src/renderer/store/modules/subscriptions.js | 12 ++-- src/renderer/store/modules/utils.js | 72 ++++++++++++++++++- src/renderer/views/Popular/Popular.css | 12 ---- src/renderer/views/Popular/Popular.js | 17 ++++- src/renderer/views/Popular/Popular.vue | 10 ++- src/renderer/views/Trending/Trending.css | 12 ---- src/renderer/views/Trending/Trending.js | 17 ++++- src/renderer/views/Trending/Trending.vue | 10 ++- static/locales/en-US.yaml | 5 +- 31 files changed, 412 insertions(+), 135 deletions(-) create mode 100644 src/renderer/components/ft-refresh-widget/ft-refresh-widget.css create mode 100644 src/renderer/components/ft-refresh-widget/ft-refresh-widget.js create mode 100644 src/renderer/components/ft-refresh-widget/ft-refresh-widget.vue diff --git a/src/renderer/App.css b/src/renderer/App.css index 24b765ca8..036435314 100644 --- a/src/renderer/App.css +++ b/src/renderer/App.css @@ -18,10 +18,14 @@ .banner { inline-size: 85%; - margin-block: 20px; + margin-block: 40px 0; margin-inline: auto; } +.banner + .banner { + margin-block: 20px; +} + .banner-wrapper { margin-block: 0; margin-inline: 10px; @@ -53,8 +57,8 @@ } .banner { - inline-size: 80%; - margin-block-start: 20px; + inline-size: 90%; + margin-block: 60px 0; } .flexBox { diff --git a/src/renderer/components/ft-icon-button/ft-icon-button.js b/src/renderer/components/ft-icon-button/ft-icon-button.js index 97062b495..cba8cfb34 100644 --- a/src/renderer/components/ft-icon-button/ft-icon-button.js +++ b/src/renderer/components/ft-icon-button/ft-icon-button.js @@ -16,6 +16,10 @@ export default defineComponent({ type: Array, default: () => ['fas', 'ellipsis-v'] }, + disabled: { + type: Boolean, + default: false + }, theme: { type: String, default: 'base' @@ -88,6 +92,7 @@ export default defineComponent({ }, handleIconClick: function () { + if (this.disabled) { return } if (this.forceDropdown || (this.dropdownOptions.length > 0)) { this.dropdownShown = !this.dropdownShown @@ -104,6 +109,7 @@ export default defineComponent({ }, handleIconMouseDown: function () { + if (this.disabled) { return } if (this.dropdownShown) { this.mouseDownOnIcon = true } diff --git a/src/renderer/components/ft-icon-button/ft-icon-button.scss b/src/renderer/components/ft-icon-button/ft-icon-button.scss index c76e9333f..6e4f3acb2 100644 --- a/src/renderer/components/ft-icon-button/ft-icon-button.scss +++ b/src/renderer/components/ft-icon-button/ft-icon-button.scss @@ -79,6 +79,12 @@ } } +.disabled { + opacity: 0.5; + pointer-events: none; + user-select: none; +} + .iconDropdown { background-color: var(--side-nav-color); box-shadow: 0 1px 2px rgb(0 0 0 / 50%); diff --git a/src/renderer/components/ft-icon-button/ft-icon-button.vue b/src/renderer/components/ft-icon-button/ft-icon-button.vue index afc4c68f4..8f4d2bfc7 100644 --- a/src/renderer/components/ft-icon-button/ft-icon-button.vue +++ b/src/renderer/components/ft-icon-button/ft-icon-button.vue @@ -7,7 +7,8 @@ :icon="icon" :class="{ [theme]: true, - shadow: useShadow + shadow: useShadow, + disabled }" :style="{ padding: padding + 'px', diff --git a/src/renderer/components/ft-list-video/ft-list-video.js b/src/renderer/components/ft-list-video/ft-list-video.js index becb7185d..8d4d6e3bf 100644 --- a/src/renderer/components/ft-list-video/ft-list-video.js +++ b/src/renderer/components/ft-list-video/ft-list-video.js @@ -5,6 +5,7 @@ import { copyToClipboard, formatDurationAsTimestamp, formatNumber, + getRelativeTimeFromDate, openExternalLink, showToast, toDistractionFreeTitle, @@ -345,6 +346,10 @@ export default defineComponent({ return this.historyEntryExists && !this.inHistory }, + currentLocale: function () { + return this.$i18n.locale.replace('_', '-') + }, + externalPlayer: function () { return this.$store.getters.getExternalPlayer }, @@ -462,14 +467,6 @@ export default defineComponent({ return query }, - currentLocale: function () { - return this.$i18n.locale.replace('_', '-') - }, - - showAddToPlaylistPrompt: function () { - return this.$store.getters.getShowAddToPlaylistPrompt - }, - useDeArrowTitles: function () { return this.$store.getters.getUseDeArrowTitles }, @@ -668,48 +665,8 @@ export default defineComponent({ if (this.inHistory) { this.uploadedTime = new Date(this.data.published).toLocaleDateString([this.currentLocale, 'en']) } else { - const now = new Date().getTime() - // Convert from ms to second - // For easier code interpretation the value is made to be positive - let timeDiffFromNow = ((now - this.data.published) / 1000) - let timeUnit = 'second' - - if (timeDiffFromNow >= 60) { - timeDiffFromNow /= 60 - timeUnit = 'minute' - } - - if (timeUnit === 'minute' && timeDiffFromNow >= 60) { - timeDiffFromNow /= 60 - timeUnit = 'hour' - } - - if (timeUnit === 'hour' && timeDiffFromNow >= 24) { - timeDiffFromNow /= 24 - timeUnit = 'day' - } - - const timeDiffFromNowDays = timeDiffFromNow - - if (timeUnit === 'day' && timeDiffFromNow >= 7) { - timeDiffFromNow /= 7 - timeUnit = 'week' - } - // Use 30 days per month, just like calculatePublishedDate - if (timeUnit === 'week' && timeDiffFromNowDays >= 30) { - timeDiffFromNow = timeDiffFromNowDays / 30 - timeUnit = 'month' - } - - if (timeUnit === 'month' && timeDiffFromNow >= 12) { - timeDiffFromNow /= 12 - timeUnit = 'year' - } - - // Using `Math.ceil` so that -1.x days ago displayed as 1 day ago - // Notice that the value is turned to negative to be displayed as "ago" - this.uploadedTime = new Intl.RelativeTimeFormat([this.currentLocale, 'en']).format(Math.ceil(-timeDiffFromNow), timeUnit) + this.uploadedTime = getRelativeTimeFromDate(new Date(this.data.published).toDateString(), false) } } diff --git a/src/renderer/components/ft-notification-banner/ft-notification-banner.css b/src/renderer/components/ft-notification-banner/ft-notification-banner.css index 2f8464be3..6efe9d4f9 100644 --- a/src/renderer/components/ft-notification-banner/ft-notification-banner.css +++ b/src/renderer/components/ft-notification-banner/ft-notification-banner.css @@ -30,3 +30,11 @@ inset-inline-end: 10px; cursor: pointer; } + +@media only screen and (width <= 680px) { + .bannerIcon { + inset-block-start: 27%; + block-size: 25px; + inline-size: 25px; + } +} diff --git a/src/renderer/components/ft-notification-banner/ft-notification-banner.vue b/src/renderer/components/ft-notification-banner/ft-notification-banner.vue index 02feed760..4b3ff2eb0 100644 --- a/src/renderer/components/ft-notification-banner/ft-notification-banner.vue +++ b/src/renderer/components/ft-notification-banner/ft-notification-banner.vue @@ -24,7 +24,7 @@ tabindex="0" :title="$t('Close Banner')" @click.stop="handleClose" - @keydown.enter.stop.prevent="handleClose" + @keydown.enter.space.stop.prevent="handleClose" /> diff --git a/src/renderer/components/ft-refresh-widget/ft-refresh-widget.css b/src/renderer/components/ft-refresh-widget/ft-refresh-widget.css new file mode 100644 index 000000000..3c9b49909 --- /dev/null +++ b/src/renderer/components/ft-refresh-widget/ft-refresh-widget.css @@ -0,0 +1,36 @@ +.floatingRefreshSection { + position: fixed; + inset-block-start: 60px; + inset-inline-end: 0; + box-sizing: border-box; + inline-size: calc(100% - 80px); + padding-block: 5px; + padding-inline: 10px; + box-shadow: 0 2px 1px 0 var(--primary-shadow-color); + background-color: var(--card-bg-color); + border-inline-start: 2px solid var(--primary-color); + display: flex; + align-items: center; + gap: 5px; + justify-content: flex-end; +} + +.floatingRefreshSection:has(.lastRefreshTimestamp + .refreshButton) { + justify-content: space-between; +} + +.floatingRefreshSection.sideNavOpen { + inline-size: calc(100% - 200px); +} + +.lastRefreshTimestamp { + margin-block: 0; + text-align: center; + font-size: 16px; +} + +@media only screen and (width <= 680px) { + .floatingRefreshSection, .floatingRefreshSection.sideNavOpen { + inline-size: 100%; + } +} diff --git a/src/renderer/components/ft-refresh-widget/ft-refresh-widget.js b/src/renderer/components/ft-refresh-widget/ft-refresh-widget.js new file mode 100644 index 000000000..24ca4e1f8 --- /dev/null +++ b/src/renderer/components/ft-refresh-widget/ft-refresh-widget.js @@ -0,0 +1,29 @@ +import { defineComponent } from 'vue' + +import FtIconButton from '../ft-icon-button/ft-icon-button.vue' + +export default defineComponent({ + name: 'FtRefreshWidget', + components: { + 'ft-icon-button': FtIconButton, + }, + props: { + disableRefresh: { + type: Boolean, + default: false + }, + lastRefreshTimestamp: { + type: String, + default: '' + }, + title: { + type: String, + required: true + } + }, + computed: { + isSideNavOpen: function () { + return this.$store.getters.getIsSideNavOpen + } + } +}) diff --git a/src/renderer/components/ft-refresh-widget/ft-refresh-widget.vue b/src/renderer/components/ft-refresh-widget/ft-refresh-widget.vue new file mode 100644 index 000000000..564f1cae8 --- /dev/null +++ b/src/renderer/components/ft-refresh-widget/ft-refresh-widget.vue @@ -0,0 +1,27 @@ + + +