Skip to content

Commit

Permalink
web/satellite: Show video thumbnail in gallery view
Browse files Browse the repository at this point in the history
video thumbnail is visible in the gallery card layout, with "video" icon overlaid.
when video card is clicked, the full screen preview opens and autoplays.

Issue:
#6856

Change-Id: Ib441c310ae4146773b824951cd9f34d7ebaaaa90
  • Loading branch information
VitaliiShpital committed Mar 29, 2024
1 parent 491175c commit 2802708
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 21 deletions.
2 changes: 1 addition & 1 deletion web/satellite/src/App.vue
Expand Up @@ -198,7 +198,7 @@ watch(() => projectsStore.state.selectedProject, (project, oldProject) => {
if (usersStore.getShouldPromptPassphrase({
isProjectOwner: project.ownerId === usersStore.state.user.id,
onboardingStepperEnabled: configStore.state.config.onboardingStepperEnabled,
}) && !user.value.freezeStatus.trialExpiredFrozen) {
}) && !user.value.freezeStatus.trialExpiredFrozen && route.name !== ROUTES.Bucket.name) {
appStore.toggleProjectPassphraseDialog(true);
}
});
Expand Down
4 changes: 2 additions & 2 deletions web/satellite/src/components/BrowserCardViewComponent.vue
Expand Up @@ -148,7 +148,7 @@
</v-card>
</template>
</v-data-iterator>
<file-preview-dialog v-model="previewDialog" />
<file-preview-dialog v-model="previewDialog" video-autoplay />

<delete-file-dialog
v-model="isDeleteFileDialogShown"
Expand Down Expand Up @@ -543,7 +543,7 @@ async function processFilePath(file: BrowserObjectWrapper) {
* Adds image files to preview queue.
*/
function addToPreviewQueue(file: BrowserObjectWrapper) {
if (file.browserObject.type === 'folder' || file.typeInfo.title !== 'Image') return;
if (file.browserObject.type === 'folder' || (file.typeInfo.title !== 'Image' && file.typeInfo.title !== 'Video')) return;
previewQueue.push(file);
if (!processingPreview) {
Expand Down
62 changes: 47 additions & 15 deletions web/satellite/src/components/FileCard.vue
Expand Up @@ -10,14 +10,32 @@
:src="objectPreviewUrl"
class="bg-light card-preview-img h-100"
alt="preview"
:aspect-ratio="1/1"
:aspect-ratio="1"
cover
>
<template #placeholder>
<v-progress-linear indeterminate />
</template>
</v-img>
</template>
<template v-else-if="previewType === PreviewType.Video">
<div class="pos-relative">
<video
ref="videoEl"
:src="objectPreviewUrl"
class="bg-light h-100 custom-video"
muted
@loadedmetadata="captureVideoFrame"
/>
<img
class="absolute"
:src="item.typeInfo.icon"
:alt="item.typeInfo.title + 'icon'"
:aria-roledescription="item.typeInfo.title + 'icon'"
height="52"
>
</div>
</template>
<div
v-else
class="d-flex h-100 bg-light flex-column justify-center align-center file-icon-container card-preview-icon"
Expand Down Expand Up @@ -46,9 +64,6 @@
{{ item.browserObject.Key }}
</small>
</v-card-title>
<!-- <v-card-subtitle class="text-caption">
{{ item.browserObject.type === 'folder' ? '&nbsp;': getFormattedSize(item.browserObject) }}
</v-card-subtitle> -->
<v-card-subtitle class="text-caption">
{{ item.browserObject.type === 'folder' ? '&nbsp;': getFormattedDate(item.browserObject) }}
</v-card-subtitle>
Expand All @@ -58,13 +73,9 @@
</template>

<script setup lang="ts">
import { useRouter } from 'vue-router';
import { computed, ref } from 'vue';
import { VCard, VCardItem, VCardSubtitle, VCardTitle, VImg, VProgressLinear } from 'vuetify/components';
import { computed } from 'vue';
import { useProjectsStore } from '@/store/modules/projectsStore';
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
import { useNotify } from '@/utils/hooks';
import { BrowserObject, PreviewCache, useObjectBrowserStore } from '@/store/modules/objectBrowserStore';
import { useBucketsStore } from '@/store/modules/bucketsStore';
import { EXTENSION_PREVIEW_TYPES, PreviewType } from '@/types/browser';
Expand All @@ -83,14 +94,9 @@ type BrowserObjectWrapper = {
ext: string;
};
const analyticsStore = useAnalyticsStore();
const projectsStore = useProjectsStore();
const bucketsStore = useBucketsStore();
const obStore = useObjectBrowserStore();
const router = useRouter();
const notify = useNotify();
const props = defineProps<{
item: BrowserObjectWrapper,
}>();
Expand All @@ -101,6 +107,8 @@ const emit = defineEmits<{
shareClick: [BrowserObject];
}>();
const videoEl = ref<HTMLVideoElement>();
/**
* Returns object preview URL from cache.
*/
Expand Down Expand Up @@ -147,11 +155,35 @@ const previewType = computed<PreviewType>(() => {
return PreviewType.None;
});
/**
* Updates current video time to show video thumbnail.
*/
function captureVideoFrame(): void {
if (videoEl.value) videoEl.value.currentTime = 0;
}
/**
* Returns the string form of the file's last modified date.
*/
function getFormattedDate(file: BrowserObject): string {
const date = file.LastModified;
return date.toLocaleDateString('en-GB', { day: 'numeric', month: 'short', year: 'numeric' });
}
</script>
</script>

<style scoped lang="scss">
.custom-video {
max-width: 100%;
max-height: 100%;
aspect-ratio: 1;
object-fit: cover;
}
.absolute {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1;
}
</style>
8 changes: 7 additions & 1 deletion web/satellite/src/components/dialogs/FilePreviewDialog.vue
Expand Up @@ -120,7 +120,7 @@
<!-- v-carousel will mount all items at the same time -->
<!-- so :active will tell file-preview-item if it is the current. -->
<!-- If it is, it'll load the preview. -->
<file-preview-item :active="i === fileIndex" :file="file" @download="download" />
<file-preview-item :active="i === fileIndex" :file="file" :video-autoplay="videoAutoplay" @download="download" />
</v-carousel-item>
</v-carousel>
</v-card>
Expand Down Expand Up @@ -172,6 +172,12 @@ const obStore = useObjectBrowserStore();
const bucketsStore = useBucketsStore();
const notify = useNotify();
withDefaults(defineProps<{
videoAutoplay?: boolean
}>(), {
videoAutoplay: false,
});
const carousel = ref<VCarousel | null>(null);
const isDownloading = ref<boolean>(false);
const isShareDialogShown = ref<boolean>(false);
Expand Down
Expand Up @@ -17,6 +17,8 @@
:src="objectPreviewUrl"
style="max-width: 100%; max-height: 90%;"
aria-roledescription="video-preview"
:autoplay="videoAutoplay"
:muted="videoAutoplay"
/>
</v-container>
<v-container v-else-if="previewType === PreviewType.Audio" class="fill-height flex-column justify-center align-center">
Expand Down Expand Up @@ -71,10 +73,13 @@ const { generateObjectPreviewAndMapURL } = useLinksharing();
const isLoading = ref<boolean>(false);
const previewAndMapFailed = ref<boolean>(false);
const props = defineProps<{
const props = withDefaults(defineProps<{
file: BrowserObject,
active: boolean, // whether this item is visible
}>();
videoAutoplay?: boolean
}>(), {
videoAutoplay: false,
});
const emit = defineEmits<{
download: [];
Expand Down

0 comments on commit 2802708

Please sign in to comment.