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;