Skip to content

Commit

Permalink
Merge pull request #1530 from owncloud/app/mediaviewer
Browse files Browse the repository at this point in the history
Mediaviewer app
  • Loading branch information
DeepDiver1975 committed Jul 23, 2019
2 parents 0f5ec31 + 0d3c6bb commit ba21594
Show file tree
Hide file tree
Showing 14 changed files with 5,319 additions and 32 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ release/*
**/l10n/template.pot

apps/*
!apps/media-viewer
!apps/files
!apps/markdown-editor
!apps/pdf-viewer
Expand Down
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,15 @@ l10n-push:
cd apps/files/l10n && tx -d push -s --skip --no-interactive
cd apps/markdown-editor/l10n && tx -d push -s --skip --no-interactive
cd apps/pdf-viewer/l10n && tx -d push -s --skip --no-interactive
cd apps/media-viewer/l10n && tx -d push -s --skip --no-interactive

.PHONY: l10n-pull
l10n-pull:
cd l10n && tx -d pull -a --skip
cd apps/files/l10n && tx -d pull -a --skip
cd apps/markdown-editor/l10n && tx -d pull -a --skip
cd apps/pdf-viewer/l10n && tx -d pull -a --skip
cd apps/media-viewer/l10n && tx -d pull -a --skip

.PHONY: l10n-clean
l10n-clean:
Expand Down
10 changes: 10 additions & 0 deletions apps/media-viewer/l10n/.tx/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[main]
host = https://www.transifex.com

[owncloud-phoenix.media-viewer]
file_filter = locale/<lang>/LC_MESSAGES/app.po
minimum_perc = 0
source_file = template.pot
source_lang = en
type = PO

1 change: 1 addition & 0 deletions apps/media-viewer/l10n/translations.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"cs":{},"de":{"of":"von"},"es":{},"fr":{},"gl":{},"it":{}}
39 changes: 39 additions & 0 deletions apps/media-viewer/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "media-viewer",
"version": "1.0.0",
"description": "View images and videos in phoenix",
"main": "index.js",
"scripts": {
"lint": "eslint src/**/*.vue src/**/*.js --color --global requirejs --global require",
"lint-fix": "eslint src/**/*.vue src/**/*.js --color --global requirejs --global require --fix",
"watch": "webpack --progress --colors --watch --mode development --config webpack.dev.js",
"build": "webpack -p --config webpack.common.js"
},
"author": "Felix Heidecke",
"license": "AGPL-3.0",
"devDependencies": {
"@babel/core": "^7.5.4",
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/polyfill": "^7.4.4",
"@babel/preset-env": "^7.5.4",
"babel-eslint": "^10.0.2",
"babel-loader": "^8.0.6",
"babel-runtime": "^6.26.0",
"css-loader": "^3.0.0",
"eslint": "^6.0.1",
"eslint-config-standard": "^13.0.1",
"eslint-loader": "^2.2.1",
"eslint-plugin-import": "^2.18.0",
"eslint-plugin-node": "^9.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^5.2.3",
"query-string": "^6.8.1",
"vue-loader": "^15.7.0",
"vue-template-compiler": "^2.6.10",
"vuex": "3.1.1",
"webpack": "^4.35.3",
"webpack-cli": "^3.3.6",
"webpack-merge": "^4.2.1"
}
}
226 changes: 226 additions & 0 deletions apps/media-viewer/src/Mediaviewer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
<template>
<div id="mediaviewer" class="uk-position-relative">
<div class="uk-position-center uk-padding-small">
<transition name="custom-classes-transition" :enter-active-class="activeClass.enter" :leave-active-class="activeClass.leave">
<img v-show="!loading && activeMediaFileCached" :src="image.url" :alt="image.name" :data-id="image.id" style="max-width:90vw;max-height:90vh" class="uk-box-shadow-medium">
</transition>
</div>
<oc-spinner class="uk-position-center" v-if="loading" size="large" />
<oc-icon v-if="failed" name="review" variation="danger" size="large" class="uk-position-center uk-z-index" />

