diff --git a/src/buttons.js b/src/buttons.js index 73b1c04b..00026eba 100644 --- a/src/buttons.js +++ b/src/buttons.js @@ -45,7 +45,11 @@ class ClapperCustomButton extends Gtk.Button return; const clapperWidget = this.get_ancestor(Gtk.Grid); - clapperWidget._setHideControlsTimeout(); + clapperWidget.revealControls(); + + /* Button opens a popover */ + if(this.popoverBox) + clapperWidget.isPopoverOpen = true; } }); @@ -124,8 +128,15 @@ class ClapperPopoverButtonBase extends CustomButton _onClosed() { - const { player } = this.get_ancestor(Gtk.Grid); - player.widget.grab_focus(); + const clapperWidget = this.get_ancestor(Gtk.Grid); + + clapperWidget.player.widget.grab_focus(); + + /* Set again timeout as popover is now closed */ + if(clapperWidget.isFullscreenMode) + clapperWidget.revealControls(); + + clapperWidget.isPopoverOpen = false; this.unset_state_flags(Gtk.StateFlags.CHECKED); } diff --git a/src/controls.js b/src/controls.js index 33300958..43d76ade 100644 --- a/src/controls.js +++ b/src/controls.js @@ -106,8 +106,8 @@ class ClapperControls extends Gtk.Box for(let button of this.buttonsArr) button.setFullscreenMode(isFullscreen); - this.unfullscreenButton.set_visible(isFullscreen); - this.set_can_focus(isFullscreen); + this.unfullscreenButton.visible = isFullscreen; + this.can_focus = isFullscreen; } setLiveMode(isLive, isSeekable) @@ -593,25 +593,33 @@ class ClapperControls extends Gtk.Box { const isPositionDragging = scale.has_css_class('dragging'); - if((this.isPositionDragging = isPositionDragging)) + if(this.isPositionDragging === isPositionDragging) return; - const isChapterSeek = this.chapterPopover.visible; - - if(!isPositionDragging) - this._setChapterVisible(false); - const clapperWidget = this.get_ancestor(Gtk.Grid); if(!clapperWidget) return; + if(clapperWidget.isFullscreenMode) { + clapperWidget.revealControls(); + + if(isPositionDragging) + clapperWidget._clearTimeout('hideControls'); + } + + if((this.isPositionDragging = isPositionDragging)) + return; + const scaleValue = scale.get_value(); + const isChapterSeek = this.chapterPopover.visible; if(!isChapterSeek) { const positionSeconds = Math.round(scaleValue); clapperWidget.player.seek_seconds(positionSeconds); } - else + else { clapperWidget.player.seek_chapter(scaleValue); + this._setChapterVisible(false); + } } /* Only happens when navigating through controls panel */ diff --git a/src/player.js b/src/player.js index ee7d7a16..e7c078d2 100644 --- a/src/player.js +++ b/src/player.js @@ -434,11 +434,8 @@ class ClapperPlayer extends PlayerBase bool = true; case Gdk.KEY_Left: this.adjust_position(bool); - clapperWidget._clearTimeout('hideControls'); - if(this.keyPressCount > 1) { - clapperWidget.revealerBottom.set_can_focus(false); - clapperWidget.revealerBottom.revealChild(true); - } + if(this.keyPressCount > 1) + clapperWidget.revealControls(); break; default: break; @@ -458,10 +455,8 @@ class ClapperPlayer extends PlayerBase this.toggle_play(); break; case Gdk.KEY_Return: - if(clapperWidget.isFullscreenMode) { + if(clapperWidget.isFullscreenMode) clapperWidget.revealControls(true); - clapperWidget._setHideControlsTimeout(); - } break; case Gdk.KEY_Right: case Gdk.KEY_Left: diff --git a/src/revealers.js b/src/revealers.js index 634542b4..d05824aa 100644 --- a/src/revealers.js +++ b/src/revealers.js @@ -4,8 +4,6 @@ const Debug = imports.src.debug; const DBus = imports.src.dbus; const Misc = imports.src.misc; -const REVEAL_TIME = 800; - const { debug } = Debug; const { settings } = Misc; @@ -19,6 +17,7 @@ class ClapperCustomRevealer extends Gtk.Revealer const defaults = { visible: false, can_focus: false, + transition_duration: 800, }; Object.assign(opts, defaults); @@ -33,35 +32,9 @@ class ClapperCustomRevealer extends Gtk.Revealer revealChild(isReveal) { if(isReveal) - this.set_visible(isReveal); + this.visible = true; - /* Restore focus ability after we are done */ - if(!isReveal) this.set_can_focus(true); - - this._timedReveal(isReveal, REVEAL_TIME); - } - - showChild(isReveal) - { - this.set_visible(isReveal); - this._timedReveal(isReveal, 0); - } - - set_visible(isVisible) - { - if(this.visible === isVisible) - return false; - - super.set_visible(isVisible); - debug(`${this.revealerName} revealer visible: ${isVisible}`); - - return true; - } - - _timedReveal(isReveal, time) - { - this.set_transition_duration(time); - this.set_reveal_child(isReveal); + this.reveal_child = isReveal; } }); @@ -71,7 +44,6 @@ class ClapperRevealerTop extends CustomRevealer _init() { super._init({ - transition_duration: REVEAL_TIME, transition_type: Gtk.RevealerTransitionType.CROSSFADE, valign: Gtk.Align.START, }); @@ -125,9 +97,14 @@ class ClapperRevealerTop extends CustomRevealer this.set_child(revealerBox); } - setMediaTitle(title) + set title(text) { - this.mediaTitle.label = title; + this.mediaTitle.label = text; + } + + get title() + { + return this.mediaTitle.label; } setTimes(currTime, endTime) @@ -154,7 +131,6 @@ class ClapperRevealerBottom extends CustomRevealer _init() { super._init({ - transition_duration: REVEAL_TIME, transition_type: Gtk.RevealerTransitionType.SLIDE_UP, valign: Gtk.Align.END, }); @@ -164,6 +140,10 @@ class ClapperRevealerBottom extends CustomRevealer this.revealerBox.add_css_class('osd'); this.set_child(this.revealerBox); + + const motionController = new Gtk.EventControllerMotion(); + motionController.connect('motion', this._onMotion.bind(this)); + this.add_controller(motionController); } append(widget) @@ -176,34 +156,10 @@ class ClapperRevealerBottom extends CustomRevealer this.revealerBox.remove(widget); } - set_visible(isVisible) + _onMotion(controller, x, y) { - const isChange = super.set_visible(isVisible); - if(!isChange || !this.can_focus) return; - - const parent = this.get_parent(); - const playerWidget = parent.get_first_child(); - if(!playerWidget) return; - - if(isVisible) { - const box = this.get_first_child(); - if(!box) return; - - const controls = box.get_first_child(); - if(!controls) return; - - const togglePlayButton = controls.get_first_child(); - if(togglePlayButton) { - togglePlayButton.grab_focus(); - debug('focus moved to toggle play button'); - } - playerWidget.set_can_focus(false); - } - else { - playerWidget.set_can_focus(true); - playerWidget.grab_focus(); - debug('focus moved to player widget'); - } + const clapperWidget = this.root.child; + clapperWidget._clearTimeout('hideControls'); } }); diff --git a/src/widget.js b/src/widget.js index 4c21e922..89cbc126 100644 --- a/src/widget.js +++ b/src/widget.js @@ -30,14 +30,17 @@ class ClapperWidget extends Gtk.Grid this.isSeekable = false; this.isMobileMonitor = false; - this.dragAllowed = false; - this.cursorInPlayer = false; - this.isWidgetDragging = false; + this.isDragAllowed = false; + this.isSwipePerformed = false; + + this.isCursorInPlayer = false; + this.isPopoverOpen = false; this._hideControlsTimeout = null; this._updateTimeTimeout = null; this.needsTracksUpdate = true; + this.needsCursorRestore = false; this.overlay = new Gtk.Overlay(); this.revealerTop = new Revealers.RevealerTop(); @@ -86,6 +89,11 @@ class ClapperWidget extends Gtk.Grid const dragGestureTop = this._getDragGesture(); this.revealerTop.add_controller(dragGestureTop); + const swipeGesture = this._getSwipeGesture(); + playerWidget.add_controller(swipeGesture); + const swipeGestureTop = this._getSwipeGesture(); + this.revealerTop.add_controller(swipeGestureTop); + const scrollController = this._getScrollController(); playerWidget.add_controller(scrollController); const scrollControllerTop = this._getScrollController(); @@ -102,16 +110,15 @@ class ClapperWidget extends Gtk.Grid this.revealerTop.add_controller(dropTargetTop); } - revealControls(isReveal) + revealControls(isAllowInput) { - for(let pos of ['Top', 'Bottom']) - this[`revealer${pos}`].revealChild(isReveal); - } + this.revealerTop.revealChild(true); + this.revealerBottom.revealChild(true); - showControls(isShow) - { - for(let pos of ['Top', 'Bottom']) - this[`revealer${pos}`].showChild(isShow); + if(isAllowInput) + this.setControlsCanFocus(true); + + this._setHideControlsTimeout(); } toggleFullscreen() @@ -138,15 +145,16 @@ class ClapperWidget extends Gtk.Grid if(!this.isMobileMonitor) root[action + '_css_class']('tvmode'); - this._changeControlsPlacement(isFullscreen); + if(!isFullscreen) + this._clearTimeout('updateTime'); + this._changeControlsPlacement(isFullscreen); this.controls.setFullscreenMode(isFullscreen); - this.showControls(isFullscreen); this.revealerTop.headerBar.visible = !isFullscreen; this.revealerTop.revealerGrid.visible = (isFullscreen && !this.isMobileMonitor); - this.player.widget.grab_focus(); + this.setControlsCanFocus(false); if(this.player.playOnFullscreen && isFullscreen) { this.player.playOnFullscreen = false; @@ -156,6 +164,18 @@ class ClapperWidget extends Gtk.Grid debug(`interface in fullscreen mode: ${isFullscreen}`); } + setControlsCanFocus(isControlsFocus) + { + this.revealerBottom.can_focus = isControlsFocus; + this.player.widget.can_focus = !isControlsFocus; + + const focusWidget = (isControlsFocus) + ? this.controls.togglePlayButton + : this.player.widget; + + focusWidget.grab_focus(); + } + _changeControlsPlacement(isOnTop) { if(isOnTop) { @@ -299,7 +319,7 @@ class ClapperWidget extends Gtk.Grid } this.root.title = title; - this.revealerTop.setMediaTitle(title); + this.revealerTop.title = title; } updateTime() @@ -586,20 +606,23 @@ class ClapperWidget extends Gtk.Grid _setHideControlsTimeout() { this._clearTimeout('hideControls'); - this._hideControlsTimeout = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 2, () => { + this._hideControlsTimeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 2500, () => { this._hideControlsTimeout = null; - if(this.cursorInPlayer) { + if(this.isCursorInPlayer) { const blankCursor = Gdk.Cursor.new_from_name('none', null); this.player.widget.set_cursor(blankCursor); this.revealerTop.set_cursor(blankCursor); - - if(this.isFullscreenMode) - this._clearTimeout('updateTime'); - - this.revealControls(false); + this.needsCursorRestore = true; } + if(!this.isPopoverOpen) { + this._clearTimeout('updateTime'); + + this.revealerTop.revealChild(false); + this.revealerBottom.revealChild(false); + } + this.setControlsCanFocus(false); return GLib.SOURCE_REMOVE; }); @@ -629,6 +652,7 @@ class ClapperWidget extends Gtk.Grid const clickGesture = new Gtk.GestureClick(); clickGesture.set_button(0); clickGesture.connect('pressed', this._onPressed.bind(this)); + clickGesture.connect('released', this._onReleased.bind(this)); return clickGesture; } @@ -699,7 +723,8 @@ class ClapperWidget extends Gtk.Grid { const button = gesture.get_current_button(); const isDouble = (nPress % 2 == 0); - this.dragAllowed = !isDouble; + this.isDragAllowed = !isDouble; + this.isSwipePerformed = false; switch(button) { case Gdk.BUTTON_PRIMARY: @@ -714,9 +739,16 @@ class ClapperWidget extends Gtk.Grid } } + _onReleased(gesture, nPress, x, y) + { + /* Reveal if touch was not a swipe or was already revealed */ + if(!this.isSwipePerformed || this.revealerBottom.child_revealed) + this.revealControls(); + } + _onDragUpdate(gesture, offsetX, offsetY) { - if(!this.dragAllowed || this.isFullscreenMode) + if(!this.isDragAllowed || this.isFullscreenMode) return; const { gtk_double_click_distance } = this.get_settings(); @@ -742,7 +774,6 @@ class ClapperWidget extends Gtk.Grid winX += nativeX; winY += nativeY; - this.isWidgetDragging = true; native.get_surface().begin_move( gesture.get_device(), gesture.get_current_button(), @@ -761,6 +792,7 @@ class ClapperWidget extends Gtk.Grid return; this._onScroll(gesture, -velocityX, 0); + this.isSwipePerformed = true; } _onSwipeUpdate(gesture, sequence) @@ -774,6 +806,7 @@ class ClapperWidget extends Gtk.Grid const isIncrease = velocityY < 0; this.player.adjust_volume(isIncrease, 0.01); + this.isSwipePerformed = true; } _onScroll(controller, dx, dy) @@ -794,29 +827,20 @@ class ClapperWidget extends Gtk.Grid _onEnter(controller, x, y) { - this.cursorInPlayer = true; - this.isWidgetDragging = false; - - this._setHideControlsTimeout(); + this.isCursorInPlayer = true; } _onLeave(controller) { - this.cursorInPlayer = false; - this._setHideControlsTimeout(250); - - if( - this.isFullscreenMode - || this.isWidgetDragging - ) + if(this.isFullscreenMode) return; - //this.revealerBottom.revealChild(false); + this.isCursorInPlayer = false; } _onMotion(controller, posX, posY) { - this.cursorInPlayer = true; + this.isCursorInPlayer = true; /* GTK4 sometimes generates motions with same coords */ if(this.posX === posX && this.posY === posY) @@ -827,24 +851,21 @@ class ClapperWidget extends Gtk.Grid Math.abs(this.posX - posX) >= 0.5 || Math.abs(this.posY - posY) >= 0.5 ) { - const defaultCursor = Gdk.Cursor.new_from_name('default', null); + if(this.needsCursorRestore) { + const defaultCursor = Gdk.Cursor.new_from_name('default', null); - this.player.widget.set_cursor(defaultCursor); - this.revealerTop.set_cursor(defaultCursor); - - this._setHideControlsTimeout(); - - if(this.isFullscreenMode) { - if(!this._updateTimeTimeout) - this._setUpdateTimeInterval(); + this.player.widget.set_cursor(defaultCursor); + this.revealerTop.set_cursor(defaultCursor); + this.needsCursorRestore = false; } - else if(this._updateTimeTimeout) - this._clearTimeout('updateTime'); + this.revealControls(); - if(!this.revealerTop.get_reveal_child()) { - /* Do not grab controls key focus on mouse movement */ - this.revealerBottom.set_can_focus(false); - this.revealControls(true); + if( + this.isFullscreenMode + && !this.isMobileMonitor + && !this._updateTimeTimeout + ) { + this._setUpdateTimeInterval(); } }