Allow pausing ongoing modal slideshow

Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
This commit is contained in:
John Molakvoæ (skjnldsv) 2019-08-07 12:34:12 +02:00
Родитель 0ca9f5edb7
Коммит 04ef5ee3a3
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 60C25B8C072916CF
3 изменённых файлов: 145 добавлений и 33 удалений

Просмотреть файл

@ -20,7 +20,13 @@ module.exports = {
'selector-type-case': null,
'selector-list-comma-newline-after': null,
'no-descending-specificity': null,
'string-quotes': 'single'
'string-quotes': 'single',
'selector-pseudo-element-no-unknown': [
true,
{
ignorePseudoElements: ['v-deep']
}
]
},
plugins: ['stylelint-scss']
}
};

Просмотреть файл

@ -80,6 +80,7 @@ export default {
<!-- Play-pause toggle -->
<button v-if="hasNext && enableSlideshow"
v-tooltip.auto="playPauseTitle"
:class="{ 'play-pause--paused': slideshowPaused }"
class="play-pause"
@click="togglePlayPause">
<!-- Progress circle, css animated -->
@ -90,7 +91,8 @@ export default {
</div>
<!-- Progress circle, css animated -->
<svg v-if="playing" class="progress-ring"
<svg v-if="playing"
class="progress-ring"
height="50" width="50">
<circle class="progress-ring__circle"
stroke="white" stroke-width="2" fill="transparent"
@ -162,6 +164,7 @@ import Hammer from 'hammerjs'
import Actions from 'Components/Actions'
import ActionButton from 'Components/ActionButton'
import Tooltip from 'Directives/Tooltip'
import Timer from 'Utils/Timer'
export default {
name: 'Modal',
@ -222,6 +225,13 @@ export default {
type: Number,
default: 3000
},
/**
* Allow to pause an ongoing slideshow
*/
slideshowPaused: {
type: Boolean,
default: false
},
/**
* Enable swipe between slides
*/
@ -269,6 +279,21 @@ export default {
}
},
watch: {
/**
* Handle play/pause of an ongoing slideshow
*/
slideshowPaused: function(paused) {
if (this.slideshowTimeout) {
if (paused) {
this.slideshowTimeout.pause()
} else {
this.slideshowTimeout.start()
}
}
}
},
beforeMount() {
window.addEventListener('keydown', this.handleKeydown)
},
@ -379,7 +404,7 @@ export default {
if (this.playing) {
this.handleSlideshow()
} else {
clearTimeout(this.slideshowTimeout)
this.slideshowTimeout.clear()
}
},
@ -388,7 +413,7 @@ export default {
*/
resetSlideshow() {
this.playing = !this.playing
clearTimeout(this.slideshowTimeout)
this.slideshowTimeout.clear()
this.$nextTick(function() {
this.togglePlayPause()
})
@ -400,13 +425,13 @@ export default {
handleSlideshow() {
this.playing = true
if (this.hasNext) {
this.slideshowTimeout = setTimeout(() => {
this.slideshowTimeout = new Timer(() => {
this.next()
this.handleSlideshow()
}, this.slideshowDelay)
} else {
this.playing = false
clearTimeout(this.slideshowTimeout)
this.slideshowTimeout.clear()
}
}
}
@ -538,6 +563,15 @@ $header-size: 50px;
background-position: center;
background-size: 22px;
}
&::v-deep .action-item__menutoggle {
padding: 13px 11px;
// force white instead of default main text
color: #fff;
// 22px is a somehow better looking for the icon-more icon
font-size: 22px;
}
}
}
@ -682,37 +716,36 @@ $header-size: 50px;
transform: scale(1.1);
}
</style>
<style lang="scss">
// we cannot scope sub-components
.modal-mask[data-v-#{$scope_version}] .modal-header .icons-menu {
.action-item__menutoggle {
padding: 13px 11px;
// force white instead of default main text
color: #fff;
// 22px is a somehow better looking for the icon-more icon
font-size: 22px;
}
}
// animated circle
$radius: 15;
$pi: 3.14159265358979;
// animated circle
.modal-mask[data-v-#{$scope_version}] .progress-ring {
position: absolute;
top: 0;
left: 0;
transform: rotate(-90deg);
.progress-ring__circle {
transition: 100ms stroke-dashoffset;
transform-origin: 50% 50%; // axis compensation
animation: progressring linear 3s infinite;
stroke-linecap: round;
stroke-dashoffset: $radius * 2 * $pi; // radius * 2 * PI
stroke-dasharray: $radius * 2 * $pi; // radius * 2 * PI
.modal-mask .play-pause {
.progress-ring {
position: absolute;
top: 0;
left: 0;
transform: rotate(-90deg);
.progress-ring__circle {
transition: 100ms stroke-dashoffset;
transform-origin: 50% 50%; // axis compensation
animation: progressring linear 3s infinite;
stroke-linecap: round;
stroke-dashoffset: $radius * 2 * $pi; // radius * 2 * PI
stroke-dasharray: $radius * 2 * $pi; // radius * 2 * PI
}
}
&--paused {
.icon-pause {
animation: breath 2s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
.progress-ring__circle {
animation-play-state: paused !important;
}
}
}
// keyframes get scoped too and break the animation name, we need them unscoped
@keyframes progressring {
from {
@ -723,4 +756,16 @@ $pi: 3.14159265358979;
}
}
@keyframes breath {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
</style>

61
src/utils/Timer.js Normal file
Просмотреть файл

@ -0,0 +1,61 @@
/**
* @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
export default function timer(callback, delay) {
let id
let started
let remaining = delay
let running
this.start = function() {
running = true
started = new Date()
id = setTimeout(callback, remaining)
}
this.pause = function() {
running = false
clearTimeout(id)
remaining -= new Date() - started
}
this.clear = function() {
running = false
clearTimeout(id)
remaining = 0
}
this.getTimeLeft = function() {
if (running) {
this.pause()
this.start()
}
return remaining
}
this.getStateRunning = function() {
return running
}
this.start()
}