Commit cbdf887a authored by abicur's avatar abicur

[NEW] Add support of MacBooks Touch Bar

parent ad9e764f
......@@ -32,6 +32,7 @@
"Enter_your_server_URL": "Enter your server URL",
"Error": "Error",
"&File": "&File",
"Formatting": "Formatting",
"&Forward": "&Forward",
"Full screen": "Full screen",
"&Help": "&Help",
......@@ -74,6 +75,7 @@
"Save_Image": "Save Image",
"Select_a_screen_to_share": "Select a screen to share",
"Select &all": "Select &all",
"Select_server": "Select server",
"Server_Failed_to_Load": "Server Failed to Load",
"Server list": "Server list",
"Share_Your_Screen": "Share Your Screen",
......
......@@ -32,6 +32,7 @@
"Enter_your_server_URL": "Введите URL Вашего сервера",
"Error": "Ошибка",
"&File": "&Файл",
"Formatting": "Форматирование",
"&Forward": "Вперед",
"Full screen": "Полноэкранный режим",
"&Help": "&Справка",
......@@ -73,6 +74,7 @@
"Reset zoom": "Восстановить масштаб",
"Select_a_screen_to_share": "Выберите экран для совместного использования",
"Select &all": "Выделить все",
"Select_server": "Выбрать сервер",
"Server_Failed_to_Load": "Не удалось загрузить сервер",
"Server list": "Список серверов",
"Share_Your_Screen": "Демонстрация Вашего экрана",
......
......@@ -2,6 +2,7 @@ import { remote } from 'electron';
import servers from './servers';
import sidebar from './sidebar';
import webview from './webview';
import { TouchBarBuilder, SelectServerPanel, FormattingPanel } from './touchBar';
const { app, getCurrentWindow, shell } = remote;
......@@ -186,6 +187,16 @@ export default () => {
dock.setState({ status });
});
if (process.platform === 'darwin') {
servers.once('active-setted', () => {
const touchBar = new TouchBarBuilder()
.addSelectServerPanel(new SelectServerPanel())
.addFormattingPanel(new FormattingPanel())
.build();
getCurrentWindow().setTouchBar(touchBar);
});
}
servers.restoreActive();
updatePreferences();
......
import { remote } from 'electron';
import { EventEmitter } from 'events';
import servers from './servers';
import webview from './webview';
import i18n from '../i18n/index.js';
const { TouchBar, nativeImage } = remote.require('electron');
const { TouchBarButton, TouchBarLabel, TouchBarSegmentedControl, TouchBarScrubber, TouchBarPopover, TouchBarGroup } = TouchBar;
export class SelectServerPanel extends EventEmitter {
constructor() {
super();
this._MAX_LENGTH_FOR_SEGMENTS_CONTROL = 76 - i18n.__('Select_server').length;
this._patternRemoveSchema = new RegExp('^http(s?):\/\/');
this._hosts = [];
this._setHostsArray();
this._subscribe();
}
_isSegmentedControl() {
return this.control && this.control.hasOwnProperty('selectedIndex');
}
_getActiveServerIndex() {
return this._hosts.findIndex((value) => value.host === servers.active);
}
_setActiveServer() {
if (this._isSegmentedControl()) {
this.control.selectedIndex = this._getActiveServerIndex();
} else {
this._update();
}
}
_setHostsArray() {
this._hosts = Object.keys(servers.hosts).map((key) => ({ label: key.replace(this._patternRemoveSchema, ''), host: key }));
this._hosts = this._trimHostsNames(this._hosts);
}
_getTotalLengthOfHostsNames() {
return this._hosts.reduce((acc, host) => acc + host.label.length, 0);
}
_update() {
this._setHostsArray();
if (this.control) {
if (this._isSegmentedControl()) {
this.control.segments = this._hosts;
} else {
this.control.items = this._hosts;
}
} else {
this.build();
}
}
build() {
const popoverItems = this._buildSelectServersPopoverItems();
this.touchBarPopover = new TouchBarPopover({
label: i18n.__('Select_server'),
items: new TouchBar({
items: popoverItems,
}),
});
return this.touchBarPopover;
}
_buildSelectServersPopoverItems() {
const items = [
new TouchBarLabel({ label: i18n.__('Select_server') }),
];
// The maximum length of available display area is limited. If exceed the length of displayed data, then
// touchbar element is not displayed. If the length of displayed host names exceeds the limit, then
// the touchBarScrubber is used. In other case SegmentedControl is used.
const hostsNamesLength = this._getTotalLengthOfHostsNames();
if (this._hosts.length) {
if (hostsNamesLength <= this._MAX_LENGTH_FOR_SEGMENTS_CONTROL) {
items.push(this._buildTouchBarSegmentedControl());
} else {
items.push(this._buildTouchBarScrubber());
}
}
return items;
}
_buildTouchBarSegmentedControl() {
this.control = new TouchBarSegmentedControl({
segmentStyle: 'separated',
selectedIndex: this._getActiveServerIndex(),
segments: this._hosts,
change: (index) => {
servers.setActive(this._hosts[index].host);
},
});
return this.control;
}
_buildTouchBarScrubber() {
this.control = new TouchBarScrubber({
selectedStyle: 'background',
showArrowButtons: true,
mode: 'fixed',
items: this._hosts,
highlight: (index) => {
servers.setActive(this._hosts[index].host);
},
});
return this.control;
}
_subscribe() {
servers.on('active-setted', () => this._setActiveServer());
servers.on('host-added', () => this._update());
servers.on('host-removed', () => this._update());
}
/**
* If it is possible to fit the hosts names to the specific limit, then trim the hosts names to the format "open.rocke.."
* @param arr {Array} array of hosts
* @returns {Array} array of hosts
*/
_trimHostsNames(arr) {
const hostsNamesLength = this._getTotalLengthOfHostsNames();
if (hostsNamesLength <= this._MAX_LENGTH_FOR_SEGMENTS_CONTROL) {
return arr;
}
// The total length of hosts names with reserved space for '..' characters
const amountOfCharsToDisplay = this._MAX_LENGTH_FOR_SEGMENTS_CONTROL - 2 * arr.length;
const amountOfCharsPerHost = Math.floor(amountOfCharsToDisplay / arr.length);
if (amountOfCharsPerHost > 0) {
let additionChars = amountOfCharsToDisplay % arr.length;
return arr.map((host) => {
if (amountOfCharsPerHost < host.label.length) {
let additionChar = 0;
if (additionChars) {
additionChar = 1;
additionChars--;
}
host.label = `${ host.label.slice(0, amountOfCharsPerHost + additionChar) }..`;
}
return host;
});
}
return arr;
}
}
export class FormattingPanel extends EventEmitter {
constructor() {
super();
this._buttonClasses = ['bold', 'italic', 'strike', 'code', 'multi-line'];
this._BACKGROUND_COLOR = '#A4A4A4';
}
build() {
const formatButtons = [];
this._buttonClasses.forEach((buttonClass) => {
const touchBarButton = new TouchBarButton({
backgroundColor: this._BACKGROUND_COLOR,
icon: nativeImage.createFromPath(`${ __dirname }/images/icon-${ buttonClass }.png`),
click: () => {
webview.getActive().executeJavaScript(`
var svg = document.querySelector("button svg[class$='${ buttonClass }']");
svg && svg.parentNode.click();
`.trim());
},
});
formatButtons.push(touchBarButton);
});
this._touchBarGroup = new TouchBarGroup({
items: [
new TouchBarLabel({ label: i18n.__('Formatting') }),
...formatButtons,
],
});
return this._touchBarGroup;
}
}
export class TouchBarBuilder extends EventEmitter {
constructor() {
super();
this._touchBarElements = {};
}
build() {
this._touchBar = new TouchBar({
items: Object.values(this._touchBarElements).map((element) => element.build()),
});
return this._touchBar;
}
addSelectServerPanel(panel) {
if (this._isPanel(panel)) {
this._touchBarElements.selectServerPanel = panel;
}
return this;
}
addFormattingPanel(panel) {
if (this._isPanel(panel)) {
this._touchBarElements.formattingtPanel = panel;
}
return this;
}
_isPanel(panel) {
return panel && typeof panel.build === 'function';
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment