diff --git a/src/scss/skin-super-modern/_mixins.scss b/src/scss/skin-super-modern/_mixins.scss index 2e8ac6d34..7bf444b62 100644 --- a/src/scss/skin-super-modern/_mixins.scss +++ b/src/scss/skin-super-modern/_mixins.scss @@ -120,11 +120,7 @@ } @mixin svg-icon-shadow { - filter: drop-shadow(0 0 1px $color-primary); -} - -@mixin svg-icon-on-shadow { - filter: drop-shadow(0 0 1px $color-highlight); + filter: drop-shadow(0 0 .25px $color-primary); } @mixin seekbar-position-marker($marker-dimension) { diff --git a/src/scss/skin-super-modern/_skin-modern-smallscreen.scss b/src/scss/skin-super-modern/_skin-modern-smallscreen.scss index 5df867f85..18460ee0c 100644 --- a/src/scss/skin-super-modern/_skin-modern-smallscreen.scss +++ b/src/scss/skin-super-modern/_skin-modern-smallscreen.scss @@ -2,6 +2,7 @@ @import 'mixins'; &.#{$prefix}-ui-skin-modern-smallscreen { + .#{$prefix}-ui-fullscreentogglebutton { background-image: url('../../assets/skin-super-modern/images/fullscreensmall.svg'); diff --git a/src/scss/skin-super-modern/_variables.scss b/src/scss/skin-super-modern/_variables.scss index bba9b643f..2430b3625 100644 --- a/src/scss/skin-super-modern/_variables.scss +++ b/src/scss/skin-super-modern/_variables.scss @@ -15,6 +15,8 @@ $color-focus: #1b7fcc; $color-item-hover: #54565a !default; $color-background-menu: #212226 !default; +$color-background-seek-circle: rgba(124, 124, 124, .35) !default; +$color-shadow-seek-label: 0 0 30px 0 rgba(0, 0, 0, .75) !default; $font-family: sans-serif !default; $font-size: 1em !default; diff --git a/src/scss/skin-super-modern/components/_button.scss b/src/scss/skin-super-modern/components/_button.scss index 108a574ed..5da696ccd 100644 --- a/src/scss/skin-super-modern/components/_button.scss +++ b/src/scss/skin-super-modern/components/_button.scss @@ -15,6 +15,7 @@ height: 1.5em; min-width: 1.5em; padding: .25em; + transition: transform .15s ease; .#{$prefix}-label { color: $color-primary; @@ -36,6 +37,10 @@ } } + &:active { + transform: scale(.9); + } + @include hidden; @include focusable; } diff --git a/src/scss/skin-super-modern/components/_settingstogglebutton.scss b/src/scss/skin-super-modern/components/_settingstogglebutton.scss index be3d494bc..889daaa23 100644 --- a/src/scss/skin-super-modern/components/_settingstogglebutton.scss +++ b/src/scss/skin-super-modern/components/_settingstogglebutton.scss @@ -7,12 +7,6 @@ &:hover { @include svg-icon-shadow; } - - &.#{$prefix}-on { - &:hover { - @include svg-icon-on-shadow; - } - } } .#{$prefix}-ui-settingstogglebutton { diff --git a/src/scss/skin-super-modern/components/_smallcenteredplaybacktogglebutton.scss b/src/scss/skin-super-modern/components/_smallcenteredplaybacktogglebutton.scss index efabe66da..f63de66a5 100644 --- a/src/scss/skin-super-modern/components/_smallcenteredplaybacktogglebutton.scss +++ b/src/scss/skin-super-modern/components/_smallcenteredplaybacktogglebutton.scss @@ -3,47 +3,16 @@ .#{$prefix}-ui-smallcenteredplaybacktogglebutton { @extend %ui-button; - @keyframes #{$prefix}-fade-out { - from { - opacity: 1; - visibility: visible; - } - - to { - opacity: 0; - transform: scale(2); - visibility: hidden; - } - } - - @keyframes #{$prefix}-fade-in { - from { - opacity: 0; - transform: scale(2); - visibility: visible; - } - - to { - opacity: 1; - } - } - - @keyframes #{$prefix}-breathe { - 30% { - transform: scale(1.1); - } - - 60% { - transform: scale(1); - } - } - cursor: default; height: 2.5em; outline: none; overflow: hidden; // hide overflow from scale animation width: 2.5em; + &:hover { + @include svg-icon-shadow; + } + .#{$prefix}-image { background-position: center; background-repeat: no-repeat; diff --git a/src/scss/skin-super-modern/components/_touch-control-overlay.scss b/src/scss/skin-super-modern/components/_touch-control-overlay.scss index 7d7a526f7..7e30a6d39 100644 --- a/src/scss/skin-super-modern/components/_touch-control-overlay.scss +++ b/src/scss/skin-super-modern/components/_touch-control-overlay.scss @@ -1,6 +1,36 @@ @import '../variables'; @import '../mixins'; +// sass-lint:disable no-vendor-prefixes +%opacity-transition { + -moz-transition: opacity .25s ease; + -ms-transition: opacity .25s ease; + -o-transition: opacity .25s ease; + -webkit-transition: opacity .25s ease; + transition: opacity .25s ease-out; +} + +%seek-circle { + @extend %opacity-transition; + background-color: $color-background-seek-circle; + border-radius: 50%; + content: ''; + height: 200%; + opacity: 0; + position: absolute; + width: 100%; +} + +%seek-label { + @extend %opacity-transition; + font-size: .4em; + font-weight: 600; + margin: 0; + opacity: 1; + position: absolute; + text-shadow: $color-shadow-seek-label; +} + .#{$prefix}-ui-touchcontrol-overlay { @extend %ui-container; @include layout-cover; @@ -9,4 +39,50 @@ display: flex; justify-content: center; text-align: center; + + // sass-lint:disable nesting-depth + > .#{$prefix}-container-wrapper { + align-items: center; + display: flex; + + .#{$prefix}-seek-forward-label { + @extend %seek-label; + right: 15%; + + &.#{$prefix}-hidden { + opacity: 0; + } + } + + .#{$prefix}-seek-backward-label { + @extend %seek-label; + left: 15%; + + &.#{$prefix}-hidden { + opacity: 0; + } + } + } + + &::before { + @extend %seek-circle; + left: -60%; + } + + &::after { + @extend %seek-circle; + right: -60%; + } + + &.#{$prefix}-seek-forward { + &::after { + opacity: 1; + } + } + + &.#{$prefix}-seek-backward { + &::before { + opacity: 1; + } + } } diff --git a/src/ts/components/touchcontroloverlay.ts b/src/ts/components/touchcontroloverlay.ts index 76c599dd8..461627fa7 100644 --- a/src/ts/components/touchcontroloverlay.ts +++ b/src/ts/components/touchcontroloverlay.ts @@ -5,6 +5,8 @@ import { UIInstanceManager } from '../uimanager'; import { EventDispatcher, NoArgs, Event as EDEvent } from '../eventdispatcher'; import { Timeout } from '../timeout'; import { HTMLElementWithComponent } from '../dom'; +import { Label, LabelConfig } from './label'; +import { i18n } from '../localization/i18n'; export interface TouchControlOverlayConfig extends ContainerConfig { /** @@ -46,6 +48,8 @@ interface ClickPosition { * Overlays the player and detects touch input */ export class TouchControlOverlay extends Container { + private readonly SEEK_FORWARD_CLASS = 'seek-forward'; + private readonly SEEK_BACKWARD_CLASS = 'seek-backward'; private touchControlEvents = { onSingleClick: new EventDispatcher(), @@ -55,6 +59,8 @@ export class TouchControlOverlay extends Container { }; private playbackToggleButton: SmallCenteredPlaybackToggleButton; + private seekForwardLabel: Label; + private seekBackwardLabel: Label; // true if the last tap on the overlay was less than 500msec ago private couldBeDoubleTapping: Boolean; @@ -69,20 +75,28 @@ export class TouchControlOverlay extends Container { enterFullscreenOnInitialPlayback: Boolean(config.enterFullscreenOnInitialPlayback), }); + this.seekForwardLabel = new Label({text: '', for: this.getConfig().id, cssClass: 'seek-forward-label', hidden: true}); + this.seekBackwardLabel = new Label({text: '', for: this.getConfig().id, cssClass: 'seek-backward-label', hidden: true}); + this.config = this.mergeConfig(config, { cssClass: 'ui-touchcontrol-overlay', acceptsTouchWithUiHidden: true, seekTime: 10, seekDoubleTapMargin: 15, - components: [this.playbackToggleButton], + components: [this.playbackToggleButton, this.seekForwardLabel, this.seekBackwardLabel], }, this.config); } configure(player: PlayerAPI, uimanager: UIInstanceManager): void { super.configure(player, uimanager); + let playerSeekTime = 0; + let startSeekTime = 0; + this.doubleTapTimeout = new Timeout(500, () => { this.couldBeDoubleTapping = false; + startSeekTime = 0; + setTimeout(() => this.hideSeekAnimationElements(), 150); }); uimanager.onControlsHide.subscribe(() => { @@ -93,21 +107,33 @@ export class TouchControlOverlay extends Container { this.playbackToggleButton.show(); }); - let playerSeekTime = 0; this.touchControlEvents.onSeekBackward.subscribe(() => { playerSeekTime -= this.config.seekTime; player.seek(playerSeekTime); + + this.seekBackwardLabel.setText(Math.abs(Math.round(playerSeekTime - startSeekTime)) + ' ' + i18n.performLocalization(i18n.getLocalizer('settings.time.seconds'))); + this.seekBackwardLabel.show(); + this.getDomElement().addClass(this.prefixCss(this.SEEK_BACKWARD_CLASS)); + this.seekForwardLabel.hide(); + this.getDomElement().removeClass(this.prefixCss(this.SEEK_FORWARD_CLASS)); }); this.touchControlEvents.onSeekForward.subscribe(() => { playerSeekTime += this.config.seekTime; player.seek(playerSeekTime); + + this.seekForwardLabel.setText(Math.abs(Math.round(playerSeekTime - startSeekTime)) + ' ' + i18n.performLocalization(i18n.getLocalizer('settings.time.seconds'))); + this.seekForwardLabel.show(); + this.getDomElement().addClass(this.prefixCss(this.SEEK_FORWARD_CLASS)); + this.seekBackwardLabel.hide(); + this.getDomElement().removeClass(this.prefixCss(this.SEEK_BACKWARD_CLASS)); }); this.touchControlEvents.onSingleClick.subscribe((_, e) => { uimanager.getUI().toggleUiShown(); playerSeekTime = player.getCurrentTime(); + startSeekTime = playerSeekTime; const eventTarget = (e as Event).target as HTMLElementWithComponent; const rect = eventTarget.getBoundingClientRect(); @@ -158,6 +184,13 @@ export class TouchControlOverlay extends Container { }; } + private hideSeekAnimationElements(): void { + this.getDomElement().removeClass(this.prefixCss(this.SEEK_FORWARD_CLASS)); + this.getDomElement().removeClass(this.prefixCss(this.SEEK_BACKWARD_CLASS)); + this.seekForwardLabel.hide(); + this.seekBackwardLabel.hide(); + } + protected onDoubleClickEvent(e: Event) { this.touchControlEvents.onDoubleClick.dispatch(this, e); }