Skip to content

Commit

Permalink
Merge pull request #3187 from owncloud/filelist-previews
Browse files Browse the repository at this point in the history
Added file previews
  • Loading branch information
individual-it authored Mar 26, 2020
2 parents d8f4584 + 8eeae76 commit 1a34c63
Show file tree
Hide file tree
Showing 22 changed files with 410 additions and 41 deletions.
40 changes: 29 additions & 11 deletions apps/files/src/components/AllFilesList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,13 @@
<oc-star class="uk-display-block" @click.native.stop="toggleFileFavorite(item)" :shining="item.starred" />
</div>
<div class="uk-text-truncate uk-width-expand" :ref="index === 0 ? 'firstRowNameColumn' : null">
<oc-file @click.native.stop="item.type === 'folder' ? navigateTo(item.path.substr(1)) : openFileActionBar(item)"
:name="$_ocFileName(item)" :extension="item.extension" class="file-row-name" :icon="fileTypeIcon(item)"
:filename="item.name" :key="item.id"/>
<file-item
@click.native.stop="item.type === 'folder' ? navigateTo(item.path.substr(1)) : openFileActionBar(item)"
:item="item"
:dav-url="davUrl"
:show-path="$_isFavoritesList"
class="file-row-name"
:key="item.viewId"/>
<oc-spinner
v-if="actionInProgress(item)"
size="small"
Expand Down Expand Up @@ -112,6 +116,7 @@
<script>
import FileList from './FileList.vue'
import Indicators from './FilesLists/Indicators.vue'
import FileItem from './FileItem.vue'
import NoContentMessage from './NoContentMessage.vue'
import { mapGetters, mapActions, mapState } from 'vuex'
Expand All @@ -127,6 +132,7 @@ export default {
components: {
FileList,
Indicators,
FileItem,
NoContentMessage,
SortableColumnHeader
},
Expand Down Expand Up @@ -188,6 +194,26 @@ export default {
return Object.keys(shareTypes).map(shareType => parseInt(shareType, 10))
},
davUrl () {
let davUrl
// FIXME: use SDK once it switches to DAV v2
if (this.publicPage()) {
davUrl = [
'..',
'dav',
'public-files'
].join('/')
} else {
davUrl = [
'..',
'dav',
'files',
this.$store.getters.user.id
].join('/')
}
return this.$client.files.getFileUrl(davUrl)
},
$_isFavoritesList () {
return (this.$route.name === 'files-favorites')
},
Expand Down Expand Up @@ -269,14 +295,6 @@ export default {
file: item
})
},
$_ocFileName (item) {
if (this.$_isFavoritesList) {
const pathSplit = item.path.substr(1).split('/')
if (pathSplit.length === 2) return `${pathSplit[pathSplit.length - 2]}/${item.basename}`
if (pathSplit.length > 2) return `…/${pathSplit[pathSplit.length - 2]}/${item.basename}`
}
return item.basename
},
isActionEnabled (item, action) {
return action.isEnabled(item, this.parentFolder)
Expand Down
23 changes: 20 additions & 3 deletions apps/files/src/components/Collaborators/SharedFilesList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@
</template>
<template #rowColumns="{ item }">
<div class="uk-text-truncate uk-width-expand">
<oc-file @click.native.stop="item.type === 'folder' ? navigateTo(item.path.substr(1)) : openFileActionBar(item)"
:name="item.basename" :extension="item.extension" class="file-row-name" :icon="fileTypeIcon(item)"
:filename="item.name" :key="item.path" />
<file-item
@click.native.stop="item.type === 'folder' ? navigateTo(item.path.substr(1)) : openFileActionBar(item)"
:item="item"
:dav-url="davUrl"
class="file-row-name"
:key="item.path" />
<oc-spinner
v-if="actionInProgress(item)"
size="small"
Expand Down Expand Up @@ -110,6 +113,7 @@ import { mapGetters, mapActions } from 'vuex'
import Mixins from '../../mixins'
import FileActions from '../../fileactions'
import FileList from '../FileList.vue'
import FileItem from '../FileItem.vue'
import NoContentMessage from '../NoContentMessage.vue'
import SortableColumnHeader from '../FilesLists/SortableColumnHeader.vue'
import { shareTypes } from '../../helpers/shareTypes'
Expand All @@ -119,6 +123,7 @@ export default {
name: 'SharedFilesList',
components: {
FileList,
FileItem,
NoContentMessage,
SortableColumnHeader
},
Expand All @@ -145,7 +150,19 @@ export default {
$_isSharedWithMe () {
return (this.$route.name === 'files-shared-with-me')
},
davUrl () {
// FIXME: use SDK once it switches to DAV v2
const davUrl = [
'..',
'dav',
'files',
this.$store.getters.user.id
].join('/')
return this.$client.files.getFileUrl(davUrl)
}
},
watch: {
$route () {
Expand Down
111 changes: 111 additions & 0 deletions apps/files/src/components/FileItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<template>
<oc-file
:name="fileName"
:extension="item.extension"
:icon="previewIcon"
:iconUrl="previewUrl"
:filename="item.name"
:data-preview-loaded="previewLoaded"
/>
</template>
<script>
import queryString from 'query-string'
import Mixins from '../mixins'
export default {
name: 'FileItem',
mixins: [
Mixins
],
props: {
item: {
type: Object
},
// override for file name
name: {
type: String
},
davUrl: {
type: String
},
showPath: {
type: Boolean,
default: false
}
},
data: function () {
return {
previewUrl: this.item.previewUrl,
// 'false' while the preview is loading (needs string for Vue.js to render the attribute)
// true when the preview loading process is done,
// even if we fell back to the mime type icon
previewLoaded: 'false'
}
},
computed: {
fileName () {
if (this.name) {
return this.name
}
if (this.showPath) {
const pathSplit = this.item.path.substr(1).split('/')
if (pathSplit.length === 2) return `${pathSplit[pathSplit.length - 2]}/${this.item.basename}`
if (pathSplit.length > 2) return `…/${pathSplit[pathSplit.length - 2]}/${this.item.basename}`
}
return this.item.basename
},
previewIcon () {
return this.fileTypeIcon(this.item)
}
},
mounted () {
this.loadPreview()
},
methods: {
loadPreview () {
if (this.item.previewUrl) {
this.previewUrl = this.item.previewUrl
this.previewLoaded = true
return
}
// TODO: check if previews are globally enabled (requires capability entry)
// don't load previews for pending or rejected shares (status)
if (!this.davUrl || this.item.type === 'folder' || (typeof this.item.status !== 'undefined' && this.item.status !== 0)) {
this.previewLoaded = true
return
}
const query = {
x: this.thumbDimensions,
y: this.thumbDimensions,
scalingup: 0,
preview: 1,
a: 1
}
if (this.item.etag) {
// add etag for URL based caching
// strip double quotes from etag
query.c = this.item.etag.substr(2, this.item.etag.length - 2)
}
let itemPath = this.item.path
if (itemPath.charAt(0) === '/') {
itemPath = itemPath.substr(1)
}
const previewUrl = this.davUrl + '/' + this.encodePath(itemPath) + '?' + queryString.stringify(query)
this.mediaSource(previewUrl, 'url', this.requestHeaders).then(dataUrl => {
// cache inside item
this.previewUrl = this.item.previewUrl = dataUrl
this.previewLoaded = true
}).catch((e) => {
this.previewUrl = null
this.previewLoaded = true
})
}
}
}
</script>
11 changes: 8 additions & 3 deletions apps/files/src/components/Trashbin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@
</template>
<template #rowColumns="{ item }">
<div class="uk-text-truncate uk-width-expand">
<oc-file
:name="$_ocTrashbin_fileName(item)" :extension="item.extension" class="file-row-name" :icon="fileTypeIcon(item)"
:filename="item.name" :key="item.id"/>
<file-item
:item="item"
:name="$_ocTrashbin_fileName(item)"
class="file-row-name"
:key="item.viewId"
/>
</div>
<div class="uk-text-meta uk-text-nowrap uk-width-small uk-text-right" :class="{ 'uk-visible@s' : !_sidebarOpen, 'uk-hidden' : _sidebarOpen }">
{{ formDateFromNow(item.deleteTimestamp) }}
Expand All @@ -58,6 +61,7 @@
import { mapGetters, mapActions } from 'vuex'
import Mixins from '../mixins'
import FileList from './FileList.vue'
import FileItem from './FileItem.vue'
import NoContentMessage from './NoContentMessage.vue'
import OcDialogPrompt from './ocDialogPrompt.vue'
import SortableColumnHeader from './FilesLists/SortableColumnHeader.vue'
Expand All @@ -69,6 +73,7 @@ export default {
components: {
OcDialogPrompt,
FileList,
FileItem,
NoContentMessage,
SortableColumnHeader
},
Expand Down
15 changes: 15 additions & 0 deletions apps/files/src/mixins.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,21 @@ export default {

_sidebarOpen () {
return this.highlightedFile !== null
},

requestHeaders () {
if (!this.publicPage()) {
return null
}

const headers = new Headers()
headers.append('X-Requested-With', 'XMLHttpRequest')

const password = this.publicLinkPassword
if (password) {
headers.append('Authorization', 'Basic ' + Buffer.from('public:' + password).toString('base64'))
}
return headers
}
},
methods: {
Expand Down
6 changes: 6 additions & 0 deletions apps/files/src/store/mutations.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,12 @@ export default {

CLEAR_CURRENT_FILES_LIST (state) {
state.currentFolder = null
// release blob urls
state.files.forEach(item => {
if (item.previewUrl && item.previewUrl.startsWith('blob:')) {
window.URL.revokeObjectURL(item.previewUrl)
}
})
state.files = []
}
}
3 changes: 2 additions & 1 deletion apps/media-viewer/src/Mediaviewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ export default {
const query = queryString.stringify({
x: this.thumbDimensions,
y: this.thumbDimensions,
c: this.activeMediaFile.etag,
// strip double quotes from etag
c: this.activeMediaFile.etag.substr(1, this.activeMediaFile.etag.length - 2),
scalingup: 0,
preview: 1,
a: 1
Expand Down
7 changes: 7 additions & 0 deletions changelog/unreleased/276
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Enhancement: Added thumbnails in file list

Thumbnails are now displayed in the file list for known file types.
When no thumbnail was returned, fall back to the file type icon.

https://github.com/owncloud/phoenix/issues/276
https://github.com/owncloud/phoenix/pull/3187
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"owncloud-design-system": "^1.1.1",
"owncloud-sdk": "^1.0.0-523",
"p-limit": "^2.2.1",
"p-queue": "^6.1.1",
"parse-json": "^5.0.0",
"path": "^0.12.7",
"requirejs": "^2.3.6",
Expand Down
12 changes: 11 additions & 1 deletion src/plugins/mediaSource.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import store from '../store'
const { default: PQueue } = require('p-queue')

export default {
install (Vue) {
Expand All @@ -11,6 +12,10 @@ export default {
headers.append('X-Requested-With', 'XMLHttpRequest')

fetch(source, { headers }).then(response => {
if (!response.ok) {
reject(response)
return
}
response.blob().then(blob => {
if (returnAs === 'base64') {
const reader = new FileReader()
Expand Down Expand Up @@ -44,9 +49,14 @@ export default {
})

Vue.mixin({
data: function () {
return {
mediaSourceQueue: new PQueue({ concurrency: 2 })
}
},
methods: {
mediaSource (source, returnAs = 'url', headers = null) {
return _mediaSource(source, returnAs, headers)
return this.mediaSourceQueue.add(() => _mediaSource(source, returnAs, headers))
}
}
})
Expand Down
13 changes: 13 additions & 0 deletions src/plugins/phoenix.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@ export default {
*/
isIE11 () {
return !!window.MSInputMethodContext && !!document.documentMode
},
/**
* URI-Encodes a file path but keep the path slashes.
*
* @param path path
* @return encoded path
*/
encodePath: function (path) {
if (!path) {
return path
}
var parts = path.split('/').map(part => encodeURIComponent(part))
return parts.join('/')
}
}
})
Expand Down
Loading

0 comments on commit 1a34c63

Please sign in to comment.