Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GPII-4049: Volume Control v3 #203

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 26 additions & 19 deletions src/main/common/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -471,27 +471,34 @@ gpii.app.ejectUSB = function (browserWindow, messageChannel, messages) {
};

/**
* Get the actual volume value. If there are an error or no value return the default
* volume value
* @param {Object} browserWindow - An Electron `BrowserWindow` object.
* @param {String} messageChannel - The channel to which the message should be sent.
* @return {Number} - The actual value of the volume
* A standard volume control, it can simulate volume up, down and mute
* @param {String} command - accepts "up", "down" and "mute" as commands
*/
gpii.app.getVolumeValue = function (browserWindow, messageChannel) {
var defaultVolumeValue = 0.5;
try {
var volumeValue = gpii.windows.nativeSettingsHandler.GetVolume().value;
gpii.app.volumeControl = function (command) {
var WM_APPCOMMAND = 0x319, // https://docs.microsoft.com/windows/win32/inputdev/wm-appcommand
APPCOMMAND_VOLUME_MUTE = 8,
APPCOMMAND_VOLUME_DOWN = 9,
APPCOMMAND_VOLUME_UP = 10,
action = false; // by default there will be no action taken

// determine which command to use
switch (command) {
case "up":
action = APPCOMMAND_VOLUME_UP;
break;
case "down":
action = APPCOMMAND_VOLUME_DOWN;
break;
case "mute":
action = APPCOMMAND_VOLUME_MUTE;
break;
}

if (isNaN(volumeValue)) {
gpii.app.notifyWindow(browserWindow, messageChannel, defaultVolumeValue);
return defaultVolumeValue;
} else {
gpii.app.notifyWindow(browserWindow, messageChannel, volumeValue);
return volumeValue;
}
} catch (err) {
fluid.log(fluid.logLevel.WARN, err);
return defaultVolumeValue;
// Send the volume up/down command directly to the task tray (rather than a simulated key press)
if (action) {
gpii.windows.messages.sendMessage("Shell_TrayWnd", WM_APPCOMMAND, 0, gpii.windows.makeLong(0, action));
} else {
fluid.log(fluid.logLevel.WARN, "gpii.app.volumeControl: Invalid volume command - " + command);
}
};

Expand Down
11 changes: 4 additions & 7 deletions src/main/dialogs/quickSetStrip/qssWidgetDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ fluid.defaults("gpii.app.qssWidget", {
// USB related events
onQssOpenUsbRequested: null,
onQssUnmountUsbRequested: null,
onQssGetVolumeRequested: null,
onQssVolumeControl: null,
onQssReApplyPreferencesRequired: null,
onQssGetEnvironmentalLoginKeyRequested: null,
onLearnMoreClicked: null,
Expand Down Expand Up @@ -158,12 +158,9 @@ fluid.defaults("gpii.app.qssWidget", {
"{arguments}.1" // messages
]
},
onQssGetVolumeRequested: {
funcName: "gpii.app.getVolumeValue",
args: [
"{qssWidget}.dialog",
"{arguments}.0" // messageChannel
]
onQssVolumeControl: {
funcName: "gpii.app.volumeControl",
args: [ "{arguments}.0" ]
},
onQssReApplyPreferencesRequired: {
funcName: "{app}.reApplyPreferences"
Expand Down
1 change: 0 additions & 1 deletion src/main/gpiiConnector.js
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,6 @@ fluid.defaults("gpii.app.dev.gpiiConnector.qss", {
"http://registry\\.gpii\\.net/common/DPIScale": { value: 0 },
"http://registry\\.gpii\\.net/common/highContrastTheme": { value: "regular-contrast" },
"http://registry\\.gpii\\.net/common/selfVoicing/enabled": { value: false },
"http://registry\\.gpii\\.net/common/volume": { value: gpii.app.getVolumeValue() },
"http://registry\\.gpii\\.net/applications/com\\.microsoft\\.windows\\.colorFilters.FilterType": {value: 0 },
// use the initial value of the language as default setting
"http://registry\\.gpii\\.net/common/language": { value: "{systemLanguageListener}.model.configuredLanguage" },
Expand Down
14 changes: 2 additions & 12 deletions src/main/qss.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ fluid.defaults("gpii.app.qssWrapper", {

// paths might be needed for some reason
settingPaths: {
language: "http://registry\\.gpii\\.net/common/language",
volume: "http://registry\\.gpii\\.net/common/volume"
language: "http://registry\\.gpii\\.net/common/language"
},

settingMessagesPrefix: "gpii_app_qss_settings",
Expand Down Expand Up @@ -685,22 +684,13 @@ gpii.app.qssWrapper.loadSettings = function (assetsManager, installedLanguages,
return setting.path === settingOptions.settingPaths.language;
});

var volumeSetting = fluid.find_if(loadedSettings, function (setting) {
return setting.path === settingOptions.settingPaths.volume;
});

// we double check if this setting exists because can be disabled via siteConfig's buttonList
if (fluid.isValue(languageSetting)) {
gpii.app.qssWrapper.populateLanguageSettingOptions(settingOptions, locale, installedLanguages, languageSetting);
// sync the language value as well
languageSetting.value = locale;
}

// we double check if this setting exists because can be disabled via siteConfig's buttonList
if (fluid.isValue(volumeSetting)) {
volumeSetting.value = gpii.windows.nativeSettingsHandler.GetVolume().value;
}

/*
* Hide settings
*/
Expand Down Expand Up @@ -1032,7 +1022,7 @@ fluid.defaults("gpii.app.qssInWrapper", {
fluid.defaults("gpii.app.undoInWrapper", {
gradeNames: "gpii.app.undoStack",
// paths of settings that are not undoable
unwatchedSettings: ["appTextZoom"],
unwatchedSettings: ["appTextZoom", "volume-control"],

listeners: {
"onChangeUndone.applyChange": {
Expand Down
20 changes: 10 additions & 10 deletions src/renderer/qss/js/qssSettingButtons.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@
});

/**
* State of the Volume button. If the value is 0 the state of the button is ON, any other value is OFF.
* @typedef {Number} volumeState
* State of the Volume button. If the value is `true` the state of the button is ON.
* @typedef {Boolean} volumeState
*/

/**
Expand All @@ -189,21 +189,21 @@
* @param {volumeState} value - The state of the button.
*/
gpii.qss.volumeButtonPresenter.hideTitle = function (titleElem, value) {
if (value === 0) {
if (value) {
titleElem.hide();
} else {
titleElem.show();
}
};

/**
* If available in the setting's schema, shows the specified image for the button when the value of setting is 0.
* If available in the setting's schema, shows the specified image for the button when the volume switch is ON.
* @param {jQuery} imageElem - The jQuery object corresponding to the image of the button.
* @param {String} image - The path to the image.
* @param {volumeState} value - The state of the button.
*/
gpii.qss.volumeButtonPresenter.renderImage = function (imageElem, image, value) {
if (image && value === 0) {
if (image && value) {
var maskImageValue = fluid.stringTemplate("url(\"%image\")", {
image: image
});
Expand All @@ -220,28 +220,28 @@
/**
* Returns the caption of the toggle button that needs to be shown below the button's
* title in case the state of the button is "on".
* In the case of the Volume widget, the caption message is shown only when the value is 0.
* In the case of the Volume widget, the caption message is shown only when the volume switch is ON.
* @param {volumeState} value - The state of the button.
* @param {Object} messages - An object containing internationalizable messages for
* this component.
* @param {Component} that - The `gpii.qss.volumeButtonPresenter` instance.
* @param {gpii.qss.volumeButtonPresenter} that - The `gpii.qss.volumeButtonPresenter` instance.
* @return {String} The caption message for the toggle button.
*/
gpii.qss.volumeButtonPresenter.getCaption = function (value, messages, that) {
that.toggleStyle(value);
that.renderImage(value);
that.hideTitle(value);
return value === 0 ? messages.caption : "";
return value ? messages.caption : "";
};

/**
* Change the color of the "Volume & Mute" button if the value is 0.
* Change the color of the "Volume & Mute" button if the volume switch is ON.
* @param {jQuery} container - The jQuery container object
* @param {String} style - Contains css class
* @param {volumeState} value - The state of the button.
*/
gpii.qss.volumeButtonPresenter.toggleStyle = function (container, style, value) {
if (value === 0) {
if (value) {
container.addClass(style);
} else {
container.removeClass(style);
Expand Down
133 changes: 48 additions & 85 deletions src/renderer/qssWidget/js/qssVolumeWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@
model: {
setting: {},
messages: {},
value: "{that}.model.setting.value",
previousValue: "{that}.model.setting.schema.previousValue",
messageChannel: "volumeMessageChannel" // Channel listening for messages related volume/mute functionality
value: "{that}.model.setting.value"
},
events: {
onHeightChanged: null
Expand All @@ -53,27 +51,16 @@
this: "{that}.dom.helpImage",
method: "attr",
args: ["src", "{that}.model.setting.schema.helpImage"]
},
"onCreate.registerIpcListener": {
funcName: "gpii.psp.registerIpcListener",
args: ["{that}.model.messageChannel", "{volume}.loadActualValue"]
},
"onCreate.sendGetVolumeRequest": {
funcName: "{channelNotifier}.events.onQssGetVolumeRequested.fire",
args: ["{that}.model.messageChannel"]
}
},
modelListeners: {
value: {
funcName: "gpii.qssWidget.volume.updateSwitchState",
args: ["{switchButton}", "{change}.value"]
"setting.value": {
func: "{channelNotifier}.events.onQssWidgetSettingAltered.fire",
args: ["{that}.model.setting"],
includeSource: "fromWidget"
}
},
invokers: {
loadActualValue: {
funcName: "gpii.qssWidget.volume.loadActualValue",
args: ["{volume}", "{arguments}.0"]
},
calculateHeight: {
funcName: "gpii.qssWidget.calculateHeight",
args: [
Expand All @@ -90,13 +77,25 @@
options: {
sounds: "{volume}.options.sounds",
model: {
setting: "{volume}.model.setting",
messages: "{volume}.model.messages",
previousValue: "{volume}.model.previousValue",
value: "{volume}.model.setting.value"
messages: "{volume}.model.messages"
},
events: {
onNotificationRequired: "{volume}.events.onNotificationRequired"
invokers: {
activateIncBtn: {
funcName: "gpii.qssWidget.volume.activateButton",
args: [
"up", // volume up
"{volume}",
"{channelNotifier}.events.onQssVolumeControl" // volume control event
]
},
activateDecBtn: {
funcName: "gpii.qssWidget.volume.activateButton",
args: [
"down", // volume down
"{volume}",
"{channelNotifier}.events.onQssVolumeControl" // volume control event
]
}
}
}
},
Expand All @@ -105,12 +104,7 @@
container: "{that}.dom.switch",
options: {
model: {
enabled: {
expander: {
funcName: "gpii.qssWidget.volume.transformValue",
args: ["{volume}.model.setting.value"]
}
},
enabled: "{volume}.model.value",
messages: {
on: "{volume}.model.messages.on",
off: "{volume}.model.messages.off"
Expand All @@ -119,78 +113,47 @@
invokers: {
toggleModel: {
funcName: "gpii.qssWidget.volume.toggleModel",
args: ["{that}", "{volume}", "{stepper}", "{channelNotifier}.events.onQssWidgetSettingAltered"]
args: [
"{that}",
"{channelNotifier}.events.onQssVolumeControl" // volume control event
]
}
}
}
}
}
});

/**
* Set the actual volume value in the case the volume is changed through the Windows itself
* @param {Component} that - The `gpii.psp.widgets.volume` instance.
* @param {Number} value - The value of the setting.
*/
gpii.qssWidget.volume.loadActualValue = function (that, value) {
that.applier.change("value", value, null, "fromWidget");
};

/**
* Invoked whenever the volume value is changed and updating the state of the
* volume switch button.
* @param {Component} switchButton - The `gpii.psp.widgets.volume.switchButton` instance.
* @param {Number} value - The value of the setting.
* Invoked whenever the either button is activated. Fires the onQssVolumeControl
* with the appropriate action ("up", or "down"). This activates the windows control
* for volume up or down
* @param {String} action - it can be up or down.
* @param {gpii.qssWidget.volume} volumeWidget - The `gpii.psp.widgets.volume.switchButton` instance.
* @param {fluid.event} volumeControlEvent - the onQssVolumeControl event.
*/
gpii.qssWidget.volume.updateSwitchState = function (switchButton, value) {
if (!value !== switchButton.model.enabled) {
switchButton.applier.change("enabled", !switchButton.model.enabled, null, "fromWidget");
} else if (value !== 0 && switchButton.model.enabled) {
switchButton.applier.change("enabled", !switchButton.model.enabled, null, "fromWidget");
}
};
gpii.qssWidget.volume.activateButton = function (action, volumeWidget, volumeControlEvent) {
volumeControlEvent.fire(action);

/**
* Transforms a number value to boolean.
* @param {Number} value - The value of the setting
* @return {Boolean} The modified value.
*/
gpii.qssWidget.volume.transformValue = function (value) {
return !value;
// Switch mute toggle if already muted
if (volumeWidget.model.value) {
volumeWidget.applier.change("value", false, null, "fromWidget");
}
};

/**
* Invoked whenever the user has activated the "switch" UI element (either
* by clicking on it or pressing "Space" or "Enter"). What this function
* does is to update model value and update settings.
* @param {Component} that - The `gpii.psp.widgets.volume.switchButton` instance.
* @param {Component} volumeWidget - The `gpii.psp.widgets.volume` instance.
* @param {Component} stepper - The `gpii.psp.widgets.volumeStepper instance.
* #param {EventListener} event - onQssWidgetSettingAltered event
* does is to change the `enabled` model property to its opposite value and update settings.
* @param {gpii.qssWidget.volume.switchButton} that - The `gpii.psp.widgets.switch` instance.
* @param {fluid.event} volumeControlEvent - the onQssVolumeControl event.
*/
gpii.qssWidget.volume.toggleModel = function (that, volumeWidget, stepper) {
if (!volumeWidget.model.setting.value && !that.model.enabled) {
return;
}

if (volumeWidget.model.setting.value !== 0) {
volumeWidget.applier.change("previousValue", volumeWidget.model.setting.value, null, "fromWidget");
stepper.applier.change("previousValue", volumeWidget.model.setting.value, null, "fromWidget");
that.applier.change("previousValue", volumeWidget.model.setting.value, null, "fromWidget");
}

if (!that.model.enabled && volumeWidget.model.setting.value !== 0) {
volumeWidget.applier.change("value", 0, null, "fromWidget");
stepper.applier.change("value", 0, null, "fromWidget");

} else {
volumeWidget.applier.change("value", volumeWidget.model.previousValue, null, "fromWidget");
stepper.applier.change("value", volumeWidget.model.previousValue, null, "fromWidget");

}
gpii.qssWidget.volume.toggleModel = function (that, volumeControlEvent) {
// toggle the widget
that.applier.change("enabled", !that.model.enabled, null, "fromWidget");

// update the volume setting
// This event has already been triggered in the previous block.
// event.fire(volumeWidget.model.setting);
// use the onQssVolumeControl event to send the mute event
volumeControlEvent.fire("mute");
};
})(fluid);
Loading