mirror of
https://gitlab.com/futo-org/fcast.git
synced 2025-06-24 21:25:23 +00:00
Receivers: Added image viewer UI
This commit is contained in:
parent
023f1054e1
commit
7e4b5485ea
6 changed files with 419 additions and 122 deletions
|
@ -22,11 +22,13 @@ export class Timer {
|
|||
private delay: number;
|
||||
private startTime: number;
|
||||
private remainingTime: number;
|
||||
public started: boolean;
|
||||
|
||||
constructor(callback: () => void, delay: number, autoStart: boolean = true) {
|
||||
this.handle = null;
|
||||
this.callback = callback;
|
||||
this.delay = delay;
|
||||
this.started = false;
|
||||
|
||||
if (autoStart) {
|
||||
this.start();
|
||||
|
@ -40,6 +42,7 @@ export class Timer {
|
|||
window.clearTimeout(this.handle);
|
||||
}
|
||||
|
||||
this.started = true;
|
||||
this.startTime = Date.now();
|
||||
this.remainingTime = null;
|
||||
this.handle = window.setTimeout(this.callback, this.delay);
|
||||
|
@ -64,6 +67,7 @@ export class Timer {
|
|||
window.clearTimeout(this.handle);
|
||||
this.handle = null;
|
||||
this.remainingTime = null;
|
||||
this.started = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { EventMessage, EventType, KeyEvent, MediaItem, MediaItemEvent, PlaylistContent, PlayMessage, SeekMessage, SetPlaylistItemMessage, SetSpeedMessage, SetVolumeMessage } from 'common/Packets';
|
||||
import { mediaItemFromPlayMessage, playMessageFromMediaItem } from 'common/UtilityFrontend';
|
||||
import { EventMessage, EventType, GenericMediaMetadata, KeyEvent, MediaItem, MediaItemEvent, MetadataType, PlaybackState, PlaylistContent, PlayMessage, SeekMessage, SetPlaylistItemMessage, SetSpeedMessage, SetVolumeMessage } from 'common/Packets';
|
||||
import { mediaItemFromPlayMessage, playMessageFromMediaItem, Timer } from 'common/UtilityFrontend';
|
||||
import { supportedImageTypes } from 'common/MimeTypes';
|
||||
import * as connectionMonitor from 'common/ConnectionMonitor';
|
||||
import { toast, ToastIcon } from 'common/components/Toast';
|
||||
|
@ -10,18 +10,53 @@ import {
|
|||
|
||||
const logger = window.targetAPI.logger;
|
||||
|
||||
const idleBackground = document.getElementById('video-player');
|
||||
const idleIcon = document.getElementById('title-icon');
|
||||
// todo: add callbacks for on-load events for image and generic content viewer
|
||||
const loadingSpinner = document.getElementById('loading-spinner');
|
||||
const imageViewer = document.getElementById('viewer-image') as HTMLImageElement;
|
||||
const genericViewer = document.getElementById('viewer-generic') as HTMLIFrameElement;
|
||||
// HTML elements
|
||||
const idleBackground = document.getElementById('idleBackground');
|
||||
const idleIcon = document.getElementById('titleIcon');
|
||||
const loadingSpinner = document.getElementById('loadingSpinner');
|
||||
const imageViewer = document.getElementById('viewerImage') as HTMLImageElement;
|
||||
const genericViewer = document.getElementById('viewerGeneric') as HTMLIFrameElement;
|
||||
|
||||
const mediaTitle = document.getElementById("mediaTitle");
|
||||
const playerControls = document.getElementById("controls");
|
||||
|
||||
const playerCtrlPlayPrevious = document.getElementById("playPrevious");
|
||||
const playerCtrlAction = document.getElementById("action");
|
||||
const playerCtrlPlaylistLength = document.getElementById("playlistLength");
|
||||
const playerCtrlPlayNext = document.getElementById("playNext");
|
||||
|
||||
let cachedPlaylist: PlaylistContent = null;
|
||||
let cachedPlayMediaItem: MediaItem = null;
|
||||
let showDurationTimeout: number = null;
|
||||
let playlistIndex = 0;
|
||||
let isMediaItem = false;
|
||||
let playItemCached = false;
|
||||
let imageViewerPlaybackState: PlaybackState = PlaybackState.Idle;
|
||||
|
||||
let uiHideTimer = new Timer(() => {
|
||||
uiVisible = false;
|
||||
playerCtrlStateUpdate(PlayerControlEvent.UiFadeOut);
|
||||
}, 3000);
|
||||
let loadingTimer = new Timer(() => { loadingSpinner.style.display = 'block'; }, 100, false);
|
||||
|
||||
let showDurationTimer = new Timer(() => {
|
||||
if (playlistIndex < cachedPlaylist.items.length - 1) {
|
||||
setPlaylistItem(playlistIndex + 1);
|
||||
}
|
||||
else {
|
||||
logger.info('End of playlist');
|
||||
imageViewer.style.display = 'none';
|
||||
imageViewer.src = '';
|
||||
|
||||
genericViewer.style.display = 'none';
|
||||
genericViewer.src = '';
|
||||
|
||||
idleBackground.style.display = 'block';
|
||||
idleIcon.style.display = 'block';
|
||||
|
||||
playerCtrlAction.setAttribute("class", "play iconSize");
|
||||
imageViewerPlaybackState = PlaybackState.Idle;
|
||||
}
|
||||
}, 0, false);
|
||||
|
||||
function onPlay(_event, value: PlayMessage) {
|
||||
if (!playItemCached) {
|
||||
|
@ -31,12 +66,21 @@ function onPlay(_event, value: PlayMessage) {
|
|||
window.targetAPI.sendEvent(new EventMessage(Date.now(), new MediaItemEvent(EventType.MediaItemChange, cachedPlayMediaItem)));
|
||||
logger.info('Media playback changed:', cachedPlayMediaItem);
|
||||
playItemCached = false;
|
||||
showDurationTimer.stop();
|
||||
|
||||
window.targetAPI.sendEvent(new EventMessage(Date.now(), new MediaItemEvent(EventType.MediaItemChange, cachedPlayMediaItem)));
|
||||
const src = value.url ? value.url : value.content;
|
||||
|
||||
loadingTimer.start();
|
||||
if (src && value.container && supportedImageTypes.find(v => v === value.container.toLocaleLowerCase()) && imageViewer) {
|
||||
logger.info('Loading image viewer');
|
||||
imageViewer.onload = (ev) => {
|
||||
loadingTimer.stop();
|
||||
loadingSpinner.style.display = 'none';
|
||||
playerCtrlStateUpdate(PlayerControlEvent.Load);
|
||||
};
|
||||
|
||||
genericViewer.onload = (ev) => {};
|
||||
|
||||
genericViewer.style.display = 'none';
|
||||
genericViewer.src = '';
|
||||
|
@ -45,12 +89,21 @@ function onPlay(_event, value: PlayMessage) {
|
|||
|
||||
imageViewer.src = src;
|
||||
imageViewer.style.display = 'block';
|
||||
playerControls.style.display = 'block';
|
||||
}
|
||||
else if (src && genericViewer) {
|
||||
logger.info('Loading generic viewer');
|
||||
imageViewer.onload = (ev) => {};
|
||||
|
||||
genericViewer.onload = (ev) => {
|
||||
loadingTimer.stop();
|
||||
loadingSpinner.style.display = 'none';
|
||||
playerCtrlStateUpdate(PlayerControlEvent.Load);
|
||||
};
|
||||
|
||||
imageViewer.style.display = 'none';
|
||||
imageViewer.src = '';
|
||||
playerControls.style.display = 'none';
|
||||
idleBackground.style.display = 'none';
|
||||
idleIcon.style.display = 'none';
|
||||
|
||||
|
@ -58,9 +111,14 @@ function onPlay(_event, value: PlayMessage) {
|
|||
genericViewer.style.display = 'block';
|
||||
} else {
|
||||
logger.error('Error loading content');
|
||||
loadingTimer.stop();
|
||||
loadingSpinner.style.display = 'none';
|
||||
imageViewer.onload = (ev) => {};
|
||||
genericViewer.onload = (ev) => {};
|
||||
|
||||
imageViewer.style.display = 'none';
|
||||
imageViewer.src = '';
|
||||
playerControls.style.display = 'none';
|
||||
|
||||
genericViewer.style.display = 'none';
|
||||
genericViewer.src = '';
|
||||
|
@ -68,29 +126,6 @@ function onPlay(_event, value: PlayMessage) {
|
|||
idleBackground.style.display = 'block';
|
||||
idleIcon.style.display = 'block';
|
||||
}
|
||||
|
||||
if (isMediaItem && cachedPlayMediaItem.showDuration && cachedPlayMediaItem.showDuration > 0) {
|
||||
showDurationTimeout = window.setTimeout(() => {
|
||||
playlistIndex++;
|
||||
|
||||
if (playlistIndex < cachedPlaylist.items.length) {
|
||||
cachedPlayMediaItem = cachedPlaylist.items[playlistIndex];
|
||||
playItemCached = true;
|
||||
window.targetAPI.sendPlayRequest(playMessageFromMediaItem(cachedPlaylist.items[playlistIndex]), playlistIndex);
|
||||
}
|
||||
else {
|
||||
logger.info('End of playlist');
|
||||
imageViewer.style.display = 'none';
|
||||
imageViewer.src = '';
|
||||
|
||||
genericViewer.style.display = 'none';
|
||||
genericViewer.src = '';
|
||||
|
||||
idleBackground.style.display = 'block';
|
||||
idleIcon.style.display = 'block';
|
||||
}
|
||||
}, cachedPlayMediaItem.showDuration * 1000);
|
||||
}
|
||||
};
|
||||
|
||||
function onPlayPlaylist(_event, value: PlaylistContent) {
|
||||
|
@ -111,28 +146,38 @@ function onPlayPlaylist(_event, value: PlaylistContent) {
|
|||
window.targetAPI.sendPlayRequest(playMessage, playlistIndex);
|
||||
}
|
||||
|
||||
function setPlaylistItem(index: number) {
|
||||
if (index === -1) {
|
||||
logger.info('Looping playlist to end');
|
||||
index = cachedPlaylist.items.length - 1;
|
||||
|
||||
}
|
||||
else if (index === cachedPlaylist.items.length) {
|
||||
logger.info('Looping playlist to start');
|
||||
index = 0;
|
||||
}
|
||||
|
||||
if (index >= 0 && index < cachedPlaylist.items.length) {
|
||||
logger.info(`Setting playlist item to index ${index}`);
|
||||
playlistIndex = index;
|
||||
cachedPlayMediaItem = cachedPlaylist.items[playlistIndex];
|
||||
playItemCached = true;
|
||||
window.targetAPI.sendPlayRequest(playMessageFromMediaItem(cachedPlaylist.items[playlistIndex]), playlistIndex);
|
||||
showDurationTimer.stop();
|
||||
}
|
||||
else {
|
||||
logger.warn(`Playlist index out of bounds ${index}, ignoring...`);
|
||||
}
|
||||
|
||||
playerCtrlPlaylistLength.textContent= `${playlistIndex+1} of ${cachedPlaylist.items.length}`;
|
||||
}
|
||||
|
||||
window.targetAPI.onPause(() => { logger.warn('onPause handler invoked for generic content viewer'); });
|
||||
window.targetAPI.onResume(() => { logger.warn('onResume handler invoked for generic content viewer'); });
|
||||
window.targetAPI.onSeek((_event, value: SeekMessage) => { logger.warn('onSeek handler invoked for generic content viewer'); });
|
||||
window.targetAPI.onSetVolume((_event, value: SetVolumeMessage) => { logger.warn('onSetVolume handler invoked for generic content viewer'); });
|
||||
window.targetAPI.onSetSpeed((_event, value: SetSpeedMessage) => { logger.warn('onSetSpeed handler invoked for generic content viewer'); });
|
||||
window.targetAPI.onSetPlaylistItem((_event, value: SetPlaylistItemMessage) => {
|
||||
if (value.itemIndex >= 0 && value.itemIndex < cachedPlaylist.items.length) {
|
||||
logger.info(`Setting playlist item to index ${value.itemIndex}`);
|
||||
playlistIndex = value.itemIndex;
|
||||
cachedPlayMediaItem = cachedPlaylist.items[playlistIndex];
|
||||
playItemCached = true;
|
||||
window.targetAPI.sendPlayRequest(playMessageFromMediaItem(cachedPlaylist.items[playlistIndex]), playlistIndex);
|
||||
|
||||
if (showDurationTimeout) {
|
||||
window.clearTimeout(showDurationTimeout);
|
||||
showDurationTimeout = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.warn(`Playlist index out of bounds ${value.itemIndex}, ignoring...`);
|
||||
}
|
||||
});
|
||||
window.targetAPI.onSetPlaylistItem((_event, value: SetPlaylistItemMessage) => { setPlaylistItem(value.itemIndex); });
|
||||
|
||||
connectionMonitor.setUiUpdateCallbacks({
|
||||
onConnect: (connections: string[], initialUpdate: boolean = false) => {
|
||||
|
@ -152,13 +197,8 @@ enum PlayerControlEvent {
|
|||
Load,
|
||||
Pause,
|
||||
Play,
|
||||
VolumeChange,
|
||||
TimeUpdate,
|
||||
UiFadeOut,
|
||||
UiFadeIn,
|
||||
SetCaptions,
|
||||
ToggleSpeedMenu,
|
||||
SetPlaybackRate,
|
||||
ToggleFullscreen,
|
||||
ExitFullscreen,
|
||||
}
|
||||
|
@ -172,14 +212,77 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) {
|
|||
|
||||
switch (event) {
|
||||
case PlayerControlEvent.Load: {
|
||||
if (isMediaItem) {
|
||||
playerCtrlPlayPrevious.style.display = 'block';
|
||||
playerCtrlPlayNext.style.display = 'block';
|
||||
|
||||
if (cachedPlayMediaItem.showDuration && cachedPlayMediaItem.showDuration > 0) {
|
||||
playerCtrlAction.style.display = 'block';
|
||||
playerCtrlPlaylistLength.style.display = 'none';
|
||||
|
||||
if (imageViewerPlaybackState === PlaybackState.Idle || imageViewerPlaybackState === PlaybackState.Playing) {
|
||||
showDurationTimer.start(cachedPlayMediaItem.showDuration * 1000);
|
||||
playerCtrlAction.setAttribute("class", "pause iconSize");
|
||||
imageViewerPlaybackState = PlaybackState.Playing;
|
||||
}
|
||||
}
|
||||
else {
|
||||
playerCtrlAction.style.display = 'none';
|
||||
playerCtrlPlaylistLength.textContent= `${playlistIndex+1} of ${cachedPlaylist.items.length}`;
|
||||
playerCtrlPlaylistLength.style.display = 'block';
|
||||
}
|
||||
}
|
||||
else {
|
||||
playerCtrlPlayPrevious.style.display = 'none';
|
||||
playerCtrlPlayNext.style.display = 'none';
|
||||
playerCtrlAction.style.display = 'none';
|
||||
playerCtrlPlaylistLength.style.display = 'none';
|
||||
}
|
||||
|
||||
if (cachedPlayMediaItem.metadata && cachedPlayMediaItem.metadata?.type === MetadataType.Generic) {
|
||||
const metadata = cachedPlayMediaItem.metadata as GenericMediaMetadata;
|
||||
|
||||
if (metadata.title) {
|
||||
mediaTitle.innerHTML = metadata.title;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PlayerControlEvent.Pause:
|
||||
playerCtrlAction.setAttribute("class", "play iconSize");
|
||||
imageViewerPlaybackState = PlaybackState.Paused;
|
||||
showDurationTimer.pause();
|
||||
break;
|
||||
|
||||
case PlayerControlEvent.Play:
|
||||
playerCtrlAction.setAttribute("class", "pause iconSize");
|
||||
|
||||
if (imageViewerPlaybackState === PlaybackState.Idle) {
|
||||
setPlaylistItem(0);
|
||||
}
|
||||
else {
|
||||
if (showDurationTimer.started) {
|
||||
showDurationTimer.resume();
|
||||
}
|
||||
else {
|
||||
showDurationTimer.start(cachedPlayMediaItem.showDuration * 1000);
|
||||
}
|
||||
|
||||
imageViewerPlaybackState = PlaybackState.Playing;
|
||||
}
|
||||
break;
|
||||
|
||||
case PlayerControlEvent.UiFadeOut: {
|
||||
document.body.style.cursor = "none";
|
||||
playerControls.style.opacity = '0';
|
||||
break;
|
||||
}
|
||||
|
||||
case PlayerControlEvent.UiFadeIn: {
|
||||
document.body.style.cursor = "default";
|
||||
playerControls.style.opacity = '1';
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -188,61 +291,79 @@ function playerCtrlStateUpdate(event: PlayerControlEvent) {
|
|||
}
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', (event: KeyboardEvent) => {
|
||||
// Receiver generated event handlers
|
||||
playerCtrlAction.onclick = () => {
|
||||
if (imageViewerPlaybackState === PlaybackState.Paused || imageViewerPlaybackState === PlaybackState.Idle) {
|
||||
playerCtrlStateUpdate(PlayerControlEvent.Play);
|
||||
} else {
|
||||
playerCtrlStateUpdate(PlayerControlEvent.Pause);
|
||||
}
|
||||
};
|
||||
|
||||
playerCtrlPlayPrevious.onclick = () => { setPlaylistItem(playlistIndex - 1); }
|
||||
playerCtrlPlayNext.onclick = () => { setPlaylistItem(playlistIndex + 1); }
|
||||
|
||||
// Component hiding
|
||||
let uiVisible = true;
|
||||
|
||||
function stopUiHideTimer() {
|
||||
uiHideTimer.stop();
|
||||
|
||||
if (!uiVisible) {
|
||||
uiVisible = true;
|
||||
playerCtrlStateUpdate(PlayerControlEvent.UiFadeIn);
|
||||
}
|
||||
}
|
||||
|
||||
document.onmouseout = () => {
|
||||
uiHideTimer.stop();
|
||||
uiVisible = false;
|
||||
playerCtrlStateUpdate(PlayerControlEvent.UiFadeOut);
|
||||
}
|
||||
|
||||
document.onmousemove = () => {
|
||||
stopUiHideTimer();
|
||||
uiHideTimer.start();
|
||||
};
|
||||
|
||||
function keyDownEventListener(event: KeyboardEvent) {
|
||||
// logger.info("KeyDown", event);
|
||||
let handledCase = targetKeyDownEventListener(event);
|
||||
|
||||
if (!handledCase) {
|
||||
switch (event.code) {
|
||||
case 'ArrowLeft': {
|
||||
// skipBack();
|
||||
// event.preventDefault();
|
||||
// handledCase = true;
|
||||
|
||||
// const value = { itemIndex: playlistIndex - 1 };
|
||||
// if (value.itemIndex >= 0 && value.itemIndex < cachedPlaylist.items.length) {
|
||||
// logger.info(`Setting playlist item to index ${value.itemIndex}`);
|
||||
// playlistIndex = value.itemIndex;
|
||||
// cachedPlayMediaItem = cachedPlaylist.items[playlistIndex];
|
||||
// playItemCached = true;
|
||||
// window.targetAPI.sendPlayRequest(playMessageFromMediaItem(cachedPlaylist.items[playlistIndex]), playlistIndex);
|
||||
|
||||
// if (showDurationTimeout) {
|
||||
// window.clearTimeout(showDurationTimeout);
|
||||
// showDurationTimeout = null;
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// logger.warn(`Playlist index out of bounds ${value.itemIndex}, ignoring...`);
|
||||
// }
|
||||
|
||||
case 'ArrowLeft':
|
||||
setPlaylistItem(playlistIndex - 1);
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
}
|
||||
case 'ArrowRight': {
|
||||
// skipForward();
|
||||
// event.preventDefault();
|
||||
// handledCase = true;
|
||||
|
||||
// const value = { itemIndex: playlistIndex + 1 };
|
||||
// if (value.itemIndex >= 0 && value.itemIndex < cachedPlaylist.items.length) {
|
||||
// logger.info(`Setting playlist item to index ${value.itemIndex}`);
|
||||
// playlistIndex = value.itemIndex;
|
||||
// cachedPlayMediaItem = cachedPlaylist.items[playlistIndex];
|
||||
// playItemCached = true;
|
||||
// window.targetAPI.sendPlayRequest(playMessageFromMediaItem(cachedPlaylist.items[playlistIndex]), playlistIndex);
|
||||
|
||||
// if (showDurationTimeout) {
|
||||
// window.clearTimeout(showDurationTimeout);
|
||||
// showDurationTimeout = null;
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// logger.warn(`Playlist index out of bounds ${value.itemIndex}, ignoring...`);
|
||||
// }
|
||||
|
||||
case 'ArrowRight':
|
||||
setPlaylistItem(playlistIndex + 1);
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
case "Home":
|
||||
setPlaylistItem(0);
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
case "End":
|
||||
setPlaylistItem(cachedPlaylist.items.length - 1);
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
case 'KeyK':
|
||||
case 'Space':
|
||||
case 'Enter':
|
||||
// Play/pause toggle
|
||||
if (imageViewerPlaybackState === PlaybackState.Paused || imageViewerPlaybackState === PlaybackState.Idle) {
|
||||
playerCtrlStateUpdate(PlayerControlEvent.Play);
|
||||
} else {
|
||||
playerCtrlStateUpdate(PlayerControlEvent.Pause);
|
||||
}
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -251,7 +372,9 @@ document.addEventListener('keydown', (event: KeyboardEvent) => {
|
|||
if (window.targetAPI.getSubscribedKeys().keyDown.has(event.key)) {
|
||||
window.targetAPI.sendEvent(new EventMessage(Date.now(), new KeyEvent(EventType.KeyDown, event.key, event.repeat, handledCase)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', keyDownEventListener);
|
||||
document.addEventListener('keyup', (event: KeyboardEvent) => {
|
||||
if (window.targetAPI.getSubscribedKeys().keyUp.has(event.key)) {
|
||||
window.targetAPI.sendEvent(new EventMessage(Date.now(), new KeyEvent(EventType.KeyUp, event.key, event.repeat, false)));
|
||||
|
@ -260,6 +383,10 @@ document.addEventListener('keyup', (event: KeyboardEvent) => {
|
|||
|
||||
export {
|
||||
PlayerControlEvent,
|
||||
idleBackground,
|
||||
idleIcon,
|
||||
imageViewer,
|
||||
genericViewer,
|
||||
onPlay,
|
||||
playerCtrlStateUpdate,
|
||||
};
|
||||
|
|
|
@ -32,7 +32,7 @@ body {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
#title-icon {
|
||||
#titleIcon {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
|
@ -42,6 +42,122 @@ body {
|
|||
background-size: cover;
|
||||
}
|
||||
|
||||
.container {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
|
||||
/* height: 100%; */
|
||||
height: 120px;
|
||||
width: 100%;
|
||||
/* background: linear-gradient(to top, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0) 100%); */
|
||||
background: linear-gradient(to top, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0.0) 35%);
|
||||
|
||||
background-size: 100% 300px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: bottom;
|
||||
|
||||
opacity: 1;
|
||||
transition: opacity 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
.iconSize {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
position: absolute;
|
||||
bottom: 24px;
|
||||
height: 24px;
|
||||
/* width: calc(50% - 24px); */
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#leftButtonContainer {
|
||||
left: 24px;
|
||||
right: 60%;
|
||||
flex-direction: row;
|
||||
|
||||
font-family: InterVariable;
|
||||
font-size: 24px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
#centerButtonContainer {
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0%);
|
||||
|
||||
font-family: InterVariable;
|
||||
font-size: 24px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
#rightButtonContainer {
|
||||
right: 24px;
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
#mediaTitle {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.play {
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
|
||||
background-image: url("../assets/icons/player/icon24_play.svg");
|
||||
transition: background-image 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
.play:hover {
|
||||
background-image: url("../assets/icons/player/icon24_play_active.svg");
|
||||
}
|
||||
|
||||
.pause {
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
|
||||
background-image: url("../assets/icons/player/icon24_pause.svg");
|
||||
transition: background-image 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
.pause:hover {
|
||||
background-image: url("../assets/icons/player/icon24_pause_active.svg");
|
||||
}
|
||||
|
||||
.playPrevious {
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
|
||||
background-image: url("../assets/icons/player/icon24_play_previous.svg");
|
||||
transition: background-image 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
.playPrevious:hover {
|
||||
background-image: url("../assets/icons/player/icon24_play_previous_active.svg");
|
||||
}
|
||||
|
||||
.playNext {
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
|
||||
background-image: url("../assets/icons/player/icon24_play_next.svg");
|
||||
transition: background-image 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
.playNext:hover {
|
||||
background-image: url("../assets/icons/player/icon24_play_next_active.svg");
|
||||
}
|
||||
|
||||
.lds-ring {
|
||||
display: block;
|
||||
position: absolute;
|
||||
|
@ -148,7 +264,7 @@ body {
|
|||
|
||||
/* Display scaling (Minimum supported resolution is 960x540) */
|
||||
@media only screen and ((min-width: 2560px) or (min-height: 1440px)) {
|
||||
#title-icon {
|
||||
#titleIcon {
|
||||
width: 164px;
|
||||
height: 164px;
|
||||
}
|
||||
|
@ -179,7 +295,7 @@ body {
|
|||
}
|
||||
|
||||
@media only screen and ((max-width: 2559px) or (max-height: 1439px)) {
|
||||
#title-icon {
|
||||
#titleIcon {
|
||||
width: 124px;
|
||||
height: 124px;
|
||||
}
|
||||
|
@ -210,7 +326,7 @@ body {
|
|||
}
|
||||
|
||||
@media only screen and ((max-width: 1919px) or (max-height: 1079px)) {
|
||||
#title-icon {
|
||||
#titleIcon {
|
||||
width: 84px;
|
||||
height: 84px;
|
||||
}
|
||||
|
@ -241,7 +357,7 @@ body {
|
|||
}
|
||||
|
||||
@media only screen and ((max-width: 1279px) or (max-height: 719px)) {
|
||||
#title-icon {
|
||||
#titleIcon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
import { PlayerControlEvent, playerCtrlStateUpdate } from 'common/viewer/Renderer';
|
||||
import { PlayerControlEvent, playerCtrlStateUpdate, idleBackground, idleIcon, imageViewer, genericViewer } from 'common/viewer/Renderer';
|
||||
|
||||
const playerCtrlFullscreen = document.getElementById("fullscreen");
|
||||
playerCtrlFullscreen.onclick = () => { playerCtrlStateUpdate(PlayerControlEvent.ToggleFullscreen); };
|
||||
idleBackground.ondblclick = () => { playerCtrlStateUpdate(PlayerControlEvent.ToggleFullscreen); };
|
||||
idleIcon.ondblclick = () => { playerCtrlStateUpdate(PlayerControlEvent.ToggleFullscreen); };
|
||||
imageViewer.ondblclick = () => { playerCtrlStateUpdate(PlayerControlEvent.ToggleFullscreen); };
|
||||
genericViewer.ondblclick = () => { playerCtrlStateUpdate(PlayerControlEvent.ToggleFullscreen); };
|
||||
|
||||
export function targetPlayerCtrlStateUpdate(event: PlayerControlEvent): boolean {
|
||||
let handledCase = false;
|
||||
|
@ -7,13 +14,13 @@ export function targetPlayerCtrlStateUpdate(event: PlayerControlEvent): boolean
|
|||
case PlayerControlEvent.ToggleFullscreen: {
|
||||
window.electronAPI.toggleFullScreen();
|
||||
|
||||
// window.electronAPI.isFullScreen().then((isFullScreen: boolean) => {
|
||||
// if (isFullScreen) {
|
||||
// playerCtrlFullscreen.setAttribute("class", "fullscreen_on");
|
||||
// } else {
|
||||
// playerCtrlFullscreen.setAttribute("class", "fullscreen_off");
|
||||
// }
|
||||
// });
|
||||
window.electronAPI.isFullScreen().then((isFullScreen: boolean) => {
|
||||
if (isFullScreen) {
|
||||
playerCtrlFullscreen.setAttribute("class", "fullscreen_on");
|
||||
} else {
|
||||
playerCtrlFullscreen.setAttribute("class", "fullscreen_off");
|
||||
}
|
||||
});
|
||||
|
||||
handledCase = true;
|
||||
break;
|
||||
|
@ -21,7 +28,7 @@ export function targetPlayerCtrlStateUpdate(event: PlayerControlEvent): boolean
|
|||
|
||||
case PlayerControlEvent.ExitFullscreen:
|
||||
window.electronAPI.exitFullScreen();
|
||||
// playerCtrlFullscreen.setAttribute("class", "fullscreen_off");
|
||||
playerCtrlFullscreen.setAttribute("class", "fullscreen_off");
|
||||
|
||||
handledCase = true;
|
||||
break;
|
||||
|
|
|
@ -6,16 +6,33 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="../assets/fonts/inter.css" />
|
||||
<link rel="stylesheet" href="./common.css" />
|
||||
<link rel="stylesheet" href="./style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<!-- Empty video element as a workaround to fix issue with white border outline without it... -->
|
||||
<video id="video-player" class="video"></video>
|
||||
<video id="idleBackground" class="video"></video>
|
||||
<div id="viewer" class="viewer">
|
||||
<div id="title-icon"></div>
|
||||
<img id="viewer-image" class="viewer" />
|
||||
<iframe id="viewer-generic" class="viewer"></iframe>
|
||||
<div id="titleIcon"></div>
|
||||
<div id="loadingSpinner" class="lds-ring"><div></div><div></div><div></div><div></div></div>
|
||||
<img id="viewerImage" class="viewer" />
|
||||
<iframe id="viewerGeneric" class="viewer"></iframe>
|
||||
</div>>
|
||||
|
||||
<div id="controls" class="container">
|
||||
<div id="leftButtonContainer" class="buttonContainer">
|
||||
<div id="mediaTitle"></div>
|
||||
</div>
|
||||
<div id="centerButtonContainer" class="buttonContainer">
|
||||
<div id="playPrevious" class="playPrevious iconSize" style="display: none"></div>
|
||||
<div id="action" class="play iconSize" style="display: none"></div>
|
||||
<div id="playlistLength" style="display: none"></div>
|
||||
<div id="playNext" class="playNext iconSize" style="display: none"></div>
|
||||
</div>
|
||||
|
||||
<div id="rightButtonContainer" class="buttonContainer">
|
||||
<div id="fullscreen" class="fullscreen_on iconSize"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="toast-notification">
|
||||
<div id="toast-icon"></div>
|
||||
|
@ -24,4 +41,4 @@
|
|||
|
||||
<script src="./renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
26
receivers/electron/src/viewer/style.css
Normal file
26
receivers/electron/src/viewer/style.css
Normal file
|
@ -0,0 +1,26 @@
|
|||
|
||||
.fullscreen_on {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
|
||||
background-image: url("../assets/icons/player/icon24_fullscreen_on.svg");
|
||||
transition: background-image 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
.fullscreen_on:hover {
|
||||
background-image: url("../assets/icons/player/icon24_fullscreen_on_active.svg");
|
||||
}
|
||||
|
||||
.fullscreen_off {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
|
||||
background-image: url("../assets/icons/player/icon24_fullscreen_off.svg");
|
||||
transition: background-image 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
.fullscreen_off:hover {
|
||||
background-image: url("../assets/icons/player/icon24_fullscreen_off_active.svg");
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue