Improve UX on iOS touch devices #832

This commit is contained in:
Michael Mayer 2021-01-16 15:49:52 +01:00
parent f67cd40e75
commit bb5f8d8858
16 changed files with 225 additions and 38 deletions

View File

@ -28,6 +28,7 @@
<v-card tile
:data-id="photo.ID"
:data-uid="photo.UID"
style="user-select: none"
class="result accent lighten-3"
:class="photo.classes()"
@contextmenu="onContextMenu($event, index)">
@ -39,6 +40,8 @@
:transition="false"
aspect-ratio="1"
class="accent lighten-2 clickable"
@touchstart="onMouseDown($event, index)"
@touchend.stop.prevent="onClick($event, index)"
@mousedown="onMouseDown($event, index)"
@click.stop.prevent="onClick($event, index)"
@mouseover="playLive(photo)"
@ -53,6 +56,8 @@
<v-btn :ripple="false" :depressed="false" class="input-open"
icon flat absolute
@touchstart.stop.prevent="openPhoto(index, true)"
@touchend.stop.prevent
@click.stop.prevent="openPhoto(index, true)">
<v-icon color="white" class="default-hidden action-raw" :title="$gettext('RAW')">photo_camera</v-icon>
<v-icon color="white" class="default-hidden action-live" :title="$gettext('Live')">adjust</v-icon>
@ -61,12 +66,16 @@
<v-btn :ripple="false" :depressed="false" class="input-view"
icon flat absolute :title="$gettext('View')"
@touchstart.stop.prevent="openPhoto(index, false)"
@touchend.stop.prevent
@click.stop.prevent="openPhoto(index, false)">
<v-icon color="white" class="action-fullscreen">zoom_in</v-icon>
</v-btn>
<v-btn :ripple="false" :depressed="false" color="white" class="input-play"
outline fab absolute :title="$gettext('Play')"
@touchstart.stop.prevent="openPhoto(index, true)"
@touchend.stop.prevent
@click.stop.prevent="openPhoto(index, true)">
<v-icon color="white" class="action-play">play_arrow</v-icon>
</v-btn>
@ -80,6 +89,8 @@
<v-btn :ripple="false"
icon flat absolute
class="input-select"
@touchstart.stop.prevent="onSelect($event, index)"
@touchend.stop.prevent
@click.stop.prevent="onSelect($event, index)">
<v-icon color="white" class="select-on">check_circle</v-icon>
<v-icon color="accent lighten-3" class="select-off">radio_button_off</v-icon>
@ -88,6 +99,8 @@
<v-btn :ripple="false"
icon flat absolute
class="input-favorite"
@touchstart.stop.prevent="photo.toggleLike()"
@touchend.stop.prevent
@click.stop.prevent="photo.toggleLike()">
<v-icon color="white" class="select-on">favorite</v-icon>
<v-icon color="accent lighten-3" class="select-off">favorite_border</v-icon>
@ -111,7 +124,7 @@
<button class="action-date-edit" :data-uid="photo.UID"
@click.exact="editPhoto(index)">
<v-icon size="14" :title="labels.taken">date_range</v-icon>
{{ photo.getDateString() }}
{{ photo.getDateString(true) }}
</button>
<template v-if="!photo.Description">
<br/>
@ -197,6 +210,7 @@ export default {
},
mouseDown: {
index: -1,
scrollY: window.scrollY,
timeStamp: -1,
},
};
@ -229,10 +243,16 @@ export default {
},
onMouseDown(ev, index) {
this.mouseDown.index = index;
this.mouseDown.scrollY = window.scrollY;
this.mouseDown.timeStamp = ev.timeStamp;
},
onClick(ev, index) {
let longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const scrolled = (this.mouseDown.scrollY - window.scrollY) !== 0;
if (scrolled) {
return;
}
if (longClick || this.selectMode) {
if (longClick || ev.shiftKey) {

View File

@ -31,14 +31,17 @@
item-key="ID"
:no-data-text="notFoundMessage"
>
<template v-slot:items="props">
<template #items="props">
<td style="user-select: none;" :data-uid="props.item.UID" class="result" :class="props.item.classes()">
<v-img :key="props.item.Hash"
:src="props.item.thumbnailUrl('tile_50')"
:alt="props.item.Title"
:transition="false"
aspect-ratio="1"
style="user-select: none"
class="accent lighten-2 clickable"
@touchstart="onMouseDown($event, props.index)"
@touchend.stop.prevent="onClick($event, props.index)"
@mousedown="onMouseDown($event, props.index)"
@contextmenu="onContextMenu($event, props.index)"
@click.stop.prevent="onClick($event, props.index)"
@ -148,6 +151,7 @@ export default {
hidePrivate: this.$config.values.settings.features.private,
mouseDown: {
index: -1,
scrollY: window.scrollY,
timeStamp: -1,
},
};
@ -169,10 +173,16 @@ export default {
},
onMouseDown(ev, index) {
this.mouseDown.index = index;
this.mouseDown.scrollY = window.scrollY;
this.mouseDown.timeStamp = ev.timeStamp;
},
onClick(ev, index) {
let longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const scrolled = (this.mouseDown.scrollY - window.scrollY) !== 0;
if (scrolled) {
return;
}
if (longClick || this.selectMode) {
if (longClick || ev.shiftKey) {

View File

@ -28,6 +28,7 @@
<v-card tile
:data-id="photo.ID"
:data-uid="photo.UID"
style="user-select: none"
class="result"
:class="photo.classes()"
@contextmenu="onContextMenu($event, index)">
@ -38,6 +39,8 @@
:transition="false"
aspect-ratio="1"
class="accent lighten-2 clickable"
@touchstart="onMouseDown($event, index)"
@touchend.stop.prevent="onClick($event, index)"
@mousedown="onMouseDown($event, index)"
@click.stop.prevent="onClick($event, index)"
@mouseover="playLive(photo)"
@ -52,6 +55,8 @@
<v-btn :ripple="false" :depressed="false" class="input-open"
icon flat small absolute
@touchstart.stop.prevent="openPhoto(index, true)"
@touchend.stop.prevent
@click.stop.prevent="openPhoto(index, true)">
<v-icon color="white" class="default-hidden action-raw" :title="$gettext('RAW')">photo_camera</v-icon>
<v-icon color="white" class="default-hidden action-live" :title="$gettext('Live')">adjust</v-icon>
@ -60,12 +65,16 @@
<v-btn :ripple="false" :depressed="false" class="input-view"
icon flat small absolute :title="$gettext('View')"
@touchstart.stop.prevent="openPhoto(index, false)"
@touchend.stop.prevent
@click.stop.prevent="openPhoto(index, false)">
<v-icon color="white" class="action-fullscreen">zoom_in</v-icon>
</v-btn>
<v-btn :ripple="false" :depressed="false" color="white" class="input-play"
outline fab absolute :title="$gettext('Play')"
@touchstart.stop.prevent="openPhoto(index, true)"
@touchend.stop.prevent
@click.stop.prevent="openPhoto(index, true)">
<v-icon color="white" class="action-play">play_arrow</v-icon>
</v-btn>
@ -79,6 +88,8 @@
<v-btn :ripple="false"
icon flat small absolute
class="input-select"
@touchstart.stop.prevent="onSelect($event, index)"
@touchend.stop.prevent
@click.stop.prevent="onSelect($event, index)">
<v-icon color="white" class="select-on">check_circle</v-icon>
<v-icon color="accent lighten-3" class="select-off">radio_button_off</v-icon>
@ -87,6 +98,8 @@
<v-btn :ripple="false"
icon flat small absolute
class="input-favorite"
@touchstart.stop.prevent="photo.toggleLike()"
@touchend.stop.prevent
@click.stop.prevent="photo.toggleLike()">
<v-icon color="white" class="select-on">favorite</v-icon>
<v-icon color="accent lighten-3" class="select-off">favorite_border</v-icon>
@ -114,6 +127,7 @@ export default {
hidePrivate: this.$config.settings().features.private,
mouseDown: {
index: -1,
scrollY: window.scrollY,
timeStamp: -1,
},
};
@ -139,13 +153,19 @@ export default {
},
onMouseDown(ev, index) {
this.mouseDown.index = index;
this.mouseDown.scrollY = window.scrollY;
this.mouseDown.timeStamp = ev.timeStamp;
},
toggle(photo) {
this.$clipboard.toggle(photo);
},
onClick(ev, index) {
let longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const scrolled = (this.mouseDown.scrollY - window.scrollY) !== 0;
if (scrolled) {
return;
}
if (longClick || this.selectMode) {
if (longClick || ev.shiftKey) {

View File

@ -1,3 +1,10 @@
#photoprism .cards-view,
#photoprism .mosaic-view,
#photoprism .cards-view .v-card,
#photoprism .mosaic-view .v-card {
user-select: none !important;
}
#photoprism .p-col-select {
width: 66px;
}

View File

@ -65,6 +65,13 @@ export class Album extends RestModel {
};
}
route(view) {
return {
name: view,
params: { uid: this.UID, slug: this.Slug, year: this.Year, month: this.Month },
};
}
classes(selected) {
let classes = ["is-album", "uid-" + this.UID, "type-" + this.Type];

View File

@ -53,6 +53,10 @@ export class Label extends RestModel {
};
}
route(view) {
return { name: view, query: { q: "label:" + (this.CustomSlug ? this.CustomSlug : this.Slug) } };
}
classes(selected) {
let classes = ["is-label", "uid-" + this.UID];

View File

@ -51,6 +51,29 @@ export const YearUnknown = -1;
export const MonthUnknown = -1;
export const DayUnknown = -1;
const num = "numeric";
const short = "short";
const long = "long";
const DATE_FULL = {
year: num,
month: long,
day: num,
weekday: long,
hour: num,
minute: num,
};
const DATE_FULL_TZ = {
year: num,
month: long,
day: num,
weekday: long,
hour: num,
minute: num,
timeZoneName: short,
};
export class Photo extends RestModel {
constructor(values) {
super(values);
@ -427,15 +450,18 @@ export class Photo extends RestModel {
return { width: newW, height: newH };
}
getDateString() {
getDateString(showTimeZone) {
if (!this.TakenAt || this.Year === YearUnknown) {
return $gettext("Unknown");
} else if (this.Month === MonthUnknown) {
return this.localYearString();
} else if (this.Day === DayUnknown) {
return this.localDate().toLocaleString({ month: "long", year: "numeric" });
return this.localDate().toLocaleString({
month: long,
year: num,
});
} else if (this.TimeZone) {
return this.localDate().toLocaleString(DateTime.DATETIME_FULL);
return this.localDate().toLocaleString(showTimeZone ? DATE_FULL_TZ : DATE_FULL);
}
return this.localDate().toLocaleString(DateTime.DATE_HUGE);

View File

@ -85,9 +85,10 @@
>
<v-card tile
:data-uid="album.UID"
style="user-select: none"
class="result accent lighten-3"
:class="album.classes(selection.includes(album.UID))"
:to="{name: view, params: {uid: album.UID, slug: album.Slug, year: album.Year, month: album.Month}}"
:to="album.route(view)"
@contextmenu="onContextMenu($event, index)"
>
<div class="card-background accent lighten-3"></div>
@ -97,12 +98,16 @@
:transition="false"
aspect-ratio="1"
class="accent lighten-2 clickable"
@touchstart="onMouseDown($event, index)"
@touchend.stop.prevent="onClick($event, index)"
@mousedown="onMouseDown($event, index)"
@click="onClick($event, index)"
@click.stop.prevent="onClick($event, index)"
>
<v-btn v-if="featureShare && album.LinkCount > 0" :ripple="false"
icon flat absolute
class="action-share"
@touchstart.stop.prevent="share(album)"
@touchend.stop.prevent
@click.stop.prevent="share(album)">
<v-icon color="white">share</v-icon>
</v-btn>
@ -110,6 +115,8 @@
<v-btn :ripple="false"
icon flat absolute
class="input-select"
@touchstart.stop.prevent="onSelect($event, index)"
@touchend.stop.prevent
@click.stop.prevent="onSelect($event, index)">
<v-icon color="white" class="select-on">check_circle</v-icon>
<v-icon color="accent lighten-3" class="select-off">radio_button_off</v-icon>
@ -118,6 +125,8 @@
<v-btn :ripple="false"
icon flat absolute
class="input-favorite"
@touchstart.stop.prevent="album.toggleLike()"
@touchend.stop.prevent
@click.stop.prevent="album.toggleLike()">
<v-icon color="#FFD600" class="select-on">star</v-icon>
<v-icon color="white" class="select-off">star_border</v-icon>
@ -234,6 +243,7 @@ export default {
titleRule: v => v.length <= this.$config.get('clip') || this.$gettext("Title too long"),
mouseDown: {
index: -1,
scrollY: window.scrollY,
timeStamp: -1,
},
lastId: "",
@ -345,20 +355,25 @@ export default {
},
onMouseDown(ev, index) {
this.mouseDown.index = index;
this.mouseDown.scrollY = window.scrollY;
this.mouseDown.timeStamp = ev.timeStamp;
},
onClick(ev, index) {
let longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const scrolled = (this.mouseDown.scrollY - window.scrollY) !== 0;
if (scrolled) {
return;
}
if (longClick || this.selection.length > 0) {
ev.preventDefault();
ev.stopPropagation();
if (longClick || ev.shiftKey) {
this.selectRange(index, this.results);
} else {
this.toggleSelection(this.results[index].getId());
}
} else {
this.$router.push(this.results[index].route(this.view));
}
},
onContextMenu(ev, index) {

View File

@ -15,8 +15,8 @@
xs3 d-flex grow
>
<v-hover>
<v-card :to="{name: 'browse', query: { color: color.name }}" :dark="useDark(color)"
:color="color.example" slot-scope="{ hover }" :flat="!hover"
<v-card slot-scope="{ hover }" :to="{name: 'browse', query: { color: color.name }}"
:dark="useDark(color)" :color="color.example" :flat="!hover"
class="clickable py-1">
<v-card-text class="px-0 py-5 body-2">{{ color.label }}</v-card-text>
</v-card>
@ -30,7 +30,7 @@
<script>
export default {
name: 'p-tab-discover-colors',
name: 'PTabDiscoverColors',
data() {
return {
readonly: this.$config.get("readonly"),
@ -38,6 +38,8 @@ export default {
labels: {},
};
},
created() {
},
methods: {
useDark(color) {
switch (color.name) {
@ -48,7 +50,5 @@ export default {
}
}
},
created() {
},
};
</script>

View File

@ -62,9 +62,10 @@
>
<v-card tile
:data-uid="label.UID"
style="user-select: none"
class="result accent lighten-3"
:class="label.classes(selection.includes(label.UID))"
:to="{name: 'all', query: {q: 'label:' + (label.CustomSlug ? label.CustomSlug : label.Slug)}}"
:to="label.route(view)"
@contextmenu="onContextMenu($event, index)"
>
<div class="card-background accent lighten-3"></div>
@ -74,12 +75,16 @@
:transition="false"
aspect-ratio="1"
class="accent lighten-2 clickable"
@touchstart="onMouseDown($event, index)"
@touchend.stop.prevent="onClick($event, index)"
@mousedown="onMouseDown($event, index)"
@click="onClick($event, index)"
@click.stop.prevent="onClick($event, index)"
>
<v-btn :ripple="false"
icon flat absolute
class="input-select"
@touchstart.stop.prevent="onSelect($event, index)"
@touchend.stop.prevent
@click.stop.prevent="onSelect($event, index)">
<v-icon color="white" class="select-on">check_circle</v-icon>
<v-icon color="accent lighten-3" class="select-off">radio_button_off</v-icon>
@ -88,6 +93,8 @@
<v-btn :ripple="false"
icon flat absolute
class="input-favorite"
@touchstart.stop.prevent="label.toggleLike()"
@touchend.stop.prevent
@click.stop.prevent="label.toggleLike()">
<v-icon color="#FFD600" class="select-on">star</v-icon>
<v-icon color="white" class="select-off">star_border</v-icon>
@ -148,6 +155,7 @@ export default {
const settings = {};
return {
view: 'all',
config: this.$config.values,
subscriptions: [],
listen: false,
@ -166,6 +174,7 @@ export default {
titleRule: v => v.length <= this.$config.get('clip') || this.$gettext("Name too long"),
mouseDown: {
index: -1,
scrollY: window.scrollY,
timeStamp: -1,
},
lastId: "",
@ -243,20 +252,25 @@ export default {
},
onMouseDown(ev, index) {
this.mouseDown.index = index;
this.mouseDown.scrollY = window.scrollY;
this.mouseDown.timeStamp = ev.timeStamp;
},
onClick(ev, index) {
let longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const scrolled = (this.mouseDown.scrollY - window.scrollY) !== 0;
if (scrolled) {
return;
}
if (longClick || this.selection.length > 0) {
ev.preventDefault();
ev.stopPropagation();
if (longClick || ev.shiftKey) {
this.selectRange(index, this.results);
} else {
this.toggleSelection(this.results[index].getId());
}
} else {
this.$router.push(this.results[index].route(this.view));
}
},
onContextMenu(ev, index) {

View File

@ -149,6 +149,7 @@ export default {
titleRule: v => v.length <= this.$config.get('clip') || this.$gettext("Name too long"),
mouseDown: {
index: -1,
scrollY: window.scrollY,
timeStamp: -1,
},
lastId: "",
@ -248,10 +249,16 @@ export default {
},
onMouseDown(ev, index) {
this.mouseDown.index = index;
this.mouseDown.scrollY = window.scrollY;
this.mouseDown.timeStamp = ev.timeStamp;
},
onClick(ev, index) {
let longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const scrolled = (this.mouseDown.scrollY - window.scrollY) !== 0;
if (scrolled) {
return;
}
if (longClick || this.selection.length > 0) {
ev.preventDefault();

View File

@ -36,9 +36,10 @@
>
<v-card tile
:data-uid="album.UID"
style="user-select: none"
class="result accent lighten-3"
:class="album.classes(selection.includes(album.UID))"
:to="{name: view, params: {uid: album.UID, slug: album.Slug, year: album.Year, month: album.Month}}"
:to="album.route(view)"
@contextmenu="onContextMenu($event, index)"
>
<div class="card-background accent lighten-3"></div>
@ -48,12 +49,16 @@
:transition="false"
aspect-ratio="1"
class="accent lighten-2 clickable"
@touchstart="onMouseDown($event, index)"
@touchend.stop.prevent="onClick($event, index)"
@mousedown="onMouseDown($event, index)"
@click="onClick($event, index)"
@click.stop.prevent="onClick($event, index)"
>
<v-btn :ripple="false"
icon flat absolute
class="input-select"
@touchstart.stop.prevent="onSelect($event, index)"
@touchend.stop.prevent
@click.stop.prevent="onSelect($event, index)">
<v-icon color="white" class="select-on">check_circle</v-icon>
<v-icon color="accent lighten-3" class="select-off">radio_button_off</v-icon>
@ -143,6 +148,7 @@ export default {
titleRule: v => v.length <= this.$config.get('clip') || this.$gettext("Title too long"),
mouseDown: {
index: -1,
scrollY: window.scrollY,
timeStamp: -1,
},
lastId: "",
@ -245,20 +251,25 @@ export default {
},
onMouseDown(ev, index) {
this.mouseDown.index = index;
this.mouseDown.scrollY = window.scrollY;
this.mouseDown.timeStamp = ev.timeStamp;
},
onClick(ev, index) {
let longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const scrolled = (this.mouseDown.scrollY - window.scrollY) !== 0;
if (scrolled) {
return;
}
if (longClick || this.selection.length > 0) {
ev.preventDefault();
ev.stopPropagation();
if (longClick || ev.shiftKey) {
this.selectRange(index, this.results);
} else {
this.toggleSelection(this.results[index].getId());
}
} else {
this.$router.push(this.results[index].route(this.view));
}
},
onContextMenu(ev, index) {

View File

@ -24,6 +24,7 @@
<v-card tile
:data-id="photo.ID"
:data-uid="photo.UID"
style="user-select: none"
class="result accent lighten-3"
:class="photo.classes()"
@contextmenu="onContextMenu($event, index)">
@ -35,6 +36,8 @@
:transition="false"
aspect-ratio="1"
class="accent lighten-2 clickable"
@touchstart="onMouseDown($event, index)"
@touchend.stop.prevent="onClick($event, index)"
@mousedown="onMouseDown($event, index)"
@click.stop.prevent="onClick($event, index)"
@mouseover="playLive(photo)"
@ -49,6 +52,8 @@
<v-btn :ripple="false" :depressed="false" class="input-open"
icon flat absolute
@touchstart.stop.prevent="openPhoto(index, true)"
@touchend.stop.prevent
@click.stop.prevent="openPhoto(index, true)">
<v-icon color="white" class="default-hidden action-raw" :title="$gettext('RAW')">photo_camera</v-icon>
<v-icon color="white" class="default-hidden action-live" :title="$gettext('Live')">adjust</v-icon>
@ -57,12 +62,16 @@
<v-btn :ripple="false" :depressed="false" class="input-view"
icon flat absolute :title="$gettext('View')"
@touchstart.stop.prevent="openPhoto(index, false)"
@touchend.stop.prevent
@click.stop.prevent="openPhoto(index, false)">
<v-icon color="white" class="action-fullscreen">zoom_in</v-icon>
</v-btn>
<v-btn :ripple="false" :depressed="false" color="white" class="input-play"
outline fab absolute :title="$gettext('Play')"
@touchstart.stop.prevent="openPhoto(index, true)"
@touchend.stop.prevent
@click.stop.prevent="openPhoto(index, true)">
<v-icon color="white" class="action-play">play_arrow</v-icon>
</v-btn>
@ -70,6 +79,8 @@
<v-btn :ripple="false"
icon flat absolute
class="input-select"
@touchstart.stop.prevent="onSelect($event, index)"
@touchend.stop.prevent
@click.stop.prevent="onSelect($event, index)">
<v-icon color="white" class="select-on">check_circle</v-icon>
<v-icon color="accent lighten-3" class="select-off">radio_button_off</v-icon>
@ -91,7 +102,7 @@
<div class="caption">
<div>
<v-icon size="14" :title="labels.taken">date_range</v-icon>
{{ photo.getDateString() }}
{{ photo.getDateString(true) }}
</div>
<template v-if="!photo.Description">
<div v-if="photo.Type === 'video'" :title="labels.video">
@ -153,6 +164,7 @@ export default {
},
mouseDown: {
index: -1,
scrollY: window.scrollY,
timeStamp: -1,
},
};
@ -185,10 +197,16 @@ export default {
},
onMouseDown(ev, index) {
this.mouseDown.index = index;
this.mouseDown.scrollY = window.scrollY;
this.mouseDown.timeStamp = ev.timeStamp;
},
onClick(ev, index) {
let longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const scrolled = (this.mouseDown.scrollY - window.scrollY) !== 0;
if (scrolled) {
return;
}
if (longClick || this.selectMode) {
if (longClick || ev.shiftKey) {

View File

@ -27,14 +27,17 @@
item-key="ID"
:no-data-text="notFoundMessage"
>
<template slot:items="props">
<template #items="props">
<td style="user-select: none;" :data-uid="props.item.UID" class="result" :class="props.item.classes()">
<v-img :key="props.item.Hash"
:src="props.item.thumbnailUrl('tile_50')"
:alt="props.item.Title"
:transition="false"
aspect-ratio="1"
style="user-select: none"
class="accent lighten-2 clickable"
@touchstart="onMouseDown($event, props.index)"
@touchend.stop.prevent="onClick($event, props.index)"
@mousedown="onMouseDown($event, props.index)"
@contextmenu="onContextMenu($event, props.index)"
@click.stop.prevent="onClick($event, props.index)"
@ -127,6 +130,7 @@ export default {
hidePrivate: this.$config.values.settings.features.private,
mouseDown: {
index: -1,
scrollY: window.scrollY,
timeStamp: -1,
},
};
@ -148,10 +152,16 @@ export default {
},
onMouseDown(ev, index) {
this.mouseDown.index = index;
this.mouseDown.scrollY = window.scrollY;
this.mouseDown.timeStamp = ev.timeStamp;
},
onClick(ev, index) {
let longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const scrolled = (this.mouseDown.scrollY - window.scrollY) !== 0;
if (scrolled) {
return;
}
if (longClick || this.selectMode) {
if (longClick || ev.shiftKey) {

View File

@ -24,6 +24,7 @@
<v-card tile
:data-id="photo.ID"
:data-uid="photo.UID"
style="user-select: none"
class="result"
:class="photo.classes()"
@contextmenu="onContextMenu($event, index)">
@ -34,6 +35,8 @@
:transition="false"
aspect-ratio="1"
class="accent lighten-2 clickable"
@touchstart="onMouseDown($event, index)"
@touchend.stop.prevent="onClick($event, index)"
@mousedown="onMouseDown($event, index)"
@click.stop.prevent="onClick($event, index)"
@mouseover="playLive(photo)"
@ -48,6 +51,8 @@
<v-btn :ripple="false" :depressed="false" class="input-open"
icon flat small absolute
@touchstart.stop.prevent="openPhoto(index, true)"
@touchend.stop.prevent
@click.stop.prevent="openPhoto(index, true)">
<v-icon color="white" class="default-hidden action-raw" :title="$gettext('RAW')">photo_camera</v-icon>
<v-icon color="white" class="default-hidden action-live" :title="$gettext('Live')">adjust</v-icon>
@ -56,12 +61,16 @@
<v-btn :ripple="false" :depressed="false" class="input-view"
icon flat small absolute :title="$gettext('View')"
@touchstart.stop.prevent="openPhoto(index, false)"
@touchend.stop.prevent
@click.stop.prevent="openPhoto(index, false)">
<v-icon color="white" class="action-fullscreen">zoom_in</v-icon>
</v-btn>
<v-btn :ripple="false" :depressed="false" color="white" class="input-play"
outline fab absolute :title="$gettext('Play')"
@touchstart.stop.prevent="openPhoto(index, true)"
@touchend.stop.prevent
@click.stop.prevent="openPhoto(index, true)">
<v-icon color="white" class="action-play">play_arrow</v-icon>
</v-btn>
@ -69,6 +78,8 @@
<v-btn :ripple="false"
icon flat small absolute
class="input-select"
@touchstart.stop.prevent="onSelect($event, index)"
@touchend.stop.prevent
@click.stop.prevent="onSelect($event, index)">
<v-icon color="white" class="select-on">check_circle</v-icon>
<v-icon color="accent lighten-3" class="select-off">radio_button_off</v-icon>
@ -96,6 +107,7 @@ export default {
hidePrivate: this.$config.settings().features.private,
mouseDown: {
index: -1,
scrollY: window.scrollY,
timeStamp: -1,
},
};
@ -121,13 +133,19 @@ export default {
},
onMouseDown(ev, index) {
this.mouseDown.index = index;
this.mouseDown.scrollY = window.scrollY;
this.mouseDown.timeStamp = ev.timeStamp;
},
toggle(photo) {
this.$clipboard.toggle(photo);
},
onClick(ev, index) {
let longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
const scrolled = (this.mouseDown.scrollY - window.scrollY) !== 0;
if (scrolled) {
return;
}
if (longClick || this.selectMode) {
if (longClick || ev.shiftKey) {

View File

@ -172,7 +172,7 @@ describe("model/photo", () => {
const values = {ID: 5, Title: "Crazy Cat", TakenAtLocal: "2012-07-08T14:45:39Z", TakenAt: "2012-07-08T14:45:39Z", TimeZone: "UTC"};
const photo = new Photo(values);
const result = photo.getDateString();
assert.equal(result, "July 8, 2012, 2:45 PM UTC");
assert.equal(result, "Sunday, July 8, 2012, 2:45 PM");
const values2 = {ID: 5, Title: "Crazy Cat", TakenAtLocal: "", TakenAt: "", TimeZone: "UTC"};
const photo2 = new Photo(values2);
const result2 = photo2.getDateString();