Skip to content

Commit

Permalink
Show when Subscriptions / Trending / Most Popular were last updated (#…
Browse files Browse the repository at this point in the history
…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 #3668)

* Add back missing line in Popular.js
  • Loading branch information
kommunarr authored Apr 17, 2024
1 parent 2bc44cd commit ab3c1b9
Show file tree
Hide file tree
Showing 31 changed files with 412 additions and 135 deletions.
10 changes: 7 additions & 3 deletions src/renderer/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -53,8 +57,8 @@
}

.banner {
inline-size: 80%;
margin-block-start: 20px;
inline-size: 90%;
margin-block: 60px 0;
}

.flexBox {
Expand Down
6 changes: 6 additions & 0 deletions src/renderer/components/ft-icon-button/ft-icon-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export default defineComponent({
type: Array,
default: () => ['fas', 'ellipsis-v']
},
disabled: {
type: Boolean,
default: false
},
theme: {
type: String,
default: 'base'
Expand Down Expand Up @@ -88,6 +92,7 @@ export default defineComponent({
},

handleIconClick: function () {
if (this.disabled) { return }
if (this.forceDropdown || (this.dropdownOptions.length > 0)) {
this.dropdownShown = !this.dropdownShown

Expand All @@ -104,6 +109,7 @@ export default defineComponent({
},

handleIconMouseDown: function () {
if (this.disabled) { return }
if (this.dropdownShown) {
this.mouseDownOnIcon = true
}
Expand Down
6 changes: 6 additions & 0 deletions src/renderer/components/ft-icon-button/ft-icon-button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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%);
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/components/ft-icon-button/ft-icon-button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
:icon="icon"
:class="{
[theme]: true,
shadow: useShadow
shadow: useShadow,
disabled
}"
:style="{
padding: padding + 'px',
Expand Down
55 changes: 6 additions & 49 deletions src/renderer/components/ft-list-video/ft-list-video.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
copyToClipboard,
formatDurationAsTimestamp,
formatNumber,
getRelativeTimeFromDate,
openExternalLink,
showToast,
toDistractionFreeTitle,
Expand Down Expand Up @@ -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
},
Expand Down Expand Up @@ -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
},
Expand Down Expand Up @@ -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)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
tabindex="0"
:title="$t('Close Banner')"
@click.stop="handleClose"
@keydown.enter.stop.prevent="handleClose"
@keydown.enter.space.stop.prevent="handleClose"
/>
</div>
</template>
Expand Down
36 changes: 36 additions & 0 deletions src/renderer/components/ft-refresh-widget/ft-refresh-widget.css
Original file line number Diff line number Diff line change
@@ -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%;
}
}
29 changes: 29 additions & 0 deletions src/renderer/components/ft-refresh-widget/ft-refresh-widget.js
Original file line number Diff line number Diff line change
@@ -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
}
}
})
27 changes: 27 additions & 0 deletions src/renderer/components/ft-refresh-widget/ft-refresh-widget.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<template>
<div
class="floatingRefreshSection"
:class="{
sideNavOpen: isSideNavOpen
}"
>
<p
v-if="lastRefreshTimestamp"
class="lastRefreshTimestamp"
>
{{ $t('Feed.Feed Last Updated', { feedName: title, date: lastRefreshTimestamp }) }}
</p>
<ft-icon-button
:disabled="disableRefresh"
:icon="['fas', 'sync']"
class="refreshButton"
:title="$t('Feed.Refresh Feed', { subscriptionName: title })"
:size="12"
theme="primary"
@click="$emit('click')"
/>
</div>
</template>

<script src="./ft-refresh-widget.js" />
<style scoped src="./ft-refresh-widget.css" />
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { defineComponent } from 'vue'
import { mapActions, mapMutations } from 'vuex'
import SubscriptionsTabUI from '../subscriptions-tab-ui/subscriptions-tab-ui.vue'

import { calculatePublishedDate, copyToClipboard, showToast } from '../../helpers/utils'
import { calculatePublishedDate, copyToClipboard, getRelativeTimeFromDate, showToast } from '../../helpers/utils'
import { getLocalChannelCommunity } from '../../helpers/api/local'
import { invidiousGetCommunityPosts } from '../../helpers/api/invidious'

Expand Down Expand Up @@ -49,6 +49,11 @@ export default defineComponent({
})
return entries
},

lastCommunityRefreshTimestamp: function () {
return getRelativeTimeFromDate(this.$store.getters.getLastCommunityRefreshTimestampByProfile(this.activeProfileId), true)
},

postCacheForAllActiveProfileChannelsPresent() {
if (this.cacheEntriesForAllActiveProfileChannels.length === 0) { return false }
if (this.cacheEntriesForAllActiveProfileChannels.length < this.activeSubscriptionList.length) { return false }
Expand All @@ -69,22 +74,33 @@ export default defineComponent({
watch: {
activeProfile: async function (_) {
this.isLoading = true
this.loadpostsFromCacheSometimes()
this.loadPostsFromCacheSometimes()
},
},
mounted: async function () {
this.isLoading = true

this.loadpostsFromCacheSometimes()
this.loadPostsFromCacheSometimes()
},
methods: {
loadpostsFromCacheSometimes() {
loadPostsFromCacheSometimes() {
// This method is called on view visible
if (this.postCacheForAllActiveProfileChannelsPresent) {
this.loadPostsFromCacheForAllActiveProfileChannels()
if (this.cacheEntriesForAllActiveProfileChannels.length > 0) {
let minTimestamp = null
this.cacheEntriesForAllActiveProfileChannels.forEach((cacheEntry) => {
if (!minTimestamp || cacheEntry.timestamp.getTime() < minTimestamp.getTime()) {
minTimestamp = cacheEntry.timestamp
}
})
this.updateLastCommunityRefreshTimestampByProfile({ profileId: this.activeProfileId, timestamp: minTimestamp })
}
return
}

// clear timestamp if not all entries are present in the cache
this.updateLastCommunityRefreshTimestampByProfile({ profileId: this.activeProfileId, timestamp: '' })
this.maybeLoadPostsForSubscriptionsFromRemote()
},

Expand Down Expand Up @@ -137,7 +153,7 @@ export default defineComponent({

this.updateSubscriptionPostsCacheByChannel({
channelId: channel.id,
posts: posts,
posts: posts
})

if (posts.length > 0) {
Expand Down Expand Up @@ -168,6 +184,7 @@ export default defineComponent({
return posts
}))).flatMap((o) => o)
postList.push(...postListFromRemote)
this.updateLastCommunityRefreshTimestampByProfile({ profileId: this.activeProfileId, timestamp: new Date() })
postList.sort((a, b) => {
return calculatePublishedDate(b.publishedText) - calculatePublishedDate(a.publishedText)
})
Expand Down Expand Up @@ -243,6 +260,7 @@ export default defineComponent({
'updateShowProgressBar',
'batchUpdateSubscriptionDetails',
'updateSubscriptionPostsCacheByChannel',
'updateLastCommunityRefreshTimestampByProfile'
]),

...mapMutations([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
:attempted-fetch="attemptedFetch"
:is-community="true"
:initial-data-limit="20"
:last-refresh-timestamp="lastCommunityRefreshTimestamp"
:title="$t('Global.Community')"
@refresh="loadPostsForSubscriptionsFromRemote"
/>
</template>
Expand Down
Loading

0 comments on commit ab3c1b9

Please sign in to comment.