<div class="uk-position-medium uk-position-bottom-center">
<div class="uk-overlay uk-overlay-default uk-padding-small uk-text-center uk-text-meta uk-text-truncate">{{ image.name }}</div>
<div class="uk-overlay uk-overlay-primary uk-light uk-padding-small">
<div class="uk-width-large uk-flex uk-flex-middle uk-flex-center uk-flex-around" style="user-select:none;">
<oc-icon role="button" class="oc-cursor-pointer" size="medium" @click="prev" name="chevron_left" />
<!-- @TODO: Bring back working uk-light -->
<span class="uk-text-small" style="color:#fff"> {{ activeIndex + 1 }} <span v-translate>of</span> {{ mediaFiles.length }} </span>
<oc-icon role="button" class="oc-cursor-pointer" size="medium" @click="next" name="chevron_right" />
<oc-icon role="button" class="oc-cursor-pointer" @click="downloadFile" name="file_download" />
<oc-icon role="button" class="oc-cursor-pointer" @click="closeApp" name="close"/>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import queryString from 'query-string'
export default {
name: 'Mediaviewer',
data () {
return {
loading: true,
failed: false,
activeIndex: null,
direction: 'rtl',
image: {},
images: [],
// Milliseconds
animationDuration: 1000
}
},
watch: {
activeIndex (o, n) {
if (o !== n) {
this.loadImage()
}
}
},
methods: {
loadImage () {
this.loading = true
// Don't bother loading if files i chached
if (this.activeMediaFileCached) {
setTimeout(() => {
this.image = this.activeMediaFileCached
this.loading = false
},
// Delay to animate
this.animationDuration / 2)
return
}
// Fetch image
this.mediaSource(this.thumbPath).then(imageUrl => {
this.images.push({
id: this.activeMediaFile.id,
name: this.activeMediaFile.name,
url: imageUrl
})
this.image = this.activeMediaFileCached
this.loading = false
this.failed = false
}).catch(e => {
this.loading = false
this.failed = true
})
},
downloadFile () {
if (this.loading) { return }
const file = this.mediaFiles[this.activeIndex]
const url = this.$client.files.getFileUrl(file.path)
const anchor = document.createElement('a')
const headers = new Headers()
headers.append('Authorization', 'Bearer ' + this.getToken)
fetch(url, { headers })
.then(response => response.blob())
.then(blobby => {
if (window.navigator && window.navigator.msSaveOrOpenBlob) { // for IE
window.navigator.msSaveOrOpenBlob(blobby, file.name)
} else { // for Non-IE (chrome, firefox etc.)
const objectUrl = window.URL.createObjectURL(blobby)
anchor.href = objectUrl
anchor.download = file.name
anchor.click()
window.URL.revokeObjectURL(objectUrl)
}
})
.catch(error => console.log(error))
},
next () {
if (this.loading) { return }
this.direction = 'rtl'
if ((this.activeIndex + 1) >= this.mediaFiles.length) {
this.activeIndex = 0
return
}
this.activeIndex++
},
prev () {
if (this.loading) { return }
this.direction = 'ltr'
if (this.activeIndex === 0) {
this.activeIndex = this.mediaFiles.length - 1
return
}
this.activeIndex--
},
handleKeyPress (e) {
if (!e) return false
else if (e.key === 'ArrowRight') this.next()
else if (e.key === 'ArrowLeft') this.prev()
},
closeApp () {
this.$router.go(-1)
}
},
mounted () {
document.addEventListener('keyup', this.handleKeyPress)
// Return if no Image is selected
if (this.$store.getters.activeFile.path === '') {
this.$router.push({
path: '/files'
})
return
}
// Set initial file
for (let i = 0; i < this.mediaFiles.length; i++) {
if (this.mediaFiles[i].path === this.$store.getters.activeFile.path) {
this.activeIndex = i
break
}
}
},
beforeDestroy () {
document.removeEventListener('keyup', this.handleKeyPress)
this.images.forEach(image => {
window.URL.revokeObjectURL(image.url)
})
},
computed: {
...mapGetters('Files', ['activeFiles']),
mediaFiles () {
return this.activeFiles.filter(file => {
return file.extension.toLowerCase().match(/(png|jpg|jpeg|gif)/)
})
},
activeMediaFile () {
return this.mediaFiles[this.activeIndex]
},
activeMediaFileCached () {
const cached = this.images.find(i => i.id === this.activeMediaFile.id)
return (cached !== undefined) ? cached : false
},
activeClass () {
const direction = ['right', 'left']
if (this.direction === 'ltr') { direction.reverse() }
return {
enter: `uk-animation-slide-${direction[0]}-small`,
leave: `uk-animation-slide-${direction[1]}-medium uk-animation-reverse`
}
},
thumbDimensions () {
switch (true) {
case (window.innerWidth <= 1024) : return 1024
case (window.innerWidth <= 1280) : return 1280
case (window.innerWidth <= 1920) : return 1920
case (window.innerWidth <= 2160) : return 2160
default: return 3840
}
},
thumbPath () {
const path = [
'..',
'dav',
'files',
this.$store.getters.user.id,
this.activeMediaFile.path
].join('/')
const query = queryString.stringify({
x: this.thumbDimensions,
y: this.thumbDimensions,
c: this.activeMediaFile.etag,
scalingup: 0,
preview: 1,
a: 1
})
return this.$client.files.getFileUrl(path) + '?' + query
}
}
}
</script>
34 changes: 34 additions & 0 deletions apps/media-viewer/src/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import '@babel/polyfill'
import translationsJson from '../l10n/translations'

import Mediaviewer from './Mediaviewer.vue'

const routes = [{
path: `/mediaviewer`,
components: {
app: Mediaviewer
},
name: 'mediaviewer'
}]

const appInfo = {
name: 'Mediaviewer',
id: 'mediaviewer',
icon: 'image',
extensions: [{
extension: 'png'
}, {
extension: 'jpg'
}, {
extension: 'jpeg'
}, {
extension: 'gif'
}]
}

const translations = translationsJson
export default define({
appInfo,
routes,
translations
})
43 changes: 43 additions & 0 deletions apps/media-viewer/webpack.common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
plugins: [
new VueLoaderPlugin()
],
entry: {
'mediaviewer': [
'core-js/modules/es6.promise',
'core-js/modules/es6.array.iterator',
'./src/app.js'
]
},
output: {
publicPath: 'apps/media-viewer/',
chunkFilename: '[name].media-viewer.chunk.js',
filename: 'media-viewer.bundle.js'
},
module: {
rules: [{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
rootMode: 'upward'
}
}, {
test: /\.vue$/,
loader: 'vue-loader'
}, {
enforce: 'pre',
test: /\.(js|vue)$/,
exclude: /node_modules/,
loader: 'eslint-loader'
}, {
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
}]
}
}
6 changes: 6 additions & 0 deletions apps/media-viewer/webpack.dev.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const merge = require('webpack-merge')
const common = require('./webpack.common.js')

module.exports = merge(common, {
devtool: 'source-map'
})
Loading

0 comments on commit ba21594

Please sign in to comment.