Migrate Popular view to composition API (#6129)

* Migrate Popular to composition API

* remove comment, use shallowRef for shownResults

Co-Authored-By: absidue <48293849+absidue@users.noreply.github.com>

* Optimize setting shownResults

Co-Authored-By: absidue <48293849+absidue@users.noreply.github.com>

* Fix typo

Co-authored-by: absidue <48293849+absidue@users.noreply.github.com>

---------

Co-authored-by: absidue <48293849+absidue@users.noreply.github.com>
This commit is contained in:
ChunkyProgrammer 2024-11-14 19:28:38 -05:00 committed by GitHub
parent 006ed4050f
commit 8ab8b4ed7f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 97 additions and 109 deletions

View File

@ -1,108 +0,0 @@
import { defineComponent } from 'vue'
import { mapMutations } from 'vuex'
import FtLoader from '../../components/ft-loader/ft-loader.vue'
import FtCard from '../../components/ft-card/ft-card.vue'
import FtElementList from '../../components/FtElementList/FtElementList.vue'
import FtIconButton from '../../components/ft-icon-button/ft-icon-button.vue'
import FtRefreshWidget from '../../components/ft-refresh-widget/ft-refresh-widget.vue'
import { invidiousAPICall } from '../../helpers/api/invidious'
import { copyToClipboard, getRelativeTimeFromDate, setPublishedTimestampsInvidious, showToast } from '../../helpers/utils'
export default defineComponent({
name: 'Popular',
components: {
'ft-loader': FtLoader,
'ft-card': FtCard,
'ft-element-list': FtElementList,
'ft-icon-button': FtIconButton,
'ft-refresh-widget': FtRefreshWidget,
},
data: function () {
return {
isLoading: false,
shownResults: []
}
},
computed: {
lastPopularRefreshTimestamp: function () {
return getRelativeTimeFromDate(this.$store.getters.getLastPopularRefreshTimestamp, true)
},
popularCache: function () {
return this.$store.getters.getPopularCache
}
},
mounted: function () {
document.addEventListener('keydown', this.keyboardShortcutHandler)
this.shownResults = this.popularCache || []
if (!this.shownResults || this.shownResults.length < 1) {
this.fetchPopularInfo()
}
},
beforeDestroy: function () {
document.removeEventListener('keydown', this.keyboardShortcutHandler)
},
methods: {
fetchPopularInfo: async function () {
const searchPayload = {
resource: 'popular',
id: '',
params: {}
}
this.isLoading = true
const result = await invidiousAPICall(searchPayload)
.catch((err) => {
const errorMessage = this.$t('Invidious API Error (Click to copy)')
showToast(`${errorMessage}: ${err}`, 10000, () => {
copyToClipboard(err)
})
return undefined
})
if (!result) {
this.isLoading = false
return
}
const items = result.filter((item) => {
return item.type === 'video' || item.type === 'shortVideo' || item.type === 'channel' || item.type === 'playlist'
})
setPublishedTimestampsInvidious(items.filter(item => item.type === 'video' || item.type === 'shortVideo'))
this.setLastPopularRefreshTimestamp(new Date())
this.shownResults = items
this.isLoading = false
this.$store.commit('setPopularCache', items)
},
/**
* This function `keyboardShortcutHandler` should always be at the bottom of this file
* @param {KeyboardEvent} event the keyboard event
*/
keyboardShortcutHandler: function (event) {
if (event.ctrlKey || document.activeElement.classList.contains('ft-input')) {
return
}
// Avoid handling events due to user holding a key (not released)
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat
if (event.repeat) { return }
switch (event.key) {
case 'r':
case 'R':
case 'F5':
if (!this.isLoading) {
this.fetchPopularInfo()
}
break
}
},
...mapMutations([
'setLastPopularRefreshTimestamp'
])
}
})

View File

@ -22,5 +22,101 @@
</div>
</template>
<script src="./Popular.js" />
<script setup>
import { computed, onBeforeUnmount, onMounted, ref, shallowRef } from 'vue'
import FtLoader from '../../components/ft-loader/ft-loader.vue'
import FtCard from '../../components/ft-card/ft-card.vue'
import FtElementList from '../../components/FtElementList/FtElementList.vue'
import FtRefreshWidget from '../../components/ft-refresh-widget/ft-refresh-widget.vue'
import store from '../../store/index'
import { invidiousAPICall } from '../../helpers/api/invidious'
import { copyToClipboard, getRelativeTimeFromDate, setPublishedTimestampsInvidious, showToast } from '../../helpers/utils'
import { useI18n } from '../../composables/use-i18n-polyfill'
const { t } = useI18n()
const isLoading = ref(false)
const lastPopularRefreshTimestamp = computed(() => {
return getRelativeTimeFromDate(store.getters.getLastPopularRefreshTimestamp, true)
})
/** @type {import('vue').ComputedRef<Array | null>} */
const popularCache = computed(() => {
return store.getters.getPopularCache
})
const shownResults = shallowRef(popularCache.value || [])
onMounted(() => {
document.addEventListener('keydown', keyboardShortcutHandler)
if (shownResults.value.length === 0) {
fetchPopularInfo()
}
})
onBeforeUnmount(() => {
document.removeEventListener('keydown', keyboardShortcutHandler)
})
async function fetchPopularInfo() {
const searchPayload = {
resource: 'popular',
id: '',
params: {}
}
isLoading.value = true
const result = await invidiousAPICall(searchPayload)
.catch((err) => {
const errorMessage = t('Invidious API Error (Click to copy)')
showToast(`${errorMessage}: ${err}`, 10000, () => {
copyToClipboard(err)
})
return undefined
})
if (!result) {
isLoading.value = false
return
}
const items = result.filter((item) => {
return item.type === 'video' || item.type === 'shortVideo' || item.type === 'channel' || item.type === 'playlist'
})
setPublishedTimestampsInvidious(items.filter(item => item.type === 'video' || item.type === 'shortVideo'))
store.commit('setLastPopularRefreshTimestamp', new Date())
shownResults.value = items
isLoading.value = false
store.commit('setPopularCache', items)
}
/**
* @param {KeyboardEvent} event the keyboard event
*/
function keyboardShortcutHandler(event) {
if (event.ctrlKey || document.activeElement.classList.contains('ft-input')) {
return
}
// Avoid handling events due to user holding a key (not released)
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat
if (event.repeat) { return }
switch (event.key) {
case 'r':
case 'R':
case 'F5':
if (!isLoading.value) {
fetchPopularInfo()
}
break
}
}
</script>
<style scoped src="./Popular.css" />