Skip to content

Commit

Permalink
Improve UX on iOS touch devices #832
Browse files Browse the repository at this point in the history
  • Loading branch information
lastzero committed Jan 16, 2021
1 parent f67cd40 commit bb5f8d8
Show file tree
Hide file tree
Showing 16 changed files with 225 additions and 38 deletions.
24 changes: 22 additions & 2 deletions frontend/src/component/photo/cards.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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)">
Expand All @@ -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)"
Expand All @@ -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>
Expand All @@ -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>
Expand All @@ -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>
Expand All @@ -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>
Expand All @@ -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/>
Expand Down Expand Up @@ -197,6 +210,7 @@ export default {
},
mouseDown: {
index: -1,
scrollY: window.scrollY,
timeStamp: -1,
},
};
Expand Down Expand Up @@ -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) {
Expand Down
14 changes: 12 additions & 2 deletions frontend/src/component/photo/list.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
Expand Down Expand Up @@ -148,6 +151,7 @@ export default {
hidePrivate: this.$config.values.settings.features.private,
mouseDown: {
index: -1,
scrollY: window.scrollY,
timeStamp: -1,
},
};
Expand All @@ -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) {
Expand Down
22 changes: 21 additions & 1 deletion frontend/src/component/photo/mosaic.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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)">
Expand All @@ -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)"
Expand All @@ -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>
Expand All @@ -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>
Expand All @@ -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>
Expand All @@ -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>
Expand Down Expand Up @@ -114,6 +127,7 @@ export default {
hidePrivate: this.$config.settings().features.private,
mouseDown: {
index: -1,
scrollY: window.scrollY,
timeStamp: -1,
},
};
Expand All @@ -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) {
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/css/search.css
Original file line number Diff line number Diff line change
@@ -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;
}
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/model/album.js
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand Down
4 changes: 4 additions & 0 deletions frontend/src/model/label.js
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand Down
32 changes: 29 additions & 3 deletions frontend/src/model/photo.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit bb5f8d8

Please sign in to comment.