mirror of
https://github.com/finos/SymphonyElectron.git
synced 2024-11-26 02:40:24 -06:00
Typescript (Complete notification & notification settings modules) (#609)
* Typescript - Implement notification settings configuration window * Typescript - Completed notification and notification settings for Context Isolation * Typescript - Fix code comment * Typescript - Enable contextIsolation for all windows * Typescript - Fix notification setup condition
This commit is contained in:
parent
de6502035b
commit
5905b7507d
@ -110,10 +110,45 @@
|
||||
</table>
|
||||
</body>
|
||||
<script>
|
||||
|
||||
const apiCmds = {
|
||||
isOnline: 'is-online',
|
||||
getVersionInfo: 'get-version-info',
|
||||
registerLogger: 'register-logger',
|
||||
setBadgeCount: 'set-badge-count',
|
||||
badgeDataUrl: 'badge-data-url',
|
||||
activate: 'activate',
|
||||
registerBoundsChange: 'register-bounds-change',
|
||||
registerProtocolHandler: 'register-protocol-handler',
|
||||
registerActivityDetection: 'register-activity-detection',
|
||||
showNotificationSettings: 'show-notification-settings',
|
||||
sanitize: 'sanitize',
|
||||
bringToFront: 'bring-to-front',
|
||||
openScreenPickerWindow: 'open-screen-picker-window',
|
||||
popupMenu: 'popup-menu',
|
||||
optimizeMemoryConsumption: 'optimize-memory-consumption',
|
||||
optimizeMemoryRegister: 'optimize-memory-register',
|
||||
setIsInMeeting: 'set-is-in-meeting',
|
||||
setLocale: 'set-locale',
|
||||
openScreenSnippet: 'open-screen-snippet',
|
||||
keyPress: 'key-press',
|
||||
closeWindow: 'close-window',
|
||||
openScreenSharingIndicator: 'open-screen-sharing-indicator',
|
||||
closeScreenSharingIndicator: 'close-screen-sharing-indicator',
|
||||
downloadManagerAction: 'download-manager-action',
|
||||
getMediaSource: 'get-media-source',
|
||||
notification: 'notification',
|
||||
closeNotification: 'close-notification',
|
||||
};
|
||||
|
||||
var openConfigWin = document.getElementById('open-config-win');
|
||||
|
||||
openConfigWin.addEventListener('click', function() {
|
||||
ssf.showNotificationSettings();
|
||||
if (window.ssf) {
|
||||
ssf.showNotificationSettings();
|
||||
} else {
|
||||
postMessage(apiCmds.showNotificationSettings)
|
||||
}
|
||||
});
|
||||
|
||||
var notfEl = document.getElementById('notf');
|
||||
@ -281,7 +316,11 @@
|
||||
document.location.reload();
|
||||
});
|
||||
|
||||
window.addEventListener('message', (event) => console.log(event));
|
||||
window.addEventListener('message', (event) => console.log(event.data));
|
||||
|
||||
const postMessage = (method, data) => {
|
||||
window.postMessage({ method, data }, '*');
|
||||
}
|
||||
|
||||
</script>
|
||||
</html>
|
||||
|
@ -57,4 +57,4 @@
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
@ -66,12 +66,12 @@ ipcMain.on(apiName.symphonyApi, (event: Electron.Event, arg: IApiArgs) => {
|
||||
activityDetection.setWindowAndThreshold(event.sender, arg.period);
|
||||
}
|
||||
break;
|
||||
/*case ApiCmds.showNotificationSettings:
|
||||
case apiCmds.showNotificationSettings:
|
||||
if (typeof arg.windowName === 'string') {
|
||||
configureNotification.openConfigurationWindow(arg.windowName);
|
||||
windowHandler.createNotificationSettingsWindow(arg.windowName);
|
||||
}
|
||||
break;
|
||||
*/case apiCmds.sanitize:
|
||||
case apiCmds.sanitize:
|
||||
if (typeof arg.windowName === 'string') {
|
||||
sanitize(arg.windowName);
|
||||
}
|
||||
|
@ -8,7 +8,9 @@ import DesktopCapturerSource = Electron.DesktopCapturerSource;
|
||||
import { apiName, WindowTypes } from '../common/api-interface';
|
||||
import { isMac, isWindowsOS } from '../common/env';
|
||||
import { i18n } from '../common/i18n';
|
||||
import { logger } from '../common/logger';
|
||||
import { getCommandLineArgs, getGuid } from '../common/utils';
|
||||
import { notification } from '../renderer/notification';
|
||||
import { AppMenu } from './app-menu';
|
||||
import { handleChildWindow } from './child-window-handler';
|
||||
import { config, IConfig } from './config-handler';
|
||||
@ -50,6 +52,7 @@ export class WindowHandler {
|
||||
sandbox: true,
|
||||
nodeIntegration: false,
|
||||
devTools: false,
|
||||
contextIsolation: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -70,6 +73,27 @@ export class WindowHandler {
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
sandbox: true,
|
||||
contextIsolation: true,
|
||||
},
|
||||
winKey: getGuid(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification settings window opts
|
||||
*/
|
||||
private static getNotificationSettingsOpts(): ICustomBrowserWindowConstructorOpts {
|
||||
return {
|
||||
width: 460,
|
||||
height: 360,
|
||||
show: false,
|
||||
modal: true,
|
||||
autoHideMenuBar: true,
|
||||
webPreferences: {
|
||||
sandbox: true,
|
||||
nodeIntegration: false,
|
||||
devTools: false,
|
||||
contextIsolation: true,
|
||||
},
|
||||
winKey: getGuid(),
|
||||
};
|
||||
@ -94,6 +118,7 @@ export class WindowHandler {
|
||||
sandbox: true,
|
||||
nodeIntegration: false,
|
||||
devTools: false,
|
||||
contextIsolation: true,
|
||||
},
|
||||
winKey: getGuid(),
|
||||
};
|
||||
@ -114,6 +139,7 @@ export class WindowHandler {
|
||||
sandbox: true,
|
||||
nodeIntegration: false,
|
||||
devTools: false,
|
||||
contextIsolation: true,
|
||||
},
|
||||
winKey: getGuid(),
|
||||
};
|
||||
@ -155,10 +181,11 @@ export class WindowHandler {
|
||||
private screenPickerWindow: Electron.BrowserWindow | null = null;
|
||||
private screenSharingIndicatorWindow: Electron.BrowserWindow | null = null;
|
||||
private basicAuthWindow: Electron.BrowserWindow | null = null;
|
||||
private notificationSettingsWindow: Electron.BrowserWindow | null = null;
|
||||
|
||||
constructor(opts?: Electron.BrowserViewConstructorOptions) {
|
||||
// Settings
|
||||
this.config = config.getConfigFields([ 'isCustomTitleBar', 'mainWinPos', 'minimizeOnClose' ]);
|
||||
// Use these variables only on initial setup
|
||||
this.config = config.getConfigFields([ 'isCustomTitleBar', 'mainWinPos', 'minimizeOnClose', 'notificationSettings' ]);
|
||||
this.globalConfig = config.getGlobalConfigFields([ 'url', 'crashReporter' ]);
|
||||
|
||||
this.windows = {};
|
||||
@ -258,7 +285,7 @@ export class WindowHandler {
|
||||
return this.destroyAllWindow();
|
||||
}
|
||||
|
||||
if (this.config.minimizeOnClose) {
|
||||
if (config.getConfigFields([ 'minimizeOnClose' ]).minimizeOnClose) {
|
||||
event.preventDefault();
|
||||
isMac ? this.mainWindow.hide() : this.mainWindow.minimize();
|
||||
} else {
|
||||
@ -318,6 +345,11 @@ export class WindowHandler {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'notification-settings':
|
||||
if (this.notificationSettingsWindow && windowExists(this.notificationSettingsWindow)) {
|
||||
this.notificationSettingsWindow.close();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -488,6 +520,66 @@ export class WindowHandler {
|
||||
ipcMain.once('basic-auth-login', login);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and displays notification settings window
|
||||
*
|
||||
* @param windowName
|
||||
*/
|
||||
public createNotificationSettingsWindow(windowName: string): void {
|
||||
const opts = WindowHandler.getNotificationSettingsOpts();
|
||||
// This prevents creating multiple instances of the
|
||||
// notification configuration window
|
||||
if (this.notificationSettingsWindow && !this.notificationSettingsWindow.isDestroyed()) {
|
||||
if (this.notificationSettingsWindow.isMinimized()) {
|
||||
this.notificationSettingsWindow.restore();
|
||||
}
|
||||
this.notificationSettingsWindow.focus();
|
||||
return;
|
||||
}
|
||||
const allWindows = BrowserWindow.getAllWindows();
|
||||
const selectedParentWindow = allWindows.find((window) => {
|
||||
return (window as ICustomBrowserWindow).winName === windowName;
|
||||
});
|
||||
|
||||
if (selectedParentWindow) {
|
||||
opts.parent = selectedParentWindow;
|
||||
}
|
||||
|
||||
this.notificationSettingsWindow = createComponentWindow('notification-settings', opts);
|
||||
this.notificationSettingsWindow.setVisibleOnAllWorkspaces(true);
|
||||
this.notificationSettingsWindow.webContents.on('did-finish-load', () => {
|
||||
if (this.notificationSettingsWindow && windowExists(this.notificationSettingsWindow)) {
|
||||
let screens: Electron.Display[] = [];
|
||||
if (app.isReady()) {
|
||||
screens = electron.screen.getAllDisplays();
|
||||
}
|
||||
const { position, display } = config.getConfigFields([ 'notificationSettings' ]).notificationSettings;
|
||||
this.notificationSettingsWindow.webContents.send('notification-settings-data', { screens, position, display });
|
||||
}
|
||||
});
|
||||
|
||||
this.addWindow(opts.winKey, this.notificationSettingsWindow);
|
||||
|
||||
ipcMain.once('notification-settings-update', async (_event, args) => {
|
||||
const { display, position } = args;
|
||||
try {
|
||||
await config.updateUserConfig({ notificationSettings: { display, position } });
|
||||
} catch (e) {
|
||||
logger.error(`NotificationSettings: Could not update user config file error`, e);
|
||||
}
|
||||
if (this.notificationSettingsWindow && windowExists(this.notificationSettingsWindow)) {
|
||||
this.notificationSettingsWindow.close();
|
||||
}
|
||||
// Update latest notification settings from config
|
||||
notification.updateNotificationSettings();
|
||||
});
|
||||
|
||||
this.notificationSettingsWindow.once('closed', () => {
|
||||
this.removeWindow(opts.winKey);
|
||||
this.notificationSettingsWindow = null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a screen sharing indicator whenever uses start
|
||||
* sharing the screen
|
||||
|
@ -55,7 +55,7 @@ export interface IApiArgs {
|
||||
type: string;
|
||||
}
|
||||
|
||||
export type WindowTypes = 'screen-picker' | 'screen-sharing-indicator';
|
||||
export type WindowTypes = 'screen-picker' | 'screen-sharing-indicator' | 'notification-settings';
|
||||
|
||||
export interface IBadgeCount {
|
||||
count: number;
|
||||
|
@ -118,6 +118,9 @@ export default class AppBridge {
|
||||
case apiCmds.closeNotification:
|
||||
notification.hideNotification(data);
|
||||
break;
|
||||
case apiCmds.showNotificationSettings:
|
||||
ssf.showNotificationSettings();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
179
src/renderer/components/notification-settings.tsx
Normal file
179
src/renderer/components/notification-settings.tsx
Normal file
@ -0,0 +1,179 @@
|
||||
import { ipcRenderer } from 'electron';
|
||||
import * as React from 'react';
|
||||
import { apiCmds, apiName } from '../../common/api-interface';
|
||||
|
||||
import { i18n } from '../../common/i18n-preload';
|
||||
|
||||
const NOTIFICATION_SETTINGS_NAMESPACE = 'NotificationSettings';
|
||||
|
||||
type startCorner = 'upper-right' | 'upper-left' | 'lower-right' | 'lower-left';
|
||||
|
||||
interface IState {
|
||||
position: startCorner;
|
||||
screens: Electron.Display[];
|
||||
display: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Window that display app version and copyright info
|
||||
*/
|
||||
export default class NotificationSettings extends React.Component<{}, IState> {
|
||||
|
||||
private readonly eventHandlers = {
|
||||
onTogglePosition: (e: React.ChangeEvent<HTMLInputElement>) => this.togglePosition(e),
|
||||
onDisplaySelect: (e: React.ChangeEvent<HTMLSelectElement>) => this.selectDisplay(e),
|
||||
onClose: () => this.close(),
|
||||
onSubmit: () => this.submit(),
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
position: 'upper-right',
|
||||
screens: [],
|
||||
display: 1,
|
||||
};
|
||||
this.updateState = this.updateState.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* main render function
|
||||
*/
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<div className='content'>
|
||||
<header className='header'>
|
||||
<span className='header__title'>
|
||||
{i18n.t('Notification Settings', NOTIFICATION_SETTINGS_NAMESPACE)()}
|
||||
</span>
|
||||
</header>
|
||||
<div className='form'>
|
||||
<form>
|
||||
<label className='label'>{i18n.t('Monitor', NOTIFICATION_SETTINGS_NAMESPACE)()}</label>
|
||||
<div id='screens' className='main'>
|
||||
<label>
|
||||
{i18n.t('Notification shown on Monitor: ', NOTIFICATION_SETTINGS_NAMESPACE)()}
|
||||
</label>
|
||||
<select className='selector' id='screen-selector' title='position' onChange={this.eventHandlers.onDisplaySelect}>
|
||||
{this.renderScreens()}
|
||||
</select>
|
||||
</div>
|
||||
<label className='label'>{i18n.t('Position', NOTIFICATION_SETTINGS_NAMESPACE)()}</label>
|
||||
<div className='main'>
|
||||
<div className='first-set'>
|
||||
{this.renderRadioButtons('upper-left', 'Top Left')}
|
||||
{this.renderRadioButtons('lower-left', 'Bottom Left')}
|
||||
</div>
|
||||
<div className='second-set'>
|
||||
{this.renderRadioButtons('upper-right', 'Top Right')}
|
||||
{this.renderRadioButtons('lower-right', 'Bottom Left')}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<footer className='footer'>
|
||||
<div className='buttonLayout'>
|
||||
<button id='cancel' className='buttonDismiss' onClick={this.eventHandlers.onClose}>
|
||||
{i18n.t('CANCEL', NOTIFICATION_SETTINGS_NAMESPACE)()}
|
||||
</button>
|
||||
<button id='ok-button' className='button' onClick={this.eventHandlers.onSubmit}>
|
||||
{i18n.t('OK', NOTIFICATION_SETTINGS_NAMESPACE)()}
|
||||
</button>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
ipcRenderer.on('notification-settings-data', this.updateState);
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
ipcRenderer.removeListener('notification-settings-data', this.updateState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders all 4 different notification position options
|
||||
*
|
||||
* @param id
|
||||
* @param content
|
||||
*/
|
||||
private renderRadioButtons(id: startCorner, content: string): JSX.Element {
|
||||
return (
|
||||
<div className='radio'>
|
||||
<label className='radio__label' htmlFor={id}>
|
||||
{i18n.t(`${content}`, NOTIFICATION_SETTINGS_NAMESPACE)()}
|
||||
</label>
|
||||
<input
|
||||
onChange={this.eventHandlers.onTogglePosition}
|
||||
className={id}
|
||||
id={id}
|
||||
type='radio'
|
||||
name='position'
|
||||
checked={this.state.position === id}
|
||||
value={id}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the drop down list of available screen
|
||||
*/
|
||||
private renderScreens(): JSX.Element[] {
|
||||
const { screens, display } = this.state;
|
||||
return screens.map((screen, index) => {
|
||||
return (
|
||||
<option id={String(screen.id)} key={screen.id} value={display}>{index + 1}</option>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the selected display state
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
private selectDisplay(event): void {
|
||||
this.setState({ display: event.target.value });
|
||||
}
|
||||
|
||||
/**
|
||||
* Updated the selected notification position
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
private togglePosition(event): void {
|
||||
this.setState({
|
||||
position: event.currentTarget.value,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the user selected notification settings options
|
||||
*/
|
||||
private submit(): void {
|
||||
const { position, display } = this.state;
|
||||
ipcRenderer.send('notification-settings-update', { position, display });
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the notification settings window
|
||||
*/
|
||||
private close(): void {
|
||||
ipcRenderer.send(apiName.symphonyApi, {
|
||||
cmd: apiCmds.closeWindow,
|
||||
windowType: 'notification-settings',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the About app state
|
||||
*
|
||||
* @param _event
|
||||
* @param data {Object} { buildNumber, clientVersion, version }
|
||||
*/
|
||||
private updateState(_event, data): void {
|
||||
this.setState(data as IState);
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import * as asyncMap from 'async.map';
|
||||
import { app } from 'electron';
|
||||
import * as electron from 'electron';
|
||||
|
||||
import { windowExists } from '../app/window-utils';
|
||||
@ -6,6 +7,7 @@ import { isMac } from '../common/env';
|
||||
|
||||
interface ISettings {
|
||||
startCorner: startCorner;
|
||||
displayId: string;
|
||||
height: number;
|
||||
width: number;
|
||||
totalHeight: number;
|
||||
@ -33,15 +35,16 @@ export default class NotificationHandler {
|
||||
};
|
||||
|
||||
private externalDisplay: Electron.Display | undefined;
|
||||
private displayId: string = '';
|
||||
|
||||
constructor(opts) {
|
||||
this.settings = opts as ISettings;
|
||||
this.setupNotificationPosition();
|
||||
|
||||
electron.screen.on('display-added', this.eventHandlers.onSetup);
|
||||
electron.screen.on('display-removed', this.eventHandlers.onSetup);
|
||||
electron.screen.on('display-metrics-changed', this.eventHandlers.onSetup);
|
||||
app.once('ready', () => {
|
||||
electron.screen.on('display-added', this.eventHandlers.onSetup);
|
||||
electron.screen.on('display-removed', this.eventHandlers.onSetup);
|
||||
electron.screen.on('display-metrics-changed', this.eventHandlers.onSetup);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,14 +65,15 @@ export default class NotificationHandler {
|
||||
*/
|
||||
public setupNotificationPosition() {
|
||||
// This feature only applies to windows
|
||||
if (isMac) {
|
||||
if (isMac || !app.isReady()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const screens = electron.screen.getAllDisplays();
|
||||
if (screens && screens.length >= 0) {
|
||||
this.externalDisplay = screens.find((screen) => {
|
||||
const screenId = screen.id.toString();
|
||||
return screenId === this.displayId;
|
||||
return screenId === this.settings.displayId;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
import { ipcMain } from 'electron';
|
||||
|
||||
import { config } from '../app/config-handler';
|
||||
import { createComponentWindow, windowExists } from '../app/window-utils';
|
||||
import { AnimationQueue } from '../common/animation-queue';
|
||||
import { logger } from '../common/logger';
|
||||
import NotificationHandler from './notification-handler';
|
||||
|
||||
// const MAX_QUEUE_SIZE = 30;
|
||||
const CLEAN_UP_INTERVAL = 60 * 100;
|
||||
const CLEAN_UP_INTERVAL = 60 * 1000; // Closes inactive notification
|
||||
const animationQueue = new AnimationQueue();
|
||||
|
||||
interface ICustomBrowserWindow extends Electron.BrowserWindow {
|
||||
@ -32,6 +33,7 @@ type startCorner = 'upper-right' | 'upper-left' | 'lower-right' | 'lower-left';
|
||||
|
||||
const notificationSettings = {
|
||||
startCorner: 'upper-right' as startCorner,
|
||||
display: '',
|
||||
width: 380,
|
||||
height: 100,
|
||||
totalHeight: 0,
|
||||
@ -74,6 +76,8 @@ class Notification extends NotificationHandler {
|
||||
ipcMain.on('notification-clicked', (_event, windowId) => {
|
||||
this.notificationClicked(windowId);
|
||||
});
|
||||
// Update latest notification settings from config
|
||||
this.updateNotificationSettings();
|
||||
this.cleanUpTimer = setInterval(this.funcHandlers.onCleanUpInactiveNotification, CLEAN_UP_INTERVAL);
|
||||
}
|
||||
|
||||
@ -100,6 +104,7 @@ class Notification extends NotificationHandler {
|
||||
*/
|
||||
public async createNotificationWindow(data): Promise<ICustomBrowserWindow | undefined> {
|
||||
|
||||
// TODO: Handle MAX_QUEUE_SIZE
|
||||
if (data.tag) {
|
||||
for (let i = 0; i < this.notificationQueue.length; i++) {
|
||||
if (this.notificationQueue[ i ].tag === data.tag) {
|
||||
@ -244,6 +249,19 @@ class Notification extends NotificationHandler {
|
||||
return this.activeNotifications[ index ] as ICustomBrowserWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update latest notification settings from config
|
||||
*/
|
||||
public updateNotificationSettings(): void {
|
||||
const { display, position } = config.getConfigFields([ 'notificationSettings' ]).notificationSettings;
|
||||
this.settings.displayId = display;
|
||||
this.settings.startCorner = position as startCorner;
|
||||
|
||||
// recalculate notification position
|
||||
this.setupNotificationPosition();
|
||||
this.moveNotificationDown(0, this.activeNotifications);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for window to load and resolves
|
||||
*
|
||||
|
@ -8,6 +8,7 @@ import BasicAuth from './components/basic-auth';
|
||||
import LoadingScreen from './components/loading-screen';
|
||||
import MoreInfo from './components/more-info';
|
||||
import NotificationComp from './components/notification-comp';
|
||||
import NotificationSettings from './components/notification-settings';
|
||||
import ScreenPicker from './components/screen-picker';
|
||||
import ScreenSharingIndicator from './components/screen-sharing-indicator';
|
||||
|
||||
@ -19,6 +20,7 @@ const enum components {
|
||||
screenSharingIndicator = 'screen-sharing-indicator',
|
||||
basicAuth = 'basic-auth',
|
||||
notification = 'notification-comp',
|
||||
notificationSettings = 'notification-settings',
|
||||
}
|
||||
|
||||
const loadStyle = (style) => {
|
||||
@ -66,6 +68,10 @@ const load = () => {
|
||||
loadStyle(components.notification);
|
||||
component = NotificationComp;
|
||||
break;
|
||||
case components.notificationSettings:
|
||||
loadStyle(components.notificationSettings);
|
||||
component = NotificationSettings;
|
||||
break;
|
||||
}
|
||||
const element = React.createElement(component);
|
||||
ReactDOM.render(element, document.getElementById('Root'));
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { ipcRenderer, remote } from 'electron';
|
||||
|
||||
import { buildNumber } from '../../package.json';
|
||||
import { ICustomBrowserWindow } from '../app/window-handler';
|
||||
import {
|
||||
apiCmds,
|
||||
apiName,
|
||||
@ -261,6 +262,17 @@ export class SSFApi {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a modal window to configure notification preference.
|
||||
*/
|
||||
public showNotificationSettings(): void {
|
||||
const windowName = (remote.getCurrentWindow() as ICustomBrowserWindow).winName;
|
||||
local.ipcRenderer.send(apiName.symphonyApi, {
|
||||
cmd: apiCmds.showNotificationSettings,
|
||||
windowName,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a banner that informs user that the screen is being shared.
|
||||
*
|
||||
|
@ -1,7 +1,8 @@
|
||||
@import "theme";
|
||||
|
||||
@white: rgb(255, 255, 255, 1);
|
||||
@version-text-color: rgb(47, 47, 47, 1);
|
||||
@copyright-text-color: rgb(127, 127, 127, 1);
|
||||
@font-family: sans-serif;
|
||||
@text-padding: 10px;
|
||||
|
||||
body {
|
||||
|
@ -1,5 +1,6 @@
|
||||
@import "theme";
|
||||
|
||||
@color-red: red;
|
||||
@font-family: sans-serif;
|
||||
|
||||
html {
|
||||
margin: 0;
|
||||
|
@ -1,4 +1,5 @@
|
||||
@font-family: sans-serif;
|
||||
@import "theme";
|
||||
|
||||
@text-padding: 10px;
|
||||
|
||||
body {
|
||||
|
@ -1,4 +1,4 @@
|
||||
@font-family: "Segoe UI", "Helvetica Neue", "Verdana", "Arial", sans-serif;
|
||||
@import "theme";
|
||||
|
||||
.light {
|
||||
--text-color: #4a4a4a;
|
||||
|
114
src/renderer/styles/notification-settings.less
Normal file
114
src/renderer/styles/notification-settings.less
Normal file
@ -0,0 +1,114 @@
|
||||
@import "theme";
|
||||
|
||||
@color: rgba(0, 0, 0, .8);
|
||||
|
||||
html {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
font-family: @font-family;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
font-family: @font-family;
|
||||
}
|
||||
|
||||
.content {
|
||||
border-radius: 2px;
|
||||
width: 100%;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 1.3;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, .1);
|
||||
margin-bottom: 20px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.header__title {
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
margin: 0 0 0 4px;
|
||||
font-size: 1.4rem;
|
||||
min-height: 13px;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
color: @color;
|
||||
}
|
||||
|
||||
.form {
|
||||
width: 95%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.selector {
|
||||
padding: 0 9px 0 16px;
|
||||
cursor: pointer;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-bottom: 20px;
|
||||
height: 100%;
|
||||
border: 1px solid #ccc !important;
|
||||
padding: 10px;
|
||||
|
||||
.first-set {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.second-set {
|
||||
flex-grow: 1;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.radio {
|
||||
line-height: 1.7;
|
||||
|
||||
.upper-right, .lower-right {
|
||||
float: right;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.upper-left, .lower-left {
|
||||
float: left;
|
||||
margin-top: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.radio__label {
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
|
||||
input {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: 12px 10px;
|
||||
border-top: 1px solid rgba(0, 0, 0, .1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.buttonLayout {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.buttonDismiss {
|
||||
margin-right: 10px;
|
||||
}
|
1
src/renderer/styles/theme.less
Normal file
1
src/renderer/styles/theme.less
Normal file
@ -0,0 +1 @@
|
||||
@font-family: "Segoe UI", "Helvetica Neue", "Verdana", "Arial", sans-serif;
|
@ -1,6 +1,7 @@
|
||||
@import "theme";
|
||||
|
||||
@color_1: rgba(255, 255, 255, 1);
|
||||
@color_2: white;
|
||||
@font_family_1: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
|
||||
@background_color_1: rgba(51, 51, 51, 1);
|
||||
|
||||
.title-bar {
|
||||
@ -50,7 +51,7 @@
|
||||
}
|
||||
|
||||
.title-bar-title {
|
||||
font-family: @font_family_1;
|
||||
font-family: @font-family;
|
||||
color: @color_2;
|
||||
margin: 0;
|
||||
padding-left: 10px;
|
||||
|
Loading…
Reference in New Issue
Block a user