Frontend: Fix photo model and card view

Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
Michael Mayer 2020-04-23 18:47:19 +02:00
parent 724ec41273
commit 7181adb360
6 changed files with 146 additions and 178 deletions

View File

@ -3,7 +3,6 @@ import PNavigation from "./p-navigation.vue";
import PLoadingBar from "./p-loading-bar.vue";
import PPhotoSearch from "./p-photo-search.vue";
import PPhotoCards from "./p-photo-cards.vue";
import PPhotoCard from "./p-photo-card.vue";
import PPhotoMosaic from "./p-photo-mosaic.vue";
import PPhotoList from "./p-photo-list.vue";
import PPhotoClipboard from "./p-photo-clipboard.vue";
@ -21,7 +20,6 @@ components.install = (Vue) => {
Vue.component("p-loading-bar", PLoadingBar);
Vue.component("p-photo-viewer", PPhotoViewer);
Vue.component("p-photo-cards", PPhotoCards);
Vue.component("p-photo-card", PPhotoCard);
Vue.component("p-photo-mosaic", PPhotoMosaic);
Vue.component("p-photo-list", PPhotoList);
Vue.component("p-photo-search", PPhotoSearch);

View File

@ -1,149 +0,0 @@
<template>
<v-hover>
<v-card tile slot-scope="{ hover }"
@contextmenu="contextMenu($event)"
:dark="isSelected"
:class="isSelected ? 'elevation-10 ma-0 accent darken-1 white--text' : 'elevation-0 ma-1 accent lighten-3'">
<v-img
:src="thumbnailUrl"
aspect-ratio="1"
v-bind:class="{ selected: isSelected }"
style="cursor: pointer;"
class="accent lighten-2"
v-longclick="longClick"
@click="onClick($event)"
>
<v-layout
slot="placeholder"
fill-height
align-center
justify-center
ma-0
>
<v-progress-circular indeterminate color="accent lighten-5"></v-progress-circular>
</v-layout>
<v-btn v-if="hover || selection.length > 0" :flat="!hover" :ripple="false"
icon large absolute
:class="isSelected ? 'p-photo-select' : 'p-photo-select opacity-50'"
@click.stop.prevent="onSelect($event)">
<v-icon v-if="selection.length && isSelected" color="white"
class="t-select t-on">check_circle
</v-icon>
<v-icon v-else color="accent lighten-3" class="t-select t-off">radio_button_off</v-icon>
</v-btn>
<v-btn :flat="!hover" :ripple="false"
icon large absolute
:class="photo.PhotoFavorite ? 'p-photo-like opacity-75' : 'p-photo-like opacity-50'"
@click.stop.prevent="photo.toggleLike()">
<v-icon v-if="photo.PhotoFavorite" color="white" class="t-like t-on">favorite</v-icon>
<v-icon v-else color="accent lighten-3" class="t-like t-off">favorite_border</v-icon>
</v-btn>
<v-btn v-if="photo.Files.length > 1" :flat="!hover" :ripple="false"
icon large absolute class="p-photo-merged opacity-75"
@click.stop.prevent="openPhoto(index, true)">
<v-icon color="white" class="action-burst">burst_mode</v-icon>
</v-btn>
</v-img>
<v-card-title primary-title class="pa-3 p-photo-desc" style="user-select: none;">
<div>
<h3 class="body-2 mb-2" :title="photo.PhotoTitle">
<button @click.exact="editPhoto(index)">
{{ photo.PhotoTitle | truncate(80) }}
</button>
</h3>
<div class="caption">
<button @click.exact="editPhoto(index)">
<v-icon size="14">date_range</v-icon>
{{ photo.getDateString() }}
</button>
<br/>
<button @click.exact="editPhoto(index)">
<v-icon size="14">photo_camera</v-icon>
{{ photo.getCamera() }}
</button>
<br/>
<button @click.exact="openLocation(index)" v-if="showLocation && photo.LocationID">
<v-icon size="14">location_on</v-icon>
{{ photo.getLocation() }}
</button>
</div>
</div>
</v-card-title>
</v-card>
</v-hover>
</template>
<script>
export default {
name: 'p-photo-card',
props: {
index: Number,
photo: Object,
selection: Array,
selectRange: Function,
openPhoto: Function,
editPhoto: Function,
openLocation: Function,
showLocation: Boolean,
},
data() {
return {
isSelected: this.$clipboard.has(this.photo),
thumbnailUrl: this.photo.getThumbnailUrl('tile_500'),
wasLong: false,
};
},
methods: {
longClick() {
this.wasLong = true;
},
onSelect(ev) {
if (this.wasLong || ev.shiftKey) {
this.selectRange(this.index);
} else {
this.$clipboard.toggle(this.photo);
}
this.wasLong = false;
},
onClick(ev) {
if (this.wasLong || this.selection.length > 0) {
ev.preventDefault();
ev.stopPropagation();
if (this.wasLong || ev.shiftKey) {
this.selectRange(this.index);
} else {
this.$clipboard.toggle(this.photo);
}
} else {
this.openPhoto(this.index, false);
}
this.wasLong = false;
},
contextMenu(ev) {
if (this.$isMobile) {
ev.preventDefault();
ev.stopPropagation();
if (this.wasLong) {
this.selectRange(this.index);
} else {
this.$clipboard.toggle(this.photo);
}
}
this.wasLong = false;
},
},
watch: {
selection() {
this.isSelected = this.$clipboard.has(this.photo);
}
},
};
</script>

View File

@ -21,10 +21,82 @@
xs12 sm6 md4 lg3 d-flex
v-bind:class="{ 'is-selected': $clipboard.has(photo) }"
>
<p-photo-card :photo="photo" :selection="selection" :index="index" :open-photo="openPhoto"
:select-range="selectRange"
:edit-photo="editPhoto" :open-location="openLocation" :show-location="places">
</p-photo-card>
<v-hover>
<v-card tile slot-scope="{ hover }"
@contextmenu="contextMenu($event, photo, index)"
:dark="$clipboard.has(photo)"
:class="$clipboard.has(photo) ? 'elevation-10 ma-0 accent darken-1 white--text' : 'elevation-0 ma-1 accent lighten-3'">
<v-img
:src="photo.getThumbnailUrl('tile_500')"
aspect-ratio="1"
v-bind:class="{ selected: $clipboard.has(photo) }"
style="cursor: pointer;"
class="accent lighten-2"
v-longclick="longClick"
@click="onClick($event, photo, index)"
>
<v-layout
slot="placeholder"
fill-height
align-center
justify-center
ma-0
>
<v-progress-circular indeterminate color="accent lighten-5"></v-progress-circular>
</v-layout>
<v-btn v-if="hover || selection.length > 0" :flat="!hover" :ripple="false"
icon large absolute
:class="$clipboard.has(photo) ? 'p-photo-select' : 'p-photo-select opacity-50'"
@click.stop.prevent="onSelect($event, photo, index)">
<v-icon v-if="selection.length && $clipboard.has(photo)" color="white"
class="t-select t-on">check_circle
</v-icon>
<v-icon v-else color="accent lighten-3" class="t-select t-off">radio_button_off</v-icon>
</v-btn>
<v-btn :flat="!hover" :ripple="false"
icon large absolute
:class="photo.PhotoFavorite ? 'p-photo-like opacity-75' : 'p-photo-like opacity-50'"
@click.stop.prevent="photo.toggleLike()">
<v-icon v-if="photo.PhotoFavorite" color="white" class="t-like t-on">favorite</v-icon>
<v-icon v-else color="accent lighten-3" class="t-like t-off">favorite_border</v-icon>
</v-btn>
<v-btn v-if="photo.Files.length > 1" :flat="!hover" :ripple="false"
icon large absolute class="p-photo-merged opacity-75"
@click.stop.prevent="openPhoto(index, true)">
<v-icon color="white" class="action-burst">burst_mode</v-icon>
</v-btn>
</v-img>
<v-card-title primary-title class="pa-3 p-photo-desc" style="user-select: none;">
<div>
<h3 class="body-2 mb-2" :title="photo.PhotoTitle">
<button @click.exact="editPhoto(index)">
{{ photo.PhotoTitle | truncate(80) }}
</button>
</h3>
<div class="caption">
<button @click.exact="editPhoto(index)">
<v-icon size="14">date_range</v-icon>
{{ photo.getDateString() }}
</button>
<br/>
<button @click.exact="editPhoto(index)">
<v-icon size="14">photo_camera</v-icon>
{{ photo.getCamera() }}
</button>
<br/>
<button @click.exact="openLocation(index)" v-if="showLocation && photo.LocationID">
<v-icon size="14">location_on</v-icon>
{{ photo.getLocation() }}
</button>
</div>
</div>
</v-card-title>
</v-card>
</v-hover>
</v-flex>
</v-layout>
</v-container>
@ -42,10 +114,53 @@
},
data() {
return {
places: this.$config.settings().features.places,
showLocation: this.$config.settings().features.places,
wasLong: false,
};
},
methods: {
longClick() {
this.wasLong = true;
},
onSelect(ev, model, index) {
if (this.wasLong || ev.shiftKey) {
this.selectRange(index);
} else {
this.$clipboard.toggle(model);
}
this.wasLong = false;
},
onClick(ev, model, index) {
if (this.wasLong || this.selection.length > 0) {
ev.preventDefault();
ev.stopPropagation();
if (this.wasLong || ev.shiftKey) {
this.selectRange(index);
} else {
this.$clipboard.toggle(model);
}
} else {
this.openPhoto(index, false);
}
this.wasLong = false;
},
contextMenu(ev, model, index) {
if (this.$isMobile) {
ev.preventDefault();
ev.stopPropagation();
if (this.wasLong) {
this.selectRange(index);
} else {
this.$clipboard.toggle(model);
}
}
this.wasLong = false;
},
selectRange(index) {
this.$clipboard.addRange(index, this.photos);
}

View File

@ -91,15 +91,15 @@ class Rest extends Model {
if (response.headers) {
if (response.headers["x-count"]) {
count = response.headers["x-count"];
count = parseInt(response.headers["x-count"]);
}
if (response.headers["x-limit"]) {
limit = response.headers["x-limit"];
limit = parseInt(response.headers["x-limit"]);
}
if (response.headers["x-offset"]) {
offset = response.headers["x-offset"];
offset = parseInt(response.headers["x-offset"]);
}
}

View File

@ -29,12 +29,12 @@
:edit-photo="editPhoto"
:open-location="openLocation"></p-photo-list>
<p-photo-cards v-else
:photos="results"
:selection="selection"
:album="model"
:open-photo="openPhoto"
:edit-photo="editPhoto"
:open-location="openLocation"></p-photo-cards>
:photos="results"
:selection="selection"
:album="model"
:open-photo="openPhoto"
:edit-photo="editPhoto"
:open-location="openLocation"></p-photo-cards>
</v-container>
</div>
</template>
@ -331,11 +331,13 @@
case 'updated':
for (let i = 0; i < data.entities.length; i++) {
const values = data.entities[i];
const model = this.results.find((m) => m.ID === values.ID);
const model = this.results.find((m) => m.PhotoUUID === values.PhotoUUID);
for (let key in values) {
if (values.hasOwnProperty(key)) {
model[key] = values[key];
if (model) {
for (let key in values) {
if (values.hasOwnProperty(key)) {
model[key] = values[key];
}
}
}
}

View File

@ -25,11 +25,11 @@
:edit-photo="editPhoto"
:open-location="openLocation"></p-photo-list>
<p-photo-cards v-else
:photos="results"
:selection="selection"
:open-photo="openPhoto"
:edit-photo="editPhoto"
:open-location="openLocation"></p-photo-cards>
:photos="results"
:selection="selection"
:open-photo="openPhoto"
:edit-photo="editPhoto"
:open-location="openLocation"></p-photo-cards>
</v-container>
</div>
</template>
@ -305,11 +305,13 @@
case 'updated':
for (let i = 0; i < data.entities.length; i++) {
const values = data.entities[i];
const model = this.results.find((m) => m.ID === values.ID);
const model = this.results.find((m) => m.PhotoUUID === values.PhotoUUID);
for (let key in values) {
if (values.hasOwnProperty(key)) {
model[key] = values[key];
if (model) {
for (let key in values) {
if (values.hasOwnProperty(key)) {
model[key] = values[key];
}
}
}
}