Skip to content

Commit

Permalink
rework Battery plugin UI / UX
Browse files Browse the repository at this point in the history
  • Loading branch information
jparez committed Jan 8, 2025
1 parent 4944a48 commit 13947ef
Show file tree
Hide file tree
Showing 19 changed files with 529 additions and 248 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ The player uses css variables to style some parts of the app, but the player is

Input

--gm-input-bg-color: #fff;
--gm-input-text-color: #000;

Design
Expand Down
4 changes: 1 addition & 3 deletions example/geny-window.css
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,6 @@ header {
--gm-btn-bg-color-disabled-hover: #ced4da;
--gm-btn-color-disabled: #6c757d;

--gm-input-bg-color: #ffffff;
--gm-input-text-color: #495057;

--gm-underline-color: var(--gm-primary-color);
Expand Down Expand Up @@ -231,8 +230,7 @@ header {
--gm-btn-bg-color-disabled-hover: #828282;
--gm-btn-color-disabled: #c4c4c4;

--gm-input-bg-color: #fff;
--gm-input-text-color: #000;
--gm-input-text-color: #fff;

--gm-underline-color: var(--gm-text-color);

Expand Down
3 changes: 3 additions & 0 deletions src/assets/images/ic_battery_charging.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/images/ic_battery_empty.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/images/ic_battery_not_charging.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions src/assets/images/ic_close-modal.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
204 changes: 103 additions & 101 deletions src/plugins/Battery.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const OverlayPlugin = require('./util/OverlayPlugin');
const {slider, switchButton, textInput} = require('./util/components');

/**
* Instance battery plugin.
Expand Down Expand Up @@ -38,8 +39,14 @@ module.exports = class Battery extends OverlayPlugin {
return;
}

this.updateUIBatteryChargingState(values[0] !== 'discharging');
this.onBatteryLevelChange(values[1]);
// Update only UI
this.chargingInput.setState(values[0] !== 'discharging');

this.updateUIBatteryChargingState();

this.chargeSlider.setValue(values[1], false);
this.chargeInput.setValue(values[1]);
this.updateUIBatteryChargingPercent(values[1]);
});
}

Expand Down Expand Up @@ -67,43 +74,34 @@ module.exports = class Battery extends OverlayPlugin {
*/
renderWidget() {
// Create elements
this.widget = document.createElement('div');
this.container = document.createElement('div');

// Generate title
const title = document.createElement('div');
title.className = 'gm-title';
title.innerHTML = this.i18n.BATTERY_TITLE || 'Battery';
this.container.appendChild(title);

const {modal, container} = this.createTemplateModal({
title: this.i18n.BATTERY_TITLE || 'Battery',
classes: 'gm-battery-plugin',
width: 378,
height: 331,
});
this.widget = modal;
this.container = container;
// Generate input rows
const inputs = document.createElement('div');
inputs.className = 'gm-inputs';
const batteryLevelLabel = this.i18n.BATTERY_CHARGE_LEVEL || 'Charge level';
const batteryLevelLabel = this.i18n.BATTERY_CHARGE_LEVEL || 'Battery level';
inputs.innerHTML = '<label>' + batteryLevelLabel + '</label>';

// Create charge level inputs
inputs.appendChild(this.createLevelSection());

// Add charging label
const chargingLabel = document.createElement('label');
chargingLabel.innerHTML = this.i18n.BATTERY_CHARGE_STATE || 'State of charge';
chargingLabel.innerHTML = this.i18n.BATTERY_CHARGE_STATE || 'Charging state';
inputs.appendChild(chargingLabel);

// Add charging section
inputs.appendChild(this.createChargingSection());

// Setup
this.container.appendChild(inputs);
this.widget.className = 'gm-overlay gm-battery-plugin gm-hidden';

// Add close button
const close = document.createElement('div');
close.onclick = this.toggleWidget.bind(this);
close.className = 'gm-close-btn';

this.widget.appendChild(close);
this.widget.appendChild(this.container);

this.instance.root.appendChild(this.widget);
}
Expand All @@ -115,17 +113,25 @@ module.exports = class Battery extends OverlayPlugin {
*/
createChargingSection() {
const chargingGroup = document.createElement('div');
this.chargingInput = document.createElement('input');
this.chargingStatus = document.createElement('div');
chargingGroup.className = 'gm-charging-group';
this.chargingInput.type = 'checkbox';
this.chargingInput.className = 'gm-charging-checkbox';
this.chargingInput.onchange = this.toggleChargingState.bind(this);
this.chargingInput.checked = true;

this.chargingImage = document.createElement('div');
this.chargingImage.className = 'gm-charging-image';
chargingGroup.appendChild(this.chargingImage);

// Switch button for charging state
this.chargingInput = switchButton.createSwitch({
onChange: () => {
this.sendDataToInstance();
this.updateUIBatteryChargingState();
},
});

this.chargingStatus.className = 'gm-charging-status';
this.chargingStatus.innerHTML = 'Discharging';
chargingGroup.appendChild(this.chargingInput);
this.chargingStatus.innerHTML = 'Not charging';
chargingGroup.appendChild(this.chargingStatus);
chargingGroup.appendChild(this.chargingInput.element);

return chargingGroup;
}
Expand All @@ -136,92 +142,84 @@ module.exports = class Battery extends OverlayPlugin {
* @return {HTMLElement} Level section.
*/
createLevelSection() {
const chargeGroup = document.createElement('div');
chargeGroup.className = 'gm-charge-level-group';

const inputGroup = document.createElement('div');
this.chargeInput = document.createElement('input');
const chargeInputLabel = document.createElement('span');
chargeInputLabel.innerHTML = '%';
this.chargeInput.className = 'gm-charge-input';
this.chargeInput.type = 'number';
this.chargeInput.value = 50;
this.chargeInput.max = 100;
this.chargeInput.min = 0;
this.chargeInput.step = 1;
this.chargeInput.oninput = this.onBatteryLevelChangeEvent.bind(this);
inputGroup.appendChild(this.chargeInput);
inputGroup.appendChild(chargeInputLabel);
chargeGroup.appendChild(inputGroup);

const sliderGroup = document.createElement('div');
this.chargeSlider = document.createElement('input');
this.chargeSlider.className = 'gm-charge-slider';
this.chargeSlider.type = 'range';
this.chargeSlider.orient = 'vertical';
this.chargeSlider.max = 100;
this.chargeSlider.min = 0;
this.chargeSlider.step = 1;
this.chargeSlider.value = 50;
this.chargeSlider.onchange = this.onBatteryLevelChangeEvent.bind(this);
sliderGroup.appendChild(this.chargeSlider);
chargeGroup.appendChild(sliderGroup);
this.chargeGroup = document.createElement('div');
this.chargeGroup.className = 'gm-charge-level-group';

// Charge level image
const chargeImageGroup = document.createElement('div');
this.chargeImage = document.createElement('div');
chargeImageGroup.className = 'gm-charge-image-group';
const chargeImage = document.createElement('div');
const chargeImageOverlayContainer = document.createElement('div');
chargeImageOverlayContainer.className = 'gm-charge-image-overlay-container';
this.chargeImageOverlay = document.createElement('div');
this.chargeImage.className = 'gm-charge-image';
chargeImage.className = 'gm-charge-image';
this.chargeImageOverlay.className = 'gm-charge-image-overlay';
this.chargeImageOverlay.style.cssText = 'height: ' + 40 + '%;';
chargeImageGroup.appendChild(this.chargeImage);
this.chargeImage.appendChild(this.chargeImageOverlay);
chargeGroup.appendChild(chargeImageGroup);
this.chargeImageOverlay.style.height = '50%;';
chargeImageGroup.appendChild(chargeImage);
chargeImageOverlayContainer.appendChild(this.chargeImageOverlay);
chargeImageGroup.appendChild(chargeImageOverlayContainer);
this.chargeGroup.appendChild(chargeImageGroup);

return chargeGroup;
}
const sliderGroup = document.createElement('div');
sliderGroup.style.display = 'flex';

// slider range for battery level
this.chargeSlider = slider.createSlider({
min: 0,
max: 100,
value: 50,
onChange: (value) => {
this.chargeInput.setValue(value);
this.updateUIBatteryChargingPercent(value);
this.sendDataToInstance();
},
onCursorMove: (value) => {
// update UI withous sending data to instance
this.chargeInput.setValue(value);
this.updateUIBatteryChargingPercent(value);
},
});

/**
* Display or hide the widget.
*/
sliderGroup.appendChild(this.chargeSlider.element);
this.chargeGroup.appendChild(sliderGroup);

/**
* Toggle Instance charging status between 'charging' and 'discharging';
*/
toggleChargingState() {
this.chargingStatus.classList.toggle('charging');
// Charge level input
const inputGroup = document.createElement('div');
this.chargeInput = textInput.createTextInput({
appendText: '%',
value: '50',
regexFilter: /^(0?[0-9]{1,2}|100)$/,
onChange: (value) => {
this.chargeSlider.setValue(value);
this.updateUIBatteryChargingPercent(value);
this.sendDataToInstance();
},
});

const chargingLabel = this.i18n.BATTERY_CHARGING || 'Charging';
const dischargingLabel = this.i18n.BATTERY_DISCHARGING || 'Discharging';
this.chargeInput.element.className = 'gm-charge-input';

inputGroup.appendChild(this.chargeInput.element);
this.chargeGroup.appendChild(inputGroup);

this.chargingStatus.innerHTML = this.chargingInput.checked ? chargingLabel : dischargingLabel;
this.sendDataToInstance();
return this.chargeGroup;
}

/**
* Display or hide the widget.
*/

/**
* Update widget charging state UI.
*
* @param {boolean} charging Whether or not the battery is charging.
*/
updateUIBatteryChargingState(charging) {
this.chargingInput.checked = charging;
this.chargingStatus.classList[charging ? 'add' : 'remove']('charging');
updateUIBatteryChargingState() {
this.chargingImage.classList[this.chargingInput.getState() ? 'add' : 'remove']('charging');

const chargingLabel = this.i18n.BATTERY_CHARGING || 'Charging';
const dischargingLabel = this.i18n.BATTERY_DISCHARGING || 'Discharging';
const dischargingLabel = this.i18n.BATTERY_DISCHARGING || 'Not charging';

this.chargingStatus.innerHTML = charging ? chargingLabel : dischargingLabel;
}

/**
* Handle battery level change events (slider & text input).
*
* @param {Event} event Event.
*/
onBatteryLevelChangeEvent(event) {
const value = Number(event.target.value);
if (this.onBatteryLevelChange(value)) {
this.sendDataToInstance();
}
this.chargingStatus.innerHTML = this.chargingInput.getState() ? chargingLabel : dischargingLabel;
}

/**
Expand All @@ -230,25 +228,29 @@ module.exports = class Battery extends OverlayPlugin {
* @param {number} value Battery level.
* @return {boolean} Whether or not battery level has been applied.
*/
onBatteryLevelChange(value) {
updateUIBatteryChargingPercent(value) {
value = Number(value);
if (Number.isNaN(value)) {
return false;
}

value = Math.min(Math.max(0, value), 100);
this.chargeSlider.value = value;
this.chargeInput.value = value;
this.chargeImageOverlay.style.cssText = 'height: ' + (value * 0.7 + 4) + '%;';
this.chargeImageOverlay.style.cssText = 'height: ' + value + '%';
this.chargeGroup.classList.remove('low', 'medium');
if (value <= 10) {
this.chargeGroup.classList.add('low');
} else if (value <= 20) {
this.chargeGroup.classList.add('medium');
}
return true;
}

/**
* Send information to instance.
*/
sendDataToInstance() {
const level = Number(this.chargeInput.value);
const charging = this.chargingInput.checked ? 'charging' : 'discharging';
const level = Number(this.chargeInput.getValue());
const charging = this.chargingInput.getState() ? 'charging' : 'discharging';
const json = {
channel: 'battery',
messages: ['set state level ' + level, 'set state status ' + charging],
Expand Down
10 changes: 4 additions & 6 deletions src/plugins/FingerPrint.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,7 @@ module.exports = class FingerPrint extends OverlayPlugin {
}

// update switch
document
.querySelector('.gm-fingerprint-dialog-recognized-fp-by-default-status')
.setState(value);
this.recognizedFPByDefaultStatus.setState(value);
break;
default:
break;
Expand Down Expand Up @@ -202,16 +200,16 @@ module.exports = class FingerPrint extends OverlayPlugin {
recognizedFPByDefaultLabel.innerHTML =
this.i18n.FINGERPRINT_RECOGNIZED_FP_BY_DEFAULT_LABEL || 'Recognized by default';

const recognizedFPByDefaultStatus = switchButton.createSwitch({
this.recognizedFPByDefaultStatus = switchButton.createSwitch({
onChange: (value) => {
this.state.isRecognizedFPByDefault = value;
},
});

recognizedFPByDefaultStatus.classList.add('gm-fingerprint-dialog-recognized-fp-by-default-status');
this.recognizedFPByDefaultStatus.element.classList.add('gm-fingerprint-dialog-recognized-fp-by-default-status');

recognizedFPByDefaultDiv.appendChild(recognizedFPByDefaultLabel);
recognizedFPByDefaultDiv.appendChild(recognizedFPByDefaultStatus);
recognizedFPByDefaultDiv.appendChild(this.recognizedFPByDefaultStatus.element);

headerDiv.appendChild(authRequiredDiv);
headerDiv.appendChild(recognizedFPByDefaultDiv);
Expand Down
Loading

0 comments on commit 13947ef

Please sign in to comment.