mirror of
https://github.com/finos/SymphonyElectron.git
synced 2025-02-25 18:55:29 -06:00
Typescript - Add custom title bar
This commit is contained in:
parent
d3b522488a
commit
5db20ef743
@ -1,48 +1,8 @@
|
|||||||
import { ipcMain } from 'electron';
|
import { ipcMain } from 'electron';
|
||||||
|
|
||||||
|
import { apiCmds, apiName, IApiArgs } from '../common/api-interface';
|
||||||
import { logger } from '../common/logger';
|
import { logger } from '../common/logger';
|
||||||
|
|
||||||
export enum ApiCmds {
|
|
||||||
isOnline,
|
|
||||||
registerLogger,
|
|
||||||
setBadgeCount,
|
|
||||||
badgeDataUrl,
|
|
||||||
activate,
|
|
||||||
registerBoundsChange,
|
|
||||||
registerProtocolHandler,
|
|
||||||
registerActivityDetection,
|
|
||||||
showNotificationSettings,
|
|
||||||
sanitize,
|
|
||||||
bringToFront,
|
|
||||||
openScreenPickerWindow,
|
|
||||||
popupMenu,
|
|
||||||
optimizeMemoryConsumption,
|
|
||||||
optimizeMemoryRegister,
|
|
||||||
setIsInMeeting,
|
|
||||||
setLocale,
|
|
||||||
keyPress,
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum apiName {
|
|
||||||
symphonyApi = 'symphony-api',
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IApiArgs {
|
|
||||||
cmd: ApiCmds;
|
|
||||||
isOnline: boolean;
|
|
||||||
count: number;
|
|
||||||
dataUrl: string;
|
|
||||||
windowName: string;
|
|
||||||
period: number;
|
|
||||||
reason: string;
|
|
||||||
sources: Electron.DesktopCapturerSource[];
|
|
||||||
id: number;
|
|
||||||
memory: Electron.ProcessMemoryInfo;
|
|
||||||
cpuUsage: Electron.CPUUsage;
|
|
||||||
isInMeeting: boolean;
|
|
||||||
locale: string;
|
|
||||||
keyCode: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure events comes from a window that we have created.
|
* Ensure events comes from a window that we have created.
|
||||||
* @param {EventEmitter} event node emitter event to be tested
|
* @param {EventEmitter} event node emitter event to be tested
|
||||||
@ -108,7 +68,7 @@ ipcMain.on(apiName.symphonyApi, (event: Electron.Event, arg: IApiArgs) => {
|
|||||||
case ApiCmds.registerBoundsChange:
|
case ApiCmds.registerBoundsChange:
|
||||||
windowMgr.setBoundsChangeWindow(event.sender);
|
windowMgr.setBoundsChangeWindow(event.sender);
|
||||||
break;*/
|
break;*/
|
||||||
case ApiCmds.registerLogger:
|
case apiCmds.registerLogger:
|
||||||
// renderer window that has a registered logger from JS.
|
// renderer window that has a registered logger from JS.
|
||||||
logger.setLoggerWindow(event.sender);
|
logger.setLoggerWindow(event.sender);
|
||||||
break;
|
break;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { BrowserWindow, crashReporter } from 'electron';
|
import { BrowserWindow, crashReporter } from 'electron';
|
||||||
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as url from 'url';
|
import * as url from 'url';
|
||||||
|
|
||||||
@ -99,7 +100,12 @@ export class WindowHandler {
|
|||||||
this.loadingWindow.destroy();
|
this.loadingWindow.destroy();
|
||||||
this.loadingWindow = null;
|
this.loadingWindow = null;
|
||||||
}
|
}
|
||||||
if (this.mainWindow) this.mainWindow.show();
|
if (this.mainWindow) {
|
||||||
|
this.mainWindow.webContents.insertCSS(
|
||||||
|
fs.readFileSync(path.join(__dirname, '..', '/renderer/styles/title-bar.css'), 'utf8').toString(),
|
||||||
|
);
|
||||||
|
this.mainWindow.show();
|
||||||
|
}
|
||||||
this.createAboutAppWindow();
|
this.createAboutAppWindow();
|
||||||
});
|
});
|
||||||
return this.mainWindow;
|
return this.mainWindow;
|
||||||
|
41
src/common/api-interface.ts
Normal file
41
src/common/api-interface.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
export enum apiCmds {
|
||||||
|
isOnline,
|
||||||
|
registerLogger,
|
||||||
|
setBadgeCount,
|
||||||
|
badgeDataUrl,
|
||||||
|
activate,
|
||||||
|
registerBoundsChange,
|
||||||
|
registerProtocolHandler,
|
||||||
|
registerActivityDetection,
|
||||||
|
showNotificationSettings,
|
||||||
|
sanitize,
|
||||||
|
bringToFront,
|
||||||
|
openScreenPickerWindow,
|
||||||
|
popupMenu,
|
||||||
|
optimizeMemoryConsumption,
|
||||||
|
optimizeMemoryRegister,
|
||||||
|
setIsInMeeting,
|
||||||
|
setLocale,
|
||||||
|
keyPress,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum apiName {
|
||||||
|
symphonyApi = 'symphony-api',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IApiArgs {
|
||||||
|
cmd: apiCmds;
|
||||||
|
isOnline: boolean;
|
||||||
|
count: number;
|
||||||
|
dataUrl: string;
|
||||||
|
windowName: string;
|
||||||
|
period: number;
|
||||||
|
reason: string;
|
||||||
|
sources: Electron.DesktopCapturerSource[];
|
||||||
|
id: number;
|
||||||
|
memory: Electron.ProcessMemoryInfo;
|
||||||
|
cpuUsage: Electron.CPUUsage;
|
||||||
|
isInMeeting: boolean;
|
||||||
|
locale: string;
|
||||||
|
keyCode: number;
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
export const isDevEnv = process.env.ELECTRON_DEV ?
|
export const isDevEnv = process.env.ELECTRON_DEV ?
|
||||||
process.env.ELECTRON_DEV.trim().toLowerCase() === 'true' : false;
|
process.env.ELECTRON_DEV.trim().toLowerCase() === 'true' : false;
|
||||||
export const isElectronQA = process.env.ELECTRON_QA;
|
export const isElectronQA = !!process.env.ELECTRON_QA;
|
||||||
|
|
||||||
export const isMac = (process.platform === 'darwin');
|
export const isMac = (process.platform === 'darwin');
|
||||||
export const isWindowsOS = (process.platform === 'win32');
|
export const isWindowsOS = (process.platform === 'win32');
|
||||||
|
64
src/common/i18n.ts
Normal file
64
src/common/i18n.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
// import { logger } from './logger';
|
||||||
|
import { formatString } from './utils';
|
||||||
|
|
||||||
|
const localeCodeRegex = /^([a-z]{2})-([A-Z]{2})$/;
|
||||||
|
|
||||||
|
export type localeType = 'en-US' | 'ja-JP';
|
||||||
|
|
||||||
|
class Translation {
|
||||||
|
private static translate = (value: string, resource) => resource[value];
|
||||||
|
private locale: localeType = 'en-US';
|
||||||
|
private loadedResource: object = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the locale for translation
|
||||||
|
* @param locale
|
||||||
|
*/
|
||||||
|
public setLocale(locale: localeType): void {
|
||||||
|
const localeMatch: string[] | null = locale.match(localeCodeRegex);
|
||||||
|
if (!locale && (!localeMatch || localeMatch.length < 1)) {
|
||||||
|
// logger.error(`Translation: invalid locale ${locale} found`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.locale = locale;
|
||||||
|
// logger.info(`Translation: locale updated with ${locale}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fetches and returns the translated value
|
||||||
|
* @param value {string}
|
||||||
|
* @param data {object}
|
||||||
|
*/
|
||||||
|
public t(value: string, data?: object): string {
|
||||||
|
console.log(process.type);
|
||||||
|
if (this.loadedResource && this.loadedResource[this.locale]) {
|
||||||
|
return formatString(Translation.translate(value, this.loadedResource[this.locale]));
|
||||||
|
}
|
||||||
|
const resource = this.loadResource(this.locale);
|
||||||
|
return formatString(resource ? resource[value] : value || value, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the resources dir and returns the data
|
||||||
|
* @param locale
|
||||||
|
*/
|
||||||
|
public loadResource(locale: localeType): object | null {
|
||||||
|
const resourcePath = path.resolve(__dirname, '..', 'locale', `${locale}.json`);
|
||||||
|
|
||||||
|
if (!fs.existsSync(resourcePath)) {
|
||||||
|
// logger.error(`Translation: locale resource path does not exits ${resourcePath}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.loadedResource[this.locale] = require(resourcePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const i18n = new Translation();
|
||||||
|
|
||||||
|
export { i18n };
|
@ -197,6 +197,4 @@ export class Logger {
|
|||||||
|
|
||||||
const logger = new Logger();
|
const logger = new Logger();
|
||||||
|
|
||||||
export {
|
export { logger };
|
||||||
logger,
|
|
||||||
};
|
|
155
src/locale/en-US.json
Normal file
155
src/locale/en-US.json
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
{
|
||||||
|
"About Symphony": "About Symphony",
|
||||||
|
"Actual Size": "Actual Size",
|
||||||
|
"Always on Top": "Always on Top",
|
||||||
|
"Auto Launch On Startup": "Auto Launch On Startup",
|
||||||
|
"BasicAuth": {
|
||||||
|
"Authentication Request": "Authentication Request",
|
||||||
|
"Cancel": "Cancel",
|
||||||
|
"hostname": "hostname",
|
||||||
|
"Invalid user name/password": "Invalid user name/password",
|
||||||
|
"Log In": "Log In",
|
||||||
|
"Password:": "Password:",
|
||||||
|
"Please provide your login credentials for:": "Please provide your login credentials for:",
|
||||||
|
"User name:": "User name:"
|
||||||
|
},
|
||||||
|
"Bring All to Front": "Bring All to Front",
|
||||||
|
"Bring to Front on Notifications": "Bring to Front on Notifications",
|
||||||
|
"Certificate Error": "Certificate Error",
|
||||||
|
"Close": "Close",
|
||||||
|
"Cancel": "Cancel",
|
||||||
|
"ContextMenu": {
|
||||||
|
"Add to Dictionary": "Add to Dictionary",
|
||||||
|
"Copy": "Copy",
|
||||||
|
"Copy Email Address": "Copy Email Address",
|
||||||
|
"Copy Image": "Copy Image",
|
||||||
|
"Copy Image URL": "Copy Image URL",
|
||||||
|
"Copy Link": "Copy Link",
|
||||||
|
"Cut": "Cut",
|
||||||
|
"Inspect Element": "Inspect Element",
|
||||||
|
"Look Up {searchText}": "Look Up \"{searchText}\"",
|
||||||
|
"Open Link": "Open Link",
|
||||||
|
"Paste": "Paste",
|
||||||
|
"Reload": "Reload",
|
||||||
|
"Search with Google": "Search with Google"
|
||||||
|
},
|
||||||
|
"DownloadManager": {
|
||||||
|
"Show in Folder": "Show in Folder",
|
||||||
|
"Reveal in Finder": "Reveal in Finder",
|
||||||
|
"Open": "Open",
|
||||||
|
"Downloaded": "Downloaded",
|
||||||
|
"File not Found": "File not Found",
|
||||||
|
"The file you are trying to open cannot be found in the specified path.": "The file you are trying to open cannot be found in the specified path."
|
||||||
|
},
|
||||||
|
"Copy": "Copy",
|
||||||
|
"Custom": "Custom",
|
||||||
|
"Cut": "Cut",
|
||||||
|
"Delete": "Delete",
|
||||||
|
"Disable Hamburger menu": "Disable Hamburger menu",
|
||||||
|
"Dev Tools disabled": "Dev Tools disabled",
|
||||||
|
"Dev Tools has been disabled. Please contact your system administrator": "Dev Tools has been disabled. Please contact your system administrator",
|
||||||
|
"Edit": "Edit",
|
||||||
|
"Enable Hamburger menu": "Enable Hamburger menu",
|
||||||
|
"Error loading configuration": "Error loading configuration",
|
||||||
|
"Error loading URL": "Error loading URL",
|
||||||
|
"Error loading window": "Error loading window",
|
||||||
|
"Error setting AutoLaunch configuration": "Error setting AutoLaunch configuration",
|
||||||
|
"Failed!": "Failed!",
|
||||||
|
"Flash Notification in Taskbar": "Flash Notification in Taskbar",
|
||||||
|
"Help": "Help",
|
||||||
|
"Help Url": "https://support.symphony.com",
|
||||||
|
"Symphony Url": "https://symphony.com/en-US",
|
||||||
|
"Hide Others": "Hide Others",
|
||||||
|
"Hide Symphony": "Hide Symphony",
|
||||||
|
"Learn More": "Learn More",
|
||||||
|
"Loading Error": "Loading Error",
|
||||||
|
"Minimize": "Minimize",
|
||||||
|
"Minimize on Close": "Minimize on Close",
|
||||||
|
"Native": "Native",
|
||||||
|
"No crashes available to share": "No crashes available to share",
|
||||||
|
"No logs are available to share": "No logs are available to share",
|
||||||
|
"Not Allowed": "Not Allowed",
|
||||||
|
"Note: When Hamburger menu is disabled, you can trigger the main menu by pressing the Alt key.": "Note: When Hamburger menu is disabled, you can trigger the main menu by pressing the \"Alt\" key.",
|
||||||
|
"NotificationSettings": {
|
||||||
|
"Bottom Left": "Bottom Left",
|
||||||
|
"Bottom Right": "Bottom Right",
|
||||||
|
"CANCEL": "CANCEL",
|
||||||
|
"Monitor": "Monitor",
|
||||||
|
"Notification Settings": "Notification Settings",
|
||||||
|
"Notification shown on Monitor: ": "Notification shown on Monitor: ",
|
||||||
|
"OK": "OK",
|
||||||
|
"Position": "Position",
|
||||||
|
"Symphony - Configure Notification Position": "Symphony - Configure Notification Position",
|
||||||
|
"Top Left": "Top Left",
|
||||||
|
"Top Right": "Top Right"
|
||||||
|
},
|
||||||
|
"Oops! Looks like we have had a crash.": "Oops! Looks like we have had a crash.",
|
||||||
|
"Oops! Looks like we have had a crash. Please reload or close this window.": "Oops! Looks like we have had a crash. Please reload or close this window.",
|
||||||
|
"Paste": "Paste",
|
||||||
|
"Paste and Match Style": "Paste and Match Style",
|
||||||
|
"Permission Denied": "Permission Denied",
|
||||||
|
"Please contact your admin for help": "Please contact your admin for help",
|
||||||
|
"please contact your administrator for more details": "please contact your administrator for more details",
|
||||||
|
"Quit Symphony": "Quit Symphony",
|
||||||
|
"Redo": "Redo",
|
||||||
|
"Refresh app when idle": "Refresh app when idle",
|
||||||
|
"Clear cache and Reload": "Clear cache and Reload",
|
||||||
|
"Relaunch Application": "Relaunch Application",
|
||||||
|
"Relaunch": "Relaunch",
|
||||||
|
"Reload": "Reload",
|
||||||
|
"Renderer Process Crashed": "Renderer Process Crashed",
|
||||||
|
"ScreenPicker": {
|
||||||
|
"Applications": "Applications",
|
||||||
|
"Cancel": "Cancel",
|
||||||
|
"Choose what you'd like to share": "Choose what you'd like to share",
|
||||||
|
"No screens or applications are currently available.": "No screens or applications are currently available.",
|
||||||
|
"Screen Picker": "Screen Picker",
|
||||||
|
"Screens": "Screens",
|
||||||
|
"Select Application": "Select Application",
|
||||||
|
"Select Screen": "Select Screen",
|
||||||
|
"Share": "Share"
|
||||||
|
},
|
||||||
|
"ScreenSnippet": {
|
||||||
|
"Done": "Done",
|
||||||
|
"Erase": "Erase",
|
||||||
|
"Highlight": "Highlight",
|
||||||
|
"Pen": "Pen",
|
||||||
|
"Snipping Tool": "Snipping Tool"
|
||||||
|
},
|
||||||
|
"Select All": "Select All",
|
||||||
|
"Services": "Services",
|
||||||
|
"Show All": "Show All",
|
||||||
|
"Show crash dump in Explorer": "Show crash dump in Explorer",
|
||||||
|
"Show crash dump in Finder": "Show crash dump in Finder",
|
||||||
|
"Show Logs in Explorer": "Show Logs in Explorer",
|
||||||
|
"Show Logs in Finder": "Show Logs in Finder",
|
||||||
|
"SnackBar": {
|
||||||
|
" to exit full screen": " to exit full screen",
|
||||||
|
"esc": "esc",
|
||||||
|
"Press ": "Press "
|
||||||
|
},
|
||||||
|
"Sorry, you are not allowed to access this website": "Sorry, you are not allowed to access this website",
|
||||||
|
"Speech": "Speech",
|
||||||
|
"Start Speaking": "Start Speaking",
|
||||||
|
"Stop Speaking": "Stop Speaking",
|
||||||
|
"Symphony Help": "Symphony Help",
|
||||||
|
"TitleBar": {
|
||||||
|
"Close": "Close",
|
||||||
|
"Maximize": "Maximize",
|
||||||
|
"Menu": "Menu",
|
||||||
|
"Minimize": "Minimize"
|
||||||
|
},
|
||||||
|
"Title Bar Style": "Title Bar Style",
|
||||||
|
"Toggle Full Screen": "Toggle Full Screen",
|
||||||
|
"Troubleshooting": "Troubleshooting",
|
||||||
|
"Unable to generate crash reports due to ": "Unable to generate crash reports due to ",
|
||||||
|
"Unable to generate logs due to ": "Unable to generate logs due to ",
|
||||||
|
"Undo": "Undo",
|
||||||
|
"Updating Title bar style requires Symphony to relaunch.": "Updating Title bar style requires Symphony to relaunch.",
|
||||||
|
"View": "View",
|
||||||
|
"Window": "Window",
|
||||||
|
"Your administrator has disabled": "Your administrator has disabled",
|
||||||
|
"Zoom": "Zoom",
|
||||||
|
"Zoom In": "Zoom In",
|
||||||
|
"Zoom Out": "Zoom Out"
|
||||||
|
}
|
155
src/locale/ja-JP.json
Normal file
155
src/locale/ja-JP.json
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
{
|
||||||
|
"About Symphony": "Symphonyについて",
|
||||||
|
"Actual Size": "実際のサイズ",
|
||||||
|
"Always on Top": "つねに前面に表示",
|
||||||
|
"Auto Launch On Startup": "スタートアップ時に自動起動",
|
||||||
|
"BasicAuth": {
|
||||||
|
"Authentication Request": "認証要求",
|
||||||
|
"Cancel": "キャンセル",
|
||||||
|
"hostname": "ホスト名",
|
||||||
|
"Invalid user name/password": "ユーザー名かパスワード、または両方が無効",
|
||||||
|
"Log In": "ログイン",
|
||||||
|
"Password:": "パスワード:",
|
||||||
|
"Please provide your login credentials for:": "あなたのログイン認証情報を入力してください。",
|
||||||
|
"User name:": "ユーザー名:"
|
||||||
|
},
|
||||||
|
"Bring All to Front": "すべて前面に表示",
|
||||||
|
"Bring to Front on Notifications": "通知時に前面に表示",
|
||||||
|
"Certificate Error": "証明書のエラー",
|
||||||
|
"Close": "閉じる",
|
||||||
|
"Cancel": "キャンセル",
|
||||||
|
"ContextMenu": {
|
||||||
|
"Add to Dictionary": "辞書に追加",
|
||||||
|
"Copy": "コピー",
|
||||||
|
"Copy Email Address": "電子メールアドレスをコピー",
|
||||||
|
"Copy Image": "画像をコピー",
|
||||||
|
"Copy Image URL": "画像のURLをコピー",
|
||||||
|
"Copy Link": "リンクをコピー",
|
||||||
|
"Cut": "切り取り",
|
||||||
|
"Inspect Element": "要素を調査",
|
||||||
|
"Look Up {searchText}": "「{searchText}」を検索",
|
||||||
|
"Open Link": "リンクを開く",
|
||||||
|
"Paste": "貼り付け",
|
||||||
|
"Reload": "再読み込み",
|
||||||
|
"Search with Google": "Googleで検索"
|
||||||
|
},
|
||||||
|
"DownloadManager": {
|
||||||
|
"Show in Folder": "フォルダで見て",
|
||||||
|
"Reveal in Finder": "Finderで明らかにする",
|
||||||
|
"Open": "開いた",
|
||||||
|
"Downloaded": "ダウンロード済み",
|
||||||
|
"File not Found": "ファイルが見つかりません",
|
||||||
|
"The file you are trying to open cannot be found in the specified path.": "開こうとしているファイルが指定されたパスに見つかりません."
|
||||||
|
},
|
||||||
|
"Copy": "コピー",
|
||||||
|
"Custom": "カスタム",
|
||||||
|
"Cut": "切り取り",
|
||||||
|
"Delete": "削除",
|
||||||
|
"Dev Tools disabled": "開発ツールを無効にする",
|
||||||
|
"Dev Tools has been disabled. Please contact your system administrator": "Dev Toolsが無効になっています。システム管理者に連絡してください",
|
||||||
|
"Disable Hamburger menu": "ハンバーガーメニューを無効にする",
|
||||||
|
"Edit": "編集",
|
||||||
|
"Enable Hamburger menu": "ハンバーガーメニューを有効にする",
|
||||||
|
"Error loading configuration": "構成の読み込みエラー",
|
||||||
|
"Error loading URL": "URLの読み込みエラー",
|
||||||
|
"Error loading window": "ウィンドウを読み込みエラー",
|
||||||
|
"Error setting AutoLaunch configuration": "自動起動の構成の設定エラー",
|
||||||
|
"Failed!": "問題が起きました!",
|
||||||
|
"Flash Notification in Taskbar": "タスクバーの通知を点滅",
|
||||||
|
"Help": "ヘルプ",
|
||||||
|
"Help Url": "https://support.symphony.com/hc/ja",
|
||||||
|
"Symphony Url": "https://symphony.com/ja",
|
||||||
|
"Hide Others": "他を隠す",
|
||||||
|
"Hide Symphony": "Symphonyを隠す",
|
||||||
|
"Learn More": "詳細",
|
||||||
|
"Loading Error": "読み込みエラー",
|
||||||
|
"Minimize": "最小化",
|
||||||
|
"Minimize on Close": "閉じるで最小化",
|
||||||
|
"Native": "Native",
|
||||||
|
"No crashes available to share": "共有できるクラッシュはありません",
|
||||||
|
"No logs are available to share": "共有できるログはありません",
|
||||||
|
"Not Allowed": "許可されていませ。",
|
||||||
|
"Note: When Hamburger menu is disabled, you can trigger the main menu by pressing the Alt key.": "注:ハンバーガーメニューが無効になっている場合、「Alt」キーを押してメインメニューをトリガーすることができます。",
|
||||||
|
"NotificationSettings": {
|
||||||
|
"Bottom Left": "左下",
|
||||||
|
"Bottom Right": "右下",
|
||||||
|
"CANCEL": "キャンセル",
|
||||||
|
"Monitor": "モニター",
|
||||||
|
"Notification Settings": "通知設定",
|
||||||
|
"Notification shown on Monitor: ": "モニターに表示する通知:",
|
||||||
|
"OK": "OK",
|
||||||
|
"Position": "位置",
|
||||||
|
"Symphony - Configure Notification Position": "Symphony - 通知位置の設定",
|
||||||
|
"Top Left": "左上",
|
||||||
|
"Top Right": "右上"
|
||||||
|
},
|
||||||
|
"Oops! Looks like we have had a crash.": "おっと!クラッシュしたようです。",
|
||||||
|
"Oops! Looks like we have had a crash. Please reload or close this window.": "おっと!クラッシュしたようです。このウィンドウを再度読み込むか閉じてください。",
|
||||||
|
"Paste": "貼り付け",
|
||||||
|
"Paste and Match Style": "貼り付けでスタイルを合わせる",
|
||||||
|
"Permission Denied": "アクセス許可が拒否されています",
|
||||||
|
"Please contact your admin for help": "不明な点がある場合は、管理者にお問い合わせください",
|
||||||
|
"please contact your administrator for more details": "詳細は、管理者にお問い合わせください",
|
||||||
|
"Quit Symphony": "Symphonyを終了",
|
||||||
|
"Redo": "やり直し",
|
||||||
|
"Refresh app when idle": "アイドル時にアプリを再表示",
|
||||||
|
"Clear cache and Reload": "キャッシュをクリアしてリロードする",
|
||||||
|
"Relaunch Application": "アプリケーションの再起動",
|
||||||
|
"Relaunch": "「リスタート」",
|
||||||
|
"Reload": "再読み込み",
|
||||||
|
"Renderer Process Crashed": "レンダラープロセスがクラッシュしました",
|
||||||
|
"ScreenPicker": {
|
||||||
|
"Applications": "アプリケーション",
|
||||||
|
"Cancel": "キャンセル",
|
||||||
|
"Choose what you'd like to share": "共有するものを選択する",
|
||||||
|
"No screens or applications are currently available.": "現在利用できる画面およびアプリケーションはありません。",
|
||||||
|
"Screen Picker": "画面の選択",
|
||||||
|
"Screens": "画面",
|
||||||
|
"Select Application": "アプリケーションを選択",
|
||||||
|
"Select Screen": "画面を選択",
|
||||||
|
"Share": "共有"
|
||||||
|
},
|
||||||
|
"ScreenSnippet": {
|
||||||
|
"Done": "完了",
|
||||||
|
"Erase": "消去",
|
||||||
|
"Highlight": "強調",
|
||||||
|
"Pen": "ペン",
|
||||||
|
"Snipping Tool": "切り取りツール"
|
||||||
|
},
|
||||||
|
"Select All": "すべてを選択",
|
||||||
|
"Services": "サービス",
|
||||||
|
"Show All": "すべてを表示",
|
||||||
|
"Show crash dump in Explorer": "Explorerにクラッシュダンプを表示",
|
||||||
|
"Show crash dump in Finder": "ファインダーにクラッシュダンプを表示",
|
||||||
|
"Show Logs in Explorer": "Explorerにログを表示",
|
||||||
|
"Show Logs in Finder": "ファインダーにログを表示",
|
||||||
|
"SnackBar": {
|
||||||
|
" to exit full screen": " を押します",
|
||||||
|
"esc": "esc",
|
||||||
|
"Press ": "全画面表示を終了するには "
|
||||||
|
},
|
||||||
|
"Sorry, you are not allowed to access this website": "申し訳ありませんが、このウェブサイトへのアクセスは許可されていません",
|
||||||
|
"Speech": "スピーチ",
|
||||||
|
"Start Speaking": "スピーチを開始",
|
||||||
|
"Stop Speaking": "スピーチを終了",
|
||||||
|
"Symphony Help": "Symphonyのヘルプ",
|
||||||
|
"TitleBar": {
|
||||||
|
"Close": "閉じる",
|
||||||
|
"Maximize": "最大化する",
|
||||||
|
"Menu": "メニュー",
|
||||||
|
"Minimize": "最小化する"
|
||||||
|
},
|
||||||
|
"Title Bar Style": "タイトルバーのスタイル",
|
||||||
|
"Toggle Full Screen": "画面表示を切り替え",
|
||||||
|
"Troubleshooting": "トラブルシューティング",
|
||||||
|
"Unable to generate crash reports due to ": "クラッシュレポートを生成できません。理由: ",
|
||||||
|
"Unable to generate logs due to ": "ログを生成できません。理由:",
|
||||||
|
"Undo": "元に戻す",
|
||||||
|
"Updating Title bar style requires Symphony to relaunch.": "タイトルバーのスタイルを更新するには、Symphonyが再起動する必要があります。",
|
||||||
|
"View": "ビュー",
|
||||||
|
"Window": "ウインドウ",
|
||||||
|
"Your administrator has disabled": "管理者によて無効にされています",
|
||||||
|
"Zoom": "ズーム",
|
||||||
|
"Zoom In": "ズームイン",
|
||||||
|
"Zoom Out": "ズームアウト"
|
||||||
|
}
|
@ -26,7 +26,7 @@ export default class AboutApp extends React.Component<{}, IState> {
|
|||||||
/**
|
/**
|
||||||
* main render function
|
* main render function
|
||||||
*/
|
*/
|
||||||
public render() {
|
public render(): JSX.Element {
|
||||||
const { clientVersion, version, buildNumber } = this.state;
|
const { clientVersion, version, buildNumber } = this.state;
|
||||||
const appName = remote.app.getName() || 'Symphony';
|
const appName = remote.app.getName() || 'Symphony';
|
||||||
const versionString = `Version ${clientVersion}-${version} (${buildNumber})`;
|
const versionString = `Version ${clientVersion}-${version} (${buildNumber})`;
|
||||||
@ -45,7 +45,7 @@ export default class AboutApp extends React.Component<{}, IState> {
|
|||||||
ipcRenderer.on('about-app-data', this.updateState.bind(this));
|
ipcRenderer.on('about-app-data', this.updateState.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount(): void {
|
||||||
ipcRenderer.removeListener('open-file-reply', this.updateState);
|
ipcRenderer.removeListener('open-file-reply', this.updateState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ export default class AboutApp extends React.Component<{}, IState> {
|
|||||||
* @param _event
|
* @param _event
|
||||||
* @param data {Object} { buildNumber, clientVersion, version }
|
* @param data {Object} { buildNumber, clientVersion, version }
|
||||||
*/
|
*/
|
||||||
private updateState(_event, data) {
|
private updateState(_event, data): void {
|
||||||
this.setState(data as IState);
|
this.setState(data as IState);
|
||||||
}
|
}
|
||||||
}
|
}
|
BIN
src/renderer/assets/symphony-title-bar-logo.png
Normal file
BIN
src/renderer/assets/symphony-title-bar-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 872 B |
@ -9,7 +9,7 @@ export default class LoadingScreen extends React.PureComponent {
|
|||||||
/**
|
/**
|
||||||
* main render function
|
* main render function
|
||||||
*/
|
*/
|
||||||
public render() {
|
public render(): JSX.Element {
|
||||||
const appName = remote.app.getName() || 'Symphony';
|
const appName = remote.app.getName() || 'Symphony';
|
||||||
return (
|
return (
|
||||||
<div className='LoadingScreen'>
|
<div className='LoadingScreen'>
|
||||||
|
@ -9,7 +9,7 @@ document.addEventListener('DOMContentLoaded', load);
|
|||||||
/**
|
/**
|
||||||
* Loads the appropriate component
|
* Loads the appropriate component
|
||||||
*/
|
*/
|
||||||
export function load() {
|
function load() {
|
||||||
const query = new URL(window.location.href).searchParams;
|
const query = new URL(window.location.href).searchParams;
|
||||||
const componentName = query.get('componentName');
|
const componentName = query.get('componentName');
|
||||||
|
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import * as ReactDOM from 'react-dom';
|
||||||
|
|
||||||
|
import WindowsTitleBar from '../renderer/windows-title-bar';
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', load);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injects custom title bar to the document body
|
||||||
|
*/
|
||||||
|
function load() {
|
||||||
|
const element = React.createElement(WindowsTitleBar);
|
||||||
|
ReactDOM.render(element, document.body);
|
||||||
|
}
|
107
src/renderer/styles/title-bar.css
Normal file
107
src/renderer/styles/title-bar.css
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
.title-bar {
|
||||||
|
display: flex;
|
||||||
|
position: fixed;
|
||||||
|
background: rgba(74,74,74,1);
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 32px;
|
||||||
|
padding-left: 0;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
-webkit-app-region: drag;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
box-sizing: content-box;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-menu-button {
|
||||||
|
color: rgba(255,255,255,1);
|
||||||
|
text-align: center;
|
||||||
|
width: 40px;
|
||||||
|
height: 32px;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
border-image: initial;
|
||||||
|
display: inline-grid;
|
||||||
|
border-radius: 0;
|
||||||
|
padding: 11px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-menu-button:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-container {
|
||||||
|
height: 32px;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-title {
|
||||||
|
font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
|
||||||
|
color: white;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 10px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-button-container {
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
right: 0;
|
||||||
|
color: rgba(255,255,255,1);
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
text-align: center;
|
||||||
|
width: 45px;
|
||||||
|
height: 32px;
|
||||||
|
background: rgba(74,74,74,1);
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-button {
|
||||||
|
color: rgba(255,255,255,1);
|
||||||
|
text-align: center;
|
||||||
|
width: 45px;
|
||||||
|
height: 32px;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
border-image: initial;
|
||||||
|
display: inline-grid;
|
||||||
|
border-radius: 0;
|
||||||
|
padding: 10px 15px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-button:hover {
|
||||||
|
background-color: rgba(51,51,51,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-button:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-button-container:hover {
|
||||||
|
background-color: rgba(51,51,51,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-border {
|
||||||
|
border-left: 1px solid rgba(74,74,74,1);
|
||||||
|
border-right: 1px solid rgba(74,74,74,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-window-border {
|
||||||
|
position: fixed;
|
||||||
|
border-bottom: 1px solid rgba(74,74,74,1);
|
||||||
|
width: 100%;
|
||||||
|
z-index: 3000;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
249
src/renderer/windows-title-bar.tsx
Normal file
249
src/renderer/windows-title-bar.tsx
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
import { ipcRenderer, remote } from 'electron';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { apiCmds, apiName } from '../common/api-interface';
|
||||||
|
import { i18n } from '../common/i18n';
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
isMaximized: boolean;
|
||||||
|
isFullScreen: boolean;
|
||||||
|
titleBarHeight: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class WindowsTitleBar extends React.Component<{}, IState> {
|
||||||
|
private window: Electron.BrowserWindow;
|
||||||
|
private readonly eventHandlers = {
|
||||||
|
onClose: () => this.close(),
|
||||||
|
onMaximize: () => this.maximize(),
|
||||||
|
onMinimize: () => this.minimize(),
|
||||||
|
onShowMenu: () => this.showMenu(),
|
||||||
|
onUnmaximize: () => this.unmaximize(),
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.window = remote.getCurrentWindow();
|
||||||
|
this.state = {
|
||||||
|
isFullScreen: this.window.isFullScreen(),
|
||||||
|
isMaximized: this.window.isMaximized(),
|
||||||
|
titleBarHeight: '32px',
|
||||||
|
};
|
||||||
|
// Adds borders to the window
|
||||||
|
this.addWindowBorders();
|
||||||
|
|
||||||
|
this.renderMaximizeButtons = this.renderMaximizeButtons.bind(this);
|
||||||
|
// Event to capture and update icons
|
||||||
|
this.window.on('maximize', () => this.updateState({ isMaximized: true }));
|
||||||
|
this.window.on('unmaximize', () => this.updateState({ isMaximized: false }));
|
||||||
|
this.window.on('enter-full-screen', () => this.updateState({ isFullScreen: true }));
|
||||||
|
this.window.on('leave-full-screen', () => this.updateState({ isFullScreen: false }));
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentDidMount() {
|
||||||
|
const contentWrapper = document.getElementById('content-wrapper');
|
||||||
|
if (contentWrapper) {
|
||||||
|
if (this.state.isFullScreen) {
|
||||||
|
contentWrapper.style.marginTop = '0px';
|
||||||
|
document.body.style.removeProperty('margin-top');
|
||||||
|
} else {
|
||||||
|
contentWrapper.style.marginTop = this.state.titleBarHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentWillMount() {
|
||||||
|
this.window.removeListener('maximize', this.updateState);
|
||||||
|
this.window.removeListener('unmaximize', this.updateState);
|
||||||
|
this.window.removeListener('enter-full-screen', this.updateState);
|
||||||
|
this.window.removeListener('leave-full-screen', this.updateState);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the custom title bar
|
||||||
|
*/
|
||||||
|
public render(): JSX.Element | null {
|
||||||
|
|
||||||
|
const { isFullScreen } = this.state;
|
||||||
|
const style = { display: isFullScreen ? 'none' : 'flex' };
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='title-bar'
|
||||||
|
onDoubleClick={this.state.isMaximized ? this.eventHandlers.onUnmaximize : this.eventHandlers.onMaximize}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
|
<div className='title-bar-button-container'>
|
||||||
|
<button
|
||||||
|
title={i18n.t('Menu')}
|
||||||
|
className='hamburger-menu-button'
|
||||||
|
onClick={this.eventHandlers.onShowMenu}
|
||||||
|
onMouseDown={this.handleMouseDown}
|
||||||
|
>
|
||||||
|
<svg x='0px' y='0px' viewBox='0 0 15 10'>
|
||||||
|
<rect fill='rgba(255, 255, 255, 0.9)' width='15' height='1'/>
|
||||||
|
<rect fill='rgba(255, 255, 255, 0.9)' y='4' width='15' height='1'/>
|
||||||
|
<rect fill='rgba(255, 255, 255, 0.9)' y='8' width='152' height='1'/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className='title-container'>
|
||||||
|
<img src='./assets/symphony-title-bar-logo.png'/>
|
||||||
|
<p className='title-bar-title'>{document.title || 'Symphony'}</p>
|
||||||
|
</div>
|
||||||
|
<div className='title-bar-button-container'>
|
||||||
|
<button
|
||||||
|
className='title-bar-button'
|
||||||
|
title={i18n.t('Minimize')}
|
||||||
|
onClick={this.eventHandlers.onMinimize}
|
||||||
|
onMouseDown={this.handleMouseDown}
|
||||||
|
>
|
||||||
|
<svg x='0px' y='0px' viewBox='0 0 14 1'>
|
||||||
|
<rect fill='rgba(255, 255, 255, 0.9)' width='14' height='0.6'/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className='title-bar-button-container'>
|
||||||
|
{this.renderMaximizeButtons()}
|
||||||
|
</div>
|
||||||
|
<div className='title-bar-button-container'>
|
||||||
|
<button
|
||||||
|
className='title-bar-button'
|
||||||
|
title={i18n.t('Close')}
|
||||||
|
onClick={this.eventHandlers.onClose}
|
||||||
|
onMouseDown={this.handleMouseDown}
|
||||||
|
>
|
||||||
|
<svg x='0px' y='0px' viewBox='0 0 14 10.2'>
|
||||||
|
<polygon
|
||||||
|
fill='rgba(255, 255, 255, 0.9)'
|
||||||
|
points='10.2,0.7 9.5,0 5.1,4.4 0.7,0 0,0.7 4.4,5.1 0,9.5 0.7,10.2 5.1,5.8 9.5,10.2 10.2,9.5 5.8,5.1 '
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders maximize or minimize buttons based on fullscreen state
|
||||||
|
*/
|
||||||
|
public renderMaximizeButtons(): JSX.Element {
|
||||||
|
const { isMaximized } = this.state;
|
||||||
|
|
||||||
|
if (isMaximized) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className='title-bar-button'
|
||||||
|
title={i18n.t('Maximize')}
|
||||||
|
onClick={this.eventHandlers.onUnmaximize}
|
||||||
|
onMouseDown={this.handleMouseDown}
|
||||||
|
>
|
||||||
|
<svg x='0px' y='0px' viewBox='0 0 14 10.2'>
|
||||||
|
<path
|
||||||
|
fill='rgba(255, 255, 255, 0.9)'
|
||||||
|
d='M2.1,0v2H0v8.1h8.2v-2h2V0H2.1z M7.2,9.2H1.1V3h6.1V9.2z M9.2,7.1h-1V2H3.1V1h6.1V7.1z'
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className='title-bar-button'
|
||||||
|
title={i18n.t('unMaximize')}
|
||||||
|
onClick={this.eventHandlers.onMaximize }
|
||||||
|
onMouseDown={this.handleMouseDown}
|
||||||
|
>
|
||||||
|
<svg x='0px' y='0px' viewBox='0 0 14 10.2'>
|
||||||
|
<path
|
||||||
|
fill='rgba(255, 255, 255, 0.9)'
|
||||||
|
d='M0,0v10.1h10.2V0H0z M9.2,9.2H1.1V1h8.1V9.2z'
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method that closes the browser window
|
||||||
|
*/
|
||||||
|
public close(): void {
|
||||||
|
if (this.isValidWindow()) {
|
||||||
|
this.window.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method that minimizes the browser window
|
||||||
|
*/
|
||||||
|
public minimize(): void {
|
||||||
|
if (this.isValidWindow()) {
|
||||||
|
this.window.minimize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method that maximize the browser window
|
||||||
|
*/
|
||||||
|
public maximize(): void {
|
||||||
|
if (this.isValidWindow()) {
|
||||||
|
console.log(this.window.maximize());
|
||||||
|
this.window.maximize();
|
||||||
|
this.setState({ isMaximized: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method that unmaximize the browser window
|
||||||
|
*/
|
||||||
|
public unmaximize(): void {
|
||||||
|
if (this.isValidWindow()) {
|
||||||
|
this.window.isFullScreen() ? this.window.setFullScreen(false) : this.window.unmaximize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method that popup the application menu
|
||||||
|
*/
|
||||||
|
public showMenu(): void {
|
||||||
|
if (this.isValidWindow()) {
|
||||||
|
ipcRenderer.send(apiName.symphonyApi, {
|
||||||
|
cmd: apiCmds.popupMenu,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* verifies if the this.window is valid and is not destroyed
|
||||||
|
*/
|
||||||
|
public isValidWindow(): boolean {
|
||||||
|
return (this.window && !this.window.isDestroyed());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent default to make sure buttons don't take focus
|
||||||
|
* @param e
|
||||||
|
*/
|
||||||
|
private handleMouseDown(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds borders to the edges of the window chrome
|
||||||
|
*/
|
||||||
|
private addWindowBorders() {
|
||||||
|
const borderBottom = document.createElement('div');
|
||||||
|
borderBottom.className = 'bottom-window-border';
|
||||||
|
|
||||||
|
document.body.appendChild(borderBottom);
|
||||||
|
document.body.classList.add('window-border');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the state with the give value
|
||||||
|
* @param state
|
||||||
|
*/
|
||||||
|
private updateState(state: Partial<IState>) {
|
||||||
|
this.setState((s) => Object.assign(s, state));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user