From 5166582386b6adc27d246e3fc4fe4b54ea4b8770 Mon Sep 17 00:00:00 2001 From: jparez Date: Thu, 14 Nov 2024 18:03:11 +0100 Subject: [PATCH] delete template feature --- README.md | 16 +++---- example/geny-window.css | 49 ++++++++------------ example/geny-window.html | 41 +++++++++-------- example/geny-window.js | 26 +++++------ gulpfile.js | 68 +++------------------------- src/DeviceRenderer.js | 7 --- src/DeviceRendererFactory.js | 64 +++++++++++--------------- src/plugins/KeyboardMapping.js | 2 +- src/scss/base/_genymotion.scss | 77 +++++++++++++++++++++++++++----- src/scss/components/_upload.scss | 9 ---- 10 files changed, 160 insertions(+), 199 deletions(-) diff --git a/README.md b/README.md index a83ec7c..a106164 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,6 @@ or check the [PaaS documentation](https://docs.genymotion.com/paas/01_Requiremen // See "Features & options" section for more details about options const options = { - template: 'renderer', // template defines how renderer is displayed token: 'i-XXXXXXXXXX', // token is the shared secret to connect to your VM fileUpload: false, // requires fileUploadUrl }; @@ -274,14 +273,6 @@ sendData({ A device renderer instance can be configured using the `options` argument (object). Possible configuration key / value are described below. -### `template` - -- **Type:** `String` -- **Default:** `renderer` -- **Compatibility:** `PaaS`, `SaaS` -- **Details:** - Defines the layout of the renderer. Can be one of the following: `bootstrap`, `fullscreen`, `fullwindow`, `renderer`, `renderer_minimal`, `renderer_no_toolbar`, `renderer_partial`. - ### `token` - **Type:** `String` @@ -333,6 +324,13 @@ A device renderer instance can be configured using the `options` argument (objec } ``` +### `showPhoneBorder` + +- **Type:** `Boolean` +- **Default:** `false` +- **Details:** + Adds a mobile-style frame around the video to mimic the appearance of a smartphone screen. + ### `streamResolution` ... diff --git a/example/geny-window.css b/example/geny-window.css index 374d9b2..7950de4 100644 --- a/example/geny-window.css +++ b/example/geny-window.css @@ -18,7 +18,7 @@ margin-left: 5px; } -.d-flex{ +.d-flex { display: flex; } @@ -54,18 +54,19 @@ hr { width: 100%; } -summary, label { +summary, +label { cursor: pointer; } -input[type="text"] { +input[type='text'] { width: 100%; padding: 5px; margin: 5px 0; box-sizing: border-box; } -input[type="checkbox"] { +input[type='checkbox'] { cursor: pointer; } .note { @@ -138,8 +139,14 @@ header { color: #fff; padding: 10px; box-sizing: border-box; - margin-right: 20px; padding-top: 20px; + height: calc(100vh - 84px); + overflow-y: scroll; + -ms-overflow-style: none; + scrollbar-width: none; +} +#sidebar::-webkit-scrollbar { + display: none; } #sidebar .actions { @@ -154,41 +161,21 @@ header { } #advancedSettings > * { - margin-bottom: 10px; + margin-bottom: 10px; } #player { - background-color: #000; + background-color: #1a1a1a; color: #fff; - padding: 10px; box-sizing: border-box; - margin-right: 20px; margin: 0 auto; - max-width: 90%; - max-height: 95vh; -} - -#fe-player { - margin: 10px; - margin: 0; - color: #fff; - font-size: 14px; - font-family: 'Roboto', sans-serif; -} - -#fe-player .gm-wrapper { - display: flex !important; + flex-grow: 1; + max-height: calc(100vh - 84px); } #fe-player .gm-toolbar { - top: 0; - height: 100%; background-color: #1e1e1e; } - -@media screen and (max-width: 800px) { - #fe-player.landscape { - max-width: 400px; - width: auto; - } +#fe-player .gm-video-wrapper { + padding: 10px 0 10px 10px; } diff --git a/example/geny-window.html b/example/geny-window.html index 9764acf..74b179e 100644 --- a/example/geny-window.html +++ b/example/geny-window.html @@ -61,9 +61,13 @@

Connect to an existing instance

@@ -71,37 +75,38 @@

Connect to an existing instance


+

More about geny's products and integration

+ ๐Ÿ‘‰ Our products + ๐Ÿ‘‰ Our CLI, gmsaas + + ๐Ÿ‘‰ Player documentation + +

Advanced settings

โšกโš™๏ธ
- +
โš ๏ธ can be read by anyone with access to local storage
- +
-
- -
+
+ +
-
-

More about geny's products and integration

- ๐Ÿ‘‰ Our products - ๐Ÿ‘‰ Our CLI, gmsaas - - ๐Ÿ‘‰ Player documentation -
diff --git a/example/geny-window.js b/example/geny-window.js index d46b4de..86375eb 100644 --- a/example/geny-window.js +++ b/example/geny-window.js @@ -35,7 +35,7 @@ const getJWTToken = async (instanceUuid) => { ...requestInit, method: 'POST', body: JSON.stringify({ - instance_uuid: instanceUuid, + instance_uuid: instanceUuid, }), }); @@ -112,8 +112,8 @@ const initPlayer = (webrtcAddress) => { } const options = { - template: 'renderer_partial', token: jwtToken || apiToken, + showPhoneBorder: true, }; const {DeviceRendererFactory} = window.genyDeviceWebPlayer; @@ -180,7 +180,6 @@ const fetchRecipes = async () => { } }; - // connect to an existing instance through an instance Uuid or an instance ws address const connectInstance = async (wsAddress) => { if (wsAddress.includes('wss://')) { @@ -217,13 +216,9 @@ const generateInstanceHistoryList = () => { const option = document.createElement('option'); option.value = instance; datalist.appendChild(option); - } - ); + }); }; - - - document.addEventListener( 'DOMContentLoaded', () => { @@ -241,7 +236,7 @@ document.addEventListener( }); // change recipeUuid when the user select a recipe - document.querySelector('#listRecipes').addEventListener('change', function (event) { + document.querySelector('#listRecipes').addEventListener('change', function () { const selectedValue = document.querySelector('#listRecipes').value; document.querySelector('#recipeUuid').value = selectedValue; }); @@ -267,15 +262,16 @@ document.addEventListener( await connectInstance(wsAddress); }); - // binding advanced settings - // fill ui with localstorage values if they exist + // binding advanced settings + // fill ui with localstorage values if they exist document.querySelector('#saveToken').checked = localStorage.getItem('hasSaveToken') === 'true'; document.querySelector('#apiToken').value = localStorage.getItem('apiToken'); - document.querySelector('#saveInstanceHistory').checked = localStorage.getItem('hasSaveInstanceHistory') === 'true'; + document.querySelector('#saveInstanceHistory').checked = + localStorage.getItem('hasSaveInstanceHistory') === 'true'; generateInstanceHistoryList(); document.querySelector('#apiBaseUrl').value = baseUrlToFetch; - // save values on change + // save values on change document.querySelector('#saveToken').addEventListener('click', (event) => { localStorage.setItem('hasSaveToken', event.target.checked); if (event.target.checked) { @@ -291,8 +287,8 @@ document.addEventListener( } else { localStorage.removeItem('instanceHistory'); } - }); - document.querySelector('#saveAPIBaseUrl').addEventListener('click', (event) => { + }); + document.querySelector('#saveAPIBaseUrl').addEventListener('click', () => { if (document.querySelector('#apiBaseUrl').value.trim().length) { localStorage.setItem('baseUrlToFetch', document.querySelector('#apiBaseUrl').value); baseUrlToFetch = document.querySelector('#apiBaseUrl').value; diff --git a/gulpfile.js b/gulpfile.js index fb1f8b1..78b8a5c 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -6,7 +6,6 @@ */ // This variable is used to store templates generated from the template folder -let templates; const autoprefixer = require('gulp-autoprefixer'); const babel = require('gulp-babel'); @@ -15,18 +14,14 @@ const browserify = require('browserify'); const browserSync = require('browser-sync').create(); const concat = require('gulp-concat'); const del = require('del'); -const graspify = require('./gulp/graspify-squery'); const gulp = require('gulp'); const gulpif = require('gulp-if'); const inject = require('gulp-inject'); const merge2 = require('merge2'); const minifyCss = require('gulp-clean-css'); -const minifyHtml = require('gulp-htmlmin'); const sass = require('gulp-sass')(require('sass')); const source = require('vinyl-source-stream'); const streamify = require('gulp-streamify'); -const tap = require('gulp-tap'); -const templateCollector = require('./gulp/gulp-template-collector'); const uglify = require('gulp-uglify-es').default; const using = require('gulp-using'); const util = require('gulp-util'); @@ -38,14 +33,12 @@ const PATHS = { APP: 'index.js', BASE: './src', WORKER: './src/worker', - TEMPLATES: './src/templates', ASSETS: { STYLES: './src/scss', }, }, DEST: { BASE: 'dist', - TEMPLATES: 'dist/templates', ASSETS: { CSS: 'dist/css', }, @@ -61,18 +54,6 @@ const PATHS = { }, }; -function getTemplateStylesStream() { - return gulp.src([PATHS.SRC.TEMPLATES + '/**/*.css']).pipe(base64()); -} - -function getTemplatesStream() { - return merge2( - gulp.src([PATHS.SRC.TEMPLATES + '/**/*.html']), - gulp.src([PATHS.SRC.TEMPLATES + '/**/*.js']), - getTemplateStylesStream(), - ).pipe(templateCollector()); -} - // Clean dist dir gulp.task('clean', function (cb) { del([PATHS.DEST.BASE + ' --force']).then( @@ -85,16 +66,7 @@ gulp.task('clean', function (cb) { ); }); -// HTML templates -gulp.task('app-partials', function () { - return gulp - .src(['*.html']) - .pipe(gulpif(util.env.debug, using())) - .pipe(gulpif(util.env.production, minifyHtml({empty: true}))) - .pipe(gulp.dest(PATHS.DEST.BASE)); -}); - -// HTML templates +// Integration Example gulp.task('app-geny-window', function () { const version = getVersion(); // Fetch the version from package.json @@ -117,9 +89,9 @@ gulp.task('app-styles', function () { .src(PATHS.SRC.ASSETS.STYLES + '/**/*.scss') .pipe(gulpif(util.env.debug, using())) .pipe(sass().on('error', sass.logError)) - .pipe(base64()) .pipe(autoprefixer()) .pipe(gulpif(util.env.production, minifyCss())) + .pipe(base64()) .pipe(concat('device-renderer.min.css')) .pipe(header(version)) .pipe(gulp.dest(PATHS.DEST.ASSETS.CSS)); @@ -130,37 +102,17 @@ gulp.task('app-dts', function () { return gulp.src(PATHS.SRC.BASE + './../*.d.ts').pipe(gulp.dest(PATHS.DEST.BASE)); }); -gulp.task('app-templates', function () { - return getTemplatesStream().pipe( - tap(function (file) { - // After getting the templates to a JSON form, we need to transform it to a javascript string - templates = file.contents.toString(); - templates = templates.replace(/\\n/g, ''); // we remove \n - templates = templates.replace(/\\"/g, 'xFic1RoIH8'); // we change \" to a tmp replacement string - templates = templates.replace(/'/g, "\\'"); // we change all ' to \' - templates = templates.replace(/"/g, "'"); // we replace all " by ' - templates = templates.replace(/xFic1RoIH8/g, '\\"'); // we change back the tmp replacement string to \" - }), - ); -}); - function setupBrowserify() { return browserify({ entries: [PATHS.SRC.BASE + '/' + PATHS.SRC.APP], standalone: 'genyDeviceWebPlayer', debug: true, - }).transform(graspify, ['#GEN_TEMPLATES', templates]); + }); } function getBundler() { return new Promise((resolve) => { - if (!templates) { - gulp.series('app-templates')(() => { - resolve(setupBrowserify()); - }); - } else { - resolve(setupBrowserify()); - } + resolve(setupBrowserify()); }); } @@ -221,15 +173,9 @@ gulp.task('connect', function () { // Build project gulp.task( 'build', - gulp.series( - 'clean', - 'app-templates', - gulp.parallel('app-partials', 'app-styles', 'app-js', 'app-dts', 'app-geny-window'), - 'inject', - function (cb) { - cb(); - }, - ), + gulp.series('clean', gulp.parallel('app-styles', 'app-js', 'app-dts', 'app-geny-window'), 'inject', function (cb) { + cb(); + }), ); // Watch project update diff --git a/src/DeviceRenderer.js b/src/DeviceRenderer.js index 8810f33..a6632d9 100644 --- a/src/DeviceRenderer.js +++ b/src/DeviceRenderer.js @@ -44,8 +44,6 @@ module.exports = class DeviceRenderer { */ constructor(domRoot, options) { this.timeoutCallbacks = []; - this.videoBackupStyleBackground = ''; - // Options associated with this instance this.options = options; @@ -242,12 +240,10 @@ module.exports = class DeviceRenderer { */ onConnectionClosed() { // closure to expose the right video and store context to onclose event - const video = this.video; const store = this.store; this.webRTCWebsocket.onclose = (event) => { store.dispatch({type: 'WEBRTC_CONNECTION_READY', payload: false}); - video.style.background = this.videoBackupStyleBackground; this.initialized = false; log.debug('Error! Maybe your VM is not available yet? (' + event.code + ') ' + event.reason); @@ -467,9 +463,6 @@ module.exports = class DeviceRenderer { // Get the PeerConnection Statistics after 3 seconds new PeerConnectionStats(this, this.peerConnection, 3000); - this.videoBackupStyleBackground = this.video.style.background; - this.video.style.background = 'transparent'; - if (this.touchEventsEnabled) { this.touchEvents.addTouchCallbacks(); } diff --git a/src/DeviceRendererFactory.js b/src/DeviceRendererFactory.js index 47d75f5..c9bd8d3 100644 --- a/src/DeviceRendererFactory.js +++ b/src/DeviceRendererFactory.js @@ -9,13 +9,8 @@ const APIManager = require('./APIManager'); const log = require('loglevel'); log.setDefaultLevel('debug'); -// Templates are loaded dynamically from the `templates` folder -const TEMPLATE_JS = 'device-renderer-js'; -const TEMPLATE_CSS = 'device-renderer-css'; - // Default options const defaultOptions = { - template: 'renderer', touch: true, mouse: true, volume: true, @@ -69,8 +64,6 @@ const defaultOptions = { module.exports = class DeviceRendererFactory { constructor() { this.instances = []; - /* global GEN_TEMPLATES */ - this.templates = GEN_TEMPLATES; } /** @@ -79,7 +72,7 @@ module.exports = class DeviceRendererFactory { * @param {HTMLElement|string} dom The DOM element (or its ID) to setup the device renderer into. * @param {string} webRTCUrl WebRTC URL of the instance. * @param {Object} options Various configuration options. - * @param {string} options.template Template to use. Default: 'renderer'. + * @param {boolean} options.showPhoneBorder Show phone border. Default: false. * @param {boolean} options.touch Touch support activated. Default: true. * @param {boolean} options.mouse Mouse support activated. Default: true. * @param {boolean} options.volume Audio volume control support activated. Default: true. @@ -136,15 +129,20 @@ module.exports = class DeviceRendererFactory { log.debug('Creating genymotion display on ' + webRTCUrl); dom.classList.add('device-renderer-instance'); - dom.classList.add('gm-template-' + options.template); - document.body.classList.add('gm-template-' + options.template + '-body'); - - // Load template before creating the Device Renderer that is using HTML elements - this.loadTemplate(dom, this.templates[options.template], options); + this.loadTemplate(dom, options); const instance = new RendererClass(dom, options); store(instance); + // Add a class to the wrapper when we are waiting for the stream to be ready in order to display a loader + instance.store.subscribe(({isWebRTCConnectionReady}) => { + if (isWebRTCConnectionReady) { + instance.wrapper.classList.remove('waitingForStream'); + } else { + instance.wrapper.classList.add('waitingForStream'); + } + }); + instance.apiManager = new APIManager(instance); this.instances.push(instance); @@ -156,35 +154,25 @@ module.exports = class DeviceRendererFactory { } /** - * Loads the selected template. + * Loads HTML template. * * @param {HTMLElement} dom The DOM element to setup the device renderer into. - * @param {string} template Template to use. * @param {Object} options Various configuration options. */ - loadTemplate(dom, template, options) { - const head = document.getElementsByTagName('head')[0]; - const scriptId = TEMPLATE_JS + '-' + options.template; - const styleId = TEMPLATE_CSS + '-' + options.template; - - // Handle template JS - if (!document.getElementById(scriptId)) { - const script = document.createElement('script'); - script.id = scriptId; - script.text = template.js; - head.appendChild(script); - } - - // Handle template CSS - if (!document.getElementById(styleId)) { - const style = document.createElement('style'); - style.id = styleId; - style.appendChild(document.createTextNode(template.css)); - head.appendChild(style); - } - - // Handle template dom - dom.innerHTML = template.html; + loadTemplate(dom, options) { + dom.innerHTML = ` +
+
+ +
+
+
+
    +
    +
    +
    + `; } /** diff --git a/src/plugins/KeyboardMapping.js b/src/plugins/KeyboardMapping.js index e818069..7244a0b 100644 --- a/src/plugins/KeyboardMapping.js +++ b/src/plugins/KeyboardMapping.js @@ -758,7 +758,7 @@ module.exports = class KeyboardMapping { const div = document.createElement('div'); div.style.position = 'absolute'; div.style.left = `${0}px`; - div.style.top = `${i * (videoSize.height * 0.1) + this.instance.coordinateUtils.getTopBorder()}px`; + div.style.top = `${i * (videoSize.height * 0.1) + (parentSize.height - videoSize.height) / 2}px`; div.style.width = '100%'; div.style.height = '1px'; div.style.background = 'red'; diff --git a/src/scss/base/_genymotion.scss b/src/scss/base/_genymotion.scss index 884e701..9ae7a0f 100644 --- a/src/scss/base/_genymotion.scss +++ b/src/scss/base/_genymotion.scss @@ -3,6 +3,7 @@ */ .device-renderer-instance { text-align: center; + height: 100%; *, *::after, @@ -38,16 +39,10 @@ } .gm { - &-video { - margin: 0; - max-width: 100%; - } - &-icon-button { display: block; width: 32px; height: 26px; - margin: 16px auto 16px auto; } &-video-overlay { @@ -90,12 +85,8 @@ width: 80%; max-width: 380px; min-height: 66px; - left: calc(10% - 30px); top: calc(86% - 34px); cursor: pointer; - @media screen and (min-width: 475px) { - left: calc(50% - 220px); - } } &-overlay-cant-connect { @@ -123,6 +114,72 @@ } } } + + .gm-wrapper { + background-color: #1a1a1a; + height: 100%; + display: grid; + grid-template-columns: auto min-content; + grid-template-rows: 100%; + grid-gap: 10px; + + > * { + transition: opacity 0.5s; + } + &.waitingForStream { + background: transparent url('../assets/images/loader.svg') center no-repeat; + background-size: 40%; + > * { + opacity: 0; + } + } + + &.phoneBorder { + .gm-video { + border: 8px solid #cbcecb; + border-radius: 27px; + outline: 7px solid #242424; + outline-offset: -13px; + } + } + + .gm-video-wrapper { + position: relative; + display: flex; + justify-content: center; + .gm-video { + max-width: 100%; + max-height: 100%; + width: auto; + height: fit-content; + align-self: center; + } + } + .gm-toolbar-wrapper { + background-color: #292929; + min-width: 50px; + overflow: scroll; + -ms-overflow-style: none; + scrollbar-width: none; + } + .gm-toolbar-wrapper::-webkit-scrollbar { + display: none; + } + + .gm-toolbar { + display: flex; + min-height: 100%; + flex-direction: column; + align-items: center; + + ul { + flex: 1; + display: flex; + flex-direction: column; + gap: 10px; + } + } + } } .gm-loader { position: relative; diff --git a/src/scss/components/_upload.scss b/src/scss/components/_upload.scss index 2bb7530..572fe7e 100644 --- a/src/scss/components/_upload.scss +++ b/src/scss/components/_upload.scss @@ -3,15 +3,6 @@ */ .device-renderer-instance { .gm { - &-wrapper { - display: inline-block; - border: 10px solid transparent; - } - - &-dragover { - border: 10px solid $accent-color-light; - } - &-upload-progress { display: block; position: absolute;