diff --git a/frontend/src/common/input.js b/frontend/src/common/input.js new file mode 100644 index 000000000..d1a2417a3 --- /dev/null +++ b/frontend/src/common/input.js @@ -0,0 +1,103 @@ +/* + +Copyright (c) 2018 - 2021 Michael Mayer + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + PhotoPrism® is a registered trademark of Michael Mayer. You may use it as required + to describe our software, run your own server, for educational purposes, but not for + offering commercial goods, products, or services without prior written permission. + In other words, please ask. + +Feel free to send an e-mail to hello@photoprism.org if you have questions, +want to support our work, or just want to say hello. + +Additional information can be found in our Developer Guide: +https://docs.photoprism.org/developer-guide/ + +*/ + +export const InputInvalid = 0; +export const ClickShort = 1; +export const ClickLong = 2; + +export class Input { + constructor() { + this.reset(); + } + + reset() { + this.index = -1; + this.scrollY = window.scrollY; + this.touches = []; + this.timeStamp = -1; + } + + touchStart(ev, index) { + this.index = index; + this.scrollY = window.scrollY; + if (ev.touches) { + this.touches = ev.touches; + } + this.timeStamp = ev.timeStamp; + } + + mouseDown(ev, index) { + this.index = index; + this.scrollY = window.scrollY; + this.touches = []; + this.timeStamp = ev.timeStamp; + } + + clickType(ev, index) { + if (this.timeStamp < 0) { + return InputInvalid; + } + + if (ev.changedTouches && ev.changedTouches.length === 1) { + if (this.touches.length !== 1) { + return InputInvalid; + } + + if ( + this.touches[0].screenX !== ev.changedTouches[0].screenX || + this.touches[0].screenY !== ev.changedTouches[0].screenY + ) { + return InputInvalid; + } + } + + if (this.index !== index || this.scrollY - window.scrollY !== 0) { + return InputInvalid; + } + + const clickDuration = ev.timeStamp - this.timeStamp; + + if (clickDuration > 0 && clickDuration < 200) { + return ClickShort; + } else if (clickDuration > 400) { + return ClickLong; + } + + return InputInvalid; + } + + eval(ev, index) { + const result = this.clickType(ev, index); + this.reset(); + return result; + } +} + +export default Input; diff --git a/frontend/src/component/photo/cards.vue b/frontend/src/component/photo/cards.vue index 6b7d06cb8..224722efc 100644 --- a/frontend/src/component/photo/cards.vue +++ b/frontend/src/component/photo/cards.vue @@ -40,9 +40,9 @@ :transition="false" aspect-ratio="1" class="accent lighten-2 clickable" - @touchstart="onMouseDown($event, index)" - @touchend.stop.prevent="onClick($event, index)" - @mousedown="onMouseDown($event, index)" + @touchstart="input.touchStart($event, index)" + @touchend.prevent="onClick($event, index)" + @mousedown="input.mouseDown($event, index)" @click.stop.prevent="onClick($event, index)" @mouseover="playLive(photo)" @mouseleave="pauseLive(photo)" @@ -56,10 +56,10 @@ + @click.stop.prevent="onOpen($event, index, true)"> photo_camera $vuetify.icons.live_photo play_arrow @@ -68,19 +68,19 @@ + @click.stop.prevent="onOpen($event, index, false)"> zoom_in + @click.stop.prevent="onOpen($event, index, true)"> play_arrow @@ -93,8 +93,8 @@ check_circle @@ -104,7 +104,7 @@ @@ -192,7 +192,8 @@