Add top overlay with title and current hour

This adds Kodi-like semi-transparent overlay with current media title, hour and estimated time when video will end. The overlay is visible only on fullscreen mode.
This commit is contained in:
Rafostar
2020-09-15 21:08:46 +02:00
parent 779796c2c3
commit 73e7f1e2a0
4 changed files with 133 additions and 22 deletions

View File

@@ -6,7 +6,7 @@
- [X] Switching video/audio/subtitles tracks from bottom bar (MPV)
- [X] Over-amplification supported by default (VLC)
- [X] Audio visualizations (VLC)
- [ ] Clock with current hour and "Ends at" time on top overlay (Kodi)
- [X] Clock with current hour and "Ends at" time on top overlay (Kodi)
- [ ] Auto select subtitles matching OS language (Totem)
- [ ] Picture-in-Picture mode window
- [ ] Touch gestures/swipes support

View File

@@ -70,8 +70,24 @@ var App = GObject.registerClass({
this.hideControlsTimeout = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 3, () => {
this.hideControlsTimeout = null;
if(this.window.isFullscreen && this.isCursorInPlayer)
if(this.window.isFullscreen && this.isCursorInPlayer) {
this.clearTimeout('updateTime');
this.interface.revealControls(false);
}
return GLib.SOURCE_REMOVE;
});
}
setUpdateTimeInterval()
{
this.clearTimeout('updateTime');
let nextUpdate = this.interface.updateTime();
this.updateTimeTimeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, nextUpdate, () => {
this.updateTimeTimeout = null;
if(this.window.isFullscreen)
this.setUpdateTimeInterval();
return GLib.SOURCE_REMOVE;
});
@@ -84,6 +100,9 @@ var App = GObject.registerClass({
GLib.source_remove(this[`${name}Timeout`]);
this[`${name}Timeout`] = null;
if(name === 'updateTime')
debug('cleared update time interval');
}
_buildUI()
@@ -146,6 +165,9 @@ var App = GObject.registerClass({
this.player.connect('error', this._onPlayerError.bind(this));
this.player.connect('state-changed', this._onPlayerStateChanged.bind(this));
this.interface.revealerTop.connect(
'button-press-event', this._onPlayerButtonPressEvent.bind(this)
);
this.player.connectWidget(
'button-press-event', this._onPlayerButtonPressEvent.bind(this)
);
@@ -177,12 +199,15 @@ var App = GObject.registerClass({
this.interface.controls.setVolumeMarks(false);
if(isFullscreen) {
this.setUpdateTimeInterval();
this.interface.showControls(true);
this.setHideControlsTimeout();
this.interface.controls.unfullscreenButton.set_sensitive(true);
this.interface.controls.unfullscreenButton.show();
}
else {
this.clearTimeout('updateTime');
this.interface.showControls(false);
this.interface.controls.unfullscreenButton.set_sensitive(false);
this.interface.controls.unfullscreenButton.hide();
}
@@ -308,7 +333,7 @@ var App = GObject.registerClass({
this._handlePrimaryButtonPress(event, button);
break;
case Gdk.BUTTON_SECONDARY:
if(event.get_event_type() !== Gdk.EventType.DOUBLE_BUTTON_PRESS)
if(event.get_event_type() === Gdk.EventType.BUTTON_PRESS)
this.player.toggle_play();
break;
default:
@@ -360,8 +385,11 @@ var App = GObject.registerClass({
this.setHideCursorTimeout();
if(this.window.isFullscreen) {
if(!this.interface.revealerTop.get_reveal_child()) {
this.setUpdateTimeInterval();
this.interface.revealControls(true);
}
this.setHideControlsTimeout();
this.interface.revealControls(true);
}
else if(this.hideControlsTimeout) {
this.clearTimeout('hideControls');

View File

@@ -1,4 +1,4 @@
const { GLib, GObject, Gtk, Gst, GstPlayer } = imports.gi;
const { Gdk, GLib, GObject, Gtk, Gst, GstPlayer } = imports.gi;
const { Controls } = imports.clapper_src.controls;
const Debug = imports.clapper_src.debug;
@@ -26,23 +26,64 @@ class ClapperInterface extends Gtk.Grid
this.headerBar = null;
this.defaultTitle = null;
let initTime = GLib.DateTime.new_now_local().format('%X');
this.timeFormat = (initTime.length > 8)
? '%I:%M %p'
: '%H:%M';
this.videoBox = new Gtk.Box();
this.overlay = new Gtk.Overlay();
this.revealer = new Gtk.Revealer({
this.revealerTop = new Gtk.Revealer({
transition_duration: this.revealTime,
transition_type: Gtk.RevealerTransitionType.CROSSFADE,
valign: Gtk.Align.START,
});
this.revealerBottom = new Gtk.Revealer({
transition_duration: this.revealTime,
transition_type: Gtk.RevealerTransitionType.SLIDE_UP,
valign: Gtk.Align.END,
});
this.revealerBox = new Gtk.Box();
this.revealerGridTop = new Gtk.Grid();
this.revealerBoxBottom = new Gtk.Box();
this.controls = new Controls();
this.fsTitle = new Gtk.Label({
expand: true,
margin_left: 12,
xalign: 0,
yalign: 0.22,
});
let timeLabelOpts = {
margin_right: 10,
xalign: 1,
yalign: 0,
};
this.fsTime = new Gtk.Label(timeLabelOpts);
this.fsEndTime = new Gtk.Label(timeLabelOpts);
this.revealerGridTop.attach(this.fsTitle, 0, 0, 1, 1);
this.revealerGridTop.attach(this.fsTime, 1, 0, 1, 1);
this.revealerGridTop.attach(this.fsEndTime, 1, 0, 1, 1);
this.videoBox.get_style_context().add_class('videobox');
this.revealerBox.get_style_context().add_class('osd');
let revealerGridTopContext = this.revealerGridTop.get_style_context();
revealerGridTopContext.add_class('osd');
revealerGridTopContext.add_class('reavealertop');
this.revealerBoxBottom.get_style_context().add_class('osd');
this.fsTime.get_style_context().add_class('osdtime');
this.fsEndTime.get_style_context().add_class('osdendtime');
this.videoBox.pack_start(this.overlay, true, true, 0);
this.revealer.add(this.revealerBox);
this.revealerBottom.add(this.revealerBoxBottom);
this.revealerTop.add(this.revealerGridTop);
this.attach(this.videoBox, 0, 0, 1, 1);
this.attach(this.controls, 0, 1, 1, 1);
this.revealerTop.add_events(Gdk.EventMask.BUTTON_PRESS_MASK);
this.revealerTop.show_all();
this.revealerBottom.show_all();
}
addPlayer(player)
@@ -89,16 +130,18 @@ class ClapperInterface extends Gtk.Grid
revealControls(isReveal)
{
this.revealer.set_transition_duration(this.revealTime);
this.revealer.set_transition_type(Gtk.RevealerTransitionType.SLIDE_UP);
this.revealer.set_reveal_child(isReveal);
for(let pos of ['Bottom', 'Top']) {
this[`revealer${pos}`].set_transition_duration(this.revealTime);
this[`revealer${pos}`].set_reveal_child(isReveal);
}
}
showControls(isShow)
{
this.revealer.set_transition_duration(0);
this.revealer.set_transition_type(Gtk.RevealerTransitionType.NONE);
this.revealer.set_reveal_child(isShow);
for(let pos of ['Bottom', 'Top']) {
this[`revealer${pos}`].set_transition_duration(0);
this[`revealer${pos}`].set_reveal_child(isShow);
}
}
setControlsOnVideo(isOnVideo)
@@ -109,17 +152,16 @@ class ClapperInterface extends Gtk.Grid
if(isOnVideo) {
this.remove(this.controls);
this.controls.pack_start(this.controls.unfullscreenButton.box, false, false, 0);
this.overlay.add_overlay(this.revealer);
this.revealerBox.pack_start(this.controls, false, true, 0);
this.revealer.show();
this.revealerBox.show();
this.overlay.add_overlay(this.revealerBottom);
this.overlay.add_overlay(this.revealerTop);
this.revealerBoxBottom.pack_start(this.controls, false, true, 0);
}
else {
this.revealerBox.remove(this.controls);
this.revealerBoxBottom.remove(this.controls);
this.controls.remove(this.controls.unfullscreenButton.box);
this.overlay.remove(this.revealer);
this.overlay.remove(this.revealerBottom);
this.overlay.remove(this.revealerTop);
this.attach(this.controls, 0, 1, 1, 1);
this.controls.show();
}
this.controlsInVideo = isOnVideo;
@@ -253,6 +295,27 @@ class ClapperInterface extends Gtk.Grid
this.headerBar.set_title(title);
this.headerBar.set_subtitle(subtitle);
this.fsTitle.label = title;
}
updateTime()
{
let currTime = GLib.DateTime.new_now_local();
let endTime = currTime.add_seconds(
this.controls.positionAdjustment.get_upper() - this.lastPositionValue
);
let now = currTime.format(this.timeFormat);
this.fsTime.set_label(now);
this.fsEndTime.set_label(`Ends at: ${endTime.format(this.timeFormat)}`);
// Make sure that next timeout is always run after clock changes,
// by delaying it for additional few milliseconds
let nextUpdate = 60002 - parseInt(currTime.get_seconds() * 1000);
debug(`updated current time: ${now}`);
return nextUpdate;
}
showVisualizationsButton(isShow)
@@ -444,6 +507,9 @@ class ClapperInterface extends Gtk.Grid
this.lastPositionValue = positionSeconds;
this._player.seek_seconds(positionSeconds);
if(this.controls.fullscreenMode)
this.updateTime();
}
_onControlsVolumeChanged(volumeScale)

View File

@@ -24,6 +24,23 @@ scale marks {
.videobox {
background: black;
}
.reavealertop {
min-height: 100px;
box-shadow: inset 0px 200px 10px -124px rgba(0,0,0,0.4);
font-size: 32px;
font-weight: 500;
background: transparent;
}
.osdtime {
margin-top: 0px;
font-size: 40px;
font-weight: 700;
}
.osdendtime {
margin-top: 42px;
font-size: 24px;
font-weight: 600;
}
/* Position Scale */
.positionscale value {