mirror of
https://github.com/nextcloud/server.git
synced 2026-03-09 09:51:03 -04:00
232 lines
5.5 KiB
Vue
232 lines
5.5 KiB
Vue
<!--
|
|
- SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
|
- SPDX-License-Identifier: AGPL-3.0-or-later
|
|
-->
|
|
<template>
|
|
<span class="files-list__row-icon">
|
|
<template v-if="source.type === 'folder'">
|
|
<FolderOpenIcon v-if="dragover" v-once />
|
|
<template v-else>
|
|
<FolderIcon v-once />
|
|
<OverlayIcon :is="folderOverlay"
|
|
v-if="folderOverlay"
|
|
class="files-list__row-icon-overlay" />
|
|
</template>
|
|
</template>
|
|
|
|
<!-- Decorative image, should not be aria documented -->
|
|
<img v-else-if="previewUrl && backgroundFailed !== true"
|
|
ref="previewImg"
|
|
alt=""
|
|
class="files-list__row-icon-preview"
|
|
:class="{'files-list__row-icon-preview--loaded': backgroundFailed === false}"
|
|
loading="lazy"
|
|
:src="previewUrl"
|
|
@error="onBackgroundError"
|
|
@load="backgroundFailed = false">
|
|
|
|
<FileIcon v-else v-once />
|
|
|
|
<!-- Favorite icon -->
|
|
<span v-if="isFavorite" class="files-list__row-icon-favorite">
|
|
<FavoriteIcon v-once />
|
|
</span>
|
|
|
|
<OverlayIcon :is="fileOverlay"
|
|
v-if="fileOverlay"
|
|
class="files-list__row-icon-overlay files-list__row-icon-overlay--file" />
|
|
</span>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import type { PropType } from 'vue'
|
|
import type { UserConfig } from '../../types.ts'
|
|
|
|
import { Node, FileType } from '@nextcloud/files'
|
|
import { generateUrl } from '@nextcloud/router'
|
|
import { translate as t } from '@nextcloud/l10n'
|
|
import { Type as ShareType } from '@nextcloud/sharing'
|
|
|
|
import Vue from 'vue'
|
|
import AccountGroupIcon from 'vue-material-design-icons/AccountGroup.vue'
|
|
import AccountPlusIcon from 'vue-material-design-icons/AccountPlus.vue'
|
|
import FileIcon from 'vue-material-design-icons/File.vue'
|
|
import FolderIcon from 'vue-material-design-icons/Folder.vue'
|
|
import FolderOpenIcon from 'vue-material-design-icons/FolderOpen.vue'
|
|
import KeyIcon from 'vue-material-design-icons/Key.vue'
|
|
import LinkIcon from 'vue-material-design-icons/Link.vue'
|
|
import NetworkIcon from 'vue-material-design-icons/Network.vue'
|
|
import TagIcon from 'vue-material-design-icons/Tag.vue'
|
|
import PlayCircleIcon from 'vue-material-design-icons/PlayCircle.vue'
|
|
|
|
import CollectivesIcon from './CollectivesIcon.vue'
|
|
import FavoriteIcon from './FavoriteIcon.vue'
|
|
|
|
import { isLivePhoto } from '../../services/LivePhotos'
|
|
import { useUserConfigStore } from '../../store/userconfig.ts'
|
|
|
|
export default Vue.extend({
|
|
name: 'FileEntryPreview',
|
|
|
|
components: {
|
|
AccountGroupIcon,
|
|
AccountPlusIcon,
|
|
CollectivesIcon,
|
|
FavoriteIcon,
|
|
FileIcon,
|
|
FolderIcon,
|
|
FolderOpenIcon,
|
|
KeyIcon,
|
|
LinkIcon,
|
|
NetworkIcon,
|
|
TagIcon,
|
|
},
|
|
|
|
props: {
|
|
source: {
|
|
type: Object as PropType<Node>,
|
|
required: true,
|
|
},
|
|
dragover: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
gridMode: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
},
|
|
|
|
setup() {
|
|
const userConfigStore = useUserConfigStore()
|
|
return {
|
|
userConfigStore,
|
|
}
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
backgroundFailed: undefined as boolean | undefined,
|
|
}
|
|
},
|
|
|
|
computed: {
|
|
fileid() {
|
|
return this.source?.fileid?.toString?.()
|
|
},
|
|
isFavorite(): boolean {
|
|
return this.source.attributes.favorite === 1
|
|
},
|
|
|
|
userConfig(): UserConfig {
|
|
return this.userConfigStore.userConfig
|
|
},
|
|
cropPreviews(): boolean {
|
|
return this.userConfig.crop_image_previews === true
|
|
},
|
|
|
|
previewUrl() {
|
|
if (this.source.type === FileType.Folder) {
|
|
return null
|
|
}
|
|
|
|
if (this.backgroundFailed === true) {
|
|
return null
|
|
}
|
|
|
|
try {
|
|
const previewUrl = this.source.attributes.previewUrl
|
|
|| generateUrl('/core/preview?fileId={fileid}', {
|
|
fileid: this.fileid,
|
|
})
|
|
const url = new URL(window.location.origin + previewUrl)
|
|
|
|
// Request tiny previews
|
|
url.searchParams.set('x', this.gridMode ? '128' : '32')
|
|
url.searchParams.set('y', this.gridMode ? '128' : '32')
|
|
url.searchParams.set('mimeFallback', 'true')
|
|
|
|
// Etag to force refresh preview on change
|
|
const etag = this.source?.attributes?.etag || ''
|
|
url.searchParams.set('v', etag.slice(0, 6))
|
|
|
|
// Handle cropping
|
|
url.searchParams.set('a', this.cropPreviews === true ? '0' : '1')
|
|
return url.href
|
|
} catch (e) {
|
|
return null
|
|
}
|
|
},
|
|
|
|
fileOverlay() {
|
|
if (isLivePhoto(this.source)) {
|
|
return PlayCircleIcon
|
|
}
|
|
|
|
return null
|
|
},
|
|
|
|
folderOverlay() {
|
|
if (this.source.type !== FileType.Folder) {
|
|
return null
|
|
}
|
|
|
|
// Encrypted folders
|
|
if (this.source?.attributes?.['is-encrypted'] === 1) {
|
|
return KeyIcon
|
|
}
|
|
|
|
// System tags
|
|
if (this.source?.attributes?.['is-tag']) {
|
|
return TagIcon
|
|
}
|
|
|
|
// Link and mail shared folders
|
|
const shareTypes = Object.values(this.source?.attributes?.['share-types'] || {}).flat() as number[]
|
|
if (shareTypes.some(type => type === ShareType.SHARE_TYPE_LINK || type === ShareType.SHARE_TYPE_EMAIL)) {
|
|
return LinkIcon
|
|
}
|
|
|
|
// Shared folders
|
|
if (shareTypes.length > 0) {
|
|
return AccountPlusIcon
|
|
}
|
|
|
|
switch (this.source?.attributes?.['mount-type']) {
|
|
case 'external':
|
|
case 'external-session':
|
|
return NetworkIcon
|
|
case 'group':
|
|
return AccountGroupIcon
|
|
case 'collective':
|
|
return CollectivesIcon
|
|
case 'shared':
|
|
return AccountPlusIcon
|
|
}
|
|
|
|
return null
|
|
},
|
|
},
|
|
|
|
methods: {
|
|
// Called from FileEntry
|
|
reset() {
|
|
// Reset background state to cancel any ongoing requests
|
|
this.backgroundFailed = undefined
|
|
if (this.$refs.previewImg) {
|
|
this.$refs.previewImg.src = ''
|
|
}
|
|
},
|
|
|
|
onBackgroundError(event) {
|
|
// Do not fail if we just reset the background
|
|
if (event.target?.src === '') {
|
|
return
|
|
}
|
|
this.backgroundFailed = true
|
|
},
|
|
|
|
t,
|
|
},
|
|
})
|
|
</script>
|