Use native dark theme titlebar on Windows
This commit is contained in:
parent
b574ba531d
commit
23e3883ce0
43 changed files with 152 additions and 965 deletions
|
@ -7,7 +7,6 @@ import React from 'react';
|
||||||
|
|
||||||
import 'sanitize.css';
|
import 'sanitize.css';
|
||||||
import '../stylesheets/manifest.scss';
|
import '../stylesheets/manifest.scss';
|
||||||
import '../node_modules/@indutny/frameless-titlebar/dist/styles.css';
|
|
||||||
|
|
||||||
import * as styles from './styles.scss';
|
import * as styles from './styles.scss';
|
||||||
import messages from '../_locales/en/messages.json';
|
import messages from '../_locales/en/messages.json';
|
||||||
|
@ -97,7 +96,6 @@ window.SignalContext = {
|
||||||
waitForChange: () => new Promise(noop),
|
waitForChange: () => new Promise(noop),
|
||||||
},
|
},
|
||||||
OS: {
|
OS: {
|
||||||
hasCustomTitleBar: () => false,
|
|
||||||
getClassName: () => '',
|
getClassName: () => '',
|
||||||
platform: '',
|
platform: '',
|
||||||
release: '',
|
release: '',
|
||||||
|
|
|
@ -13,30 +13,6 @@ Signal Desktop makes use of the following open source projects.
|
||||||
|
|
||||||
License: MIT
|
License: MIT
|
||||||
|
|
||||||
## @indutny/frameless-titlebar
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2019 Cristian Ponce
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
## @indutny/sneequals
|
## @indutny/sneequals
|
||||||
|
|
||||||
Copyright Fedor Indutny, 2022.
|
Copyright Fedor Indutny, 2022.
|
||||||
|
|
|
@ -20,11 +20,6 @@
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
type="text/css"
|
type="text/css"
|
||||||
/>
|
/>
|
||||||
<link
|
|
||||||
href="node_modules/@indutny/frameless-titlebar/dist/styles.css"
|
|
||||||
rel="stylesheet"
|
|
||||||
type="text/css"
|
|
||||||
/>
|
|
||||||
<link href="stylesheets/manifest.css" rel="stylesheet" type="text/css" />
|
<link href="stylesheets/manifest.css" rel="stylesheet" type="text/css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -35,7 +35,6 @@ if (getEnvironment() === Environment.Production) {
|
||||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '';
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '';
|
||||||
process.env.SIGNAL_ENABLE_HTTP = '';
|
process.env.SIGNAL_ENABLE_HTTP = '';
|
||||||
process.env.SIGNAL_CI_CONFIG = '';
|
process.env.SIGNAL_CI_CONFIG = '';
|
||||||
process.env.CUSTOM_TITLEBAR = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We load config after we've made our modifications to NODE_ENV
|
// We load config after we've made our modifications to NODE_ENV
|
||||||
|
|
128
app/main.ts
128
app/main.ts
|
@ -31,7 +31,6 @@ import {
|
||||||
} from 'electron';
|
} from 'electron';
|
||||||
import type {
|
import type {
|
||||||
MenuItemConstructorOptions,
|
MenuItemConstructorOptions,
|
||||||
TitleBarOverlayOptions,
|
|
||||||
LoginItemSettingsOptions,
|
LoginItemSettingsOptions,
|
||||||
} from 'electron';
|
} from 'electron';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
@ -95,7 +94,6 @@ import { MainSQL } from '../ts/sql/main';
|
||||||
import * as sqlChannels from './sql_channel';
|
import * as sqlChannels from './sql_channel';
|
||||||
import * as windowState from './window_state';
|
import * as windowState from './window_state';
|
||||||
import type { CreateTemplateOptionsType } from './menu';
|
import type { CreateTemplateOptionsType } from './menu';
|
||||||
import type { MenuActionType } from '../ts/types/menu';
|
|
||||||
import { createTemplate } from './menu';
|
import { createTemplate } from './menu';
|
||||||
import { installFileHandler, installWebHandler } from './protocol_filter';
|
import { installFileHandler, installWebHandler } from './protocol_filter';
|
||||||
import OS from '../ts/util/os/osMain';
|
import OS from '../ts/util/os/osMain';
|
||||||
|
@ -541,10 +539,7 @@ async function handleUrl(rawTarget: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleCommonWindowEvents(
|
async function handleCommonWindowEvents(window: BrowserWindow) {
|
||||||
window: BrowserWindow,
|
|
||||||
titleBarOverlay: TitleBarOverlayOptions | false = false
|
|
||||||
) {
|
|
||||||
window.webContents.on('will-navigate', (event, rawTarget) => {
|
window.webContents.on('will-navigate', (event, rawTarget) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
|
@ -578,23 +573,6 @@ async function handleCommonWindowEvents(
|
||||||
await zoomFactorService.syncWindow(window);
|
await zoomFactorService.syncWindow(window);
|
||||||
|
|
||||||
nativeThemeNotifier.addWindow(window);
|
nativeThemeNotifier.addWindow(window);
|
||||||
|
|
||||||
if (titleBarOverlay) {
|
|
||||||
const onThemeChange = async () => {
|
|
||||||
try {
|
|
||||||
const newOverlay = await getTitleBarOverlay();
|
|
||||||
if (!newOverlay) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
window.setTitleBarOverlay(newOverlay);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('onThemeChange error', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
nativeTheme.on('updated', onThemeChange);
|
|
||||||
settingsChannel?.on('change:themeSetting', onThemeChange);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_WIDTH = ciMode ? 1024 : 800;
|
const DEFAULT_WIDTH = ciMode ? 1024 : 800;
|
||||||
|
@ -654,45 +632,11 @@ if (OS.isWindows()) {
|
||||||
// - Windows < 10 (7, 8)
|
// - Windows < 10 (7, 8)
|
||||||
// - macOS (but no custom titlebar is displayed, see
|
// - macOS (but no custom titlebar is displayed, see
|
||||||
// `--title-bar-drag-area-height` in `stylesheets/_titlebar.scss`
|
// `--title-bar-drag-area-height` in `stylesheets/_titlebar.scss`
|
||||||
const mainTitleBarStyle =
|
const mainTitleBarStyle = OS.isMacOS()
|
||||||
(OS.isMacOS() || OS.hasCustomTitleBar()) &&
|
|
||||||
!isTestEnvironment(getEnvironment())
|
|
||||||
? ('hidden' as const)
|
|
||||||
: ('default' as const);
|
|
||||||
|
|
||||||
const nonMainTitleBarStyle = OS.hasCustomTitleBar()
|
|
||||||
? ('hidden' as const)
|
? ('hidden' as const)
|
||||||
: ('default' as const);
|
: ('default' as const);
|
||||||
|
|
||||||
async function getTitleBarOverlay(): Promise<TitleBarOverlayOptions | false> {
|
const nonMainTitleBarStyle = 'default' as const;
|
||||||
if (!OS.hasCustomTitleBar()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const theme = await getResolvedThemeSetting();
|
|
||||||
|
|
||||||
let color: string;
|
|
||||||
let symbolColor: string;
|
|
||||||
if (theme === 'light') {
|
|
||||||
color = '#e8e8e8';
|
|
||||||
symbolColor = '#1b1b1b';
|
|
||||||
} else if (theme === 'dark') {
|
|
||||||
// $color-gray-80
|
|
||||||
color = '#2e2e2e';
|
|
||||||
// $color-gray-05
|
|
||||||
symbolColor = '#e9e9e9';
|
|
||||||
} else {
|
|
||||||
throw missingCaseError(theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
color,
|
|
||||||
symbolColor,
|
|
||||||
|
|
||||||
// Should match `--titlebar-height` in stylesheets/_titlebar.scss
|
|
||||||
height: 28 - 1,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function safeLoadURL(window: BrowserWindow, url: string): Promise<void> {
|
async function safeLoadURL(window: BrowserWindow, url: string): Promise<void> {
|
||||||
let wasDestroyed = false;
|
let wasDestroyed = false;
|
||||||
|
@ -731,8 +675,6 @@ async function createWindow() {
|
||||||
const usePreloadBundle =
|
const usePreloadBundle =
|
||||||
!isTestEnvironment(getEnvironment()) || forcePreloadBundle;
|
!isTestEnvironment(getEnvironment()) || forcePreloadBundle;
|
||||||
|
|
||||||
const titleBarOverlay = await getTitleBarOverlay();
|
|
||||||
|
|
||||||
const windowOptions: Electron.BrowserWindowConstructorOptions = {
|
const windowOptions: Electron.BrowserWindowConstructorOptions = {
|
||||||
show: false,
|
show: false,
|
||||||
width: DEFAULT_WIDTH,
|
width: DEFAULT_WIDTH,
|
||||||
|
@ -741,7 +683,6 @@ async function createWindow() {
|
||||||
minHeight: MIN_HEIGHT,
|
minHeight: MIN_HEIGHT,
|
||||||
autoHideMenuBar: false,
|
autoHideMenuBar: false,
|
||||||
titleBarStyle: mainTitleBarStyle,
|
titleBarStyle: mainTitleBarStyle,
|
||||||
titleBarOverlay,
|
|
||||||
backgroundColor: isTestEnvironment(getEnvironment())
|
backgroundColor: isTestEnvironment(getEnvironment())
|
||||||
? '#ffffff' // Tests should always be rendered on a white background
|
? '#ffffff' // Tests should always be rendered on a white background
|
||||||
: await getBackgroundColor(),
|
: await getBackgroundColor(),
|
||||||
|
@ -887,7 +828,7 @@ async function createWindow() {
|
||||||
mainWindow.webContents.openDevTools();
|
mainWindow.webContents.openDevTools();
|
||||||
}
|
}
|
||||||
|
|
||||||
await handleCommonWindowEvents(mainWindow, titleBarOverlay);
|
await handleCommonWindowEvents(mainWindow);
|
||||||
|
|
||||||
// App dock icon bounce
|
// App dock icon bounce
|
||||||
bounce.init(mainWindow);
|
bounce.init(mainWindow);
|
||||||
|
@ -1288,15 +1229,12 @@ async function showAbout() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const titleBarOverlay = await getTitleBarOverlay();
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
title: getResolvedMessagesLocale().i18n('icu:aboutSignalDesktop'),
|
title: getResolvedMessagesLocale().i18n('icu:aboutSignalDesktop'),
|
||||||
titleBarStyle: nonMainTitleBarStyle,
|
titleBarStyle: nonMainTitleBarStyle,
|
||||||
titleBarOverlay,
|
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
backgroundColor: await getBackgroundColor(),
|
backgroundColor: await getBackgroundColor(),
|
||||||
show: false,
|
show: false,
|
||||||
|
@ -1313,7 +1251,7 @@ async function showAbout() {
|
||||||
|
|
||||||
aboutWindow = new BrowserWindow(options);
|
aboutWindow = new BrowserWindow(options);
|
||||||
|
|
||||||
await handleCommonWindowEvents(aboutWindow, titleBarOverlay);
|
await handleCommonWindowEvents(aboutWindow);
|
||||||
|
|
||||||
aboutWindow.on('closed', () => {
|
aboutWindow.on('closed', () => {
|
||||||
aboutWindow = undefined;
|
aboutWindow = undefined;
|
||||||
|
@ -1338,8 +1276,6 @@ async function showSettingsWindow() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const titleBarOverlay = await getTitleBarOverlay();
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
width: 700,
|
width: 700,
|
||||||
height: 700,
|
height: 700,
|
||||||
|
@ -1347,7 +1283,6 @@ async function showSettingsWindow() {
|
||||||
resizable: false,
|
resizable: false,
|
||||||
title: getResolvedMessagesLocale().i18n('icu:signalDesktopPreferences'),
|
title: getResolvedMessagesLocale().i18n('icu:signalDesktopPreferences'),
|
||||||
titleBarStyle: mainTitleBarStyle,
|
titleBarStyle: mainTitleBarStyle,
|
||||||
titleBarOverlay,
|
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
backgroundColor: await getBackgroundColor(),
|
backgroundColor: await getBackgroundColor(),
|
||||||
show: false,
|
show: false,
|
||||||
|
@ -1364,7 +1299,7 @@ async function showSettingsWindow() {
|
||||||
|
|
||||||
settingsWindow = new BrowserWindow(options);
|
settingsWindow = new BrowserWindow(options);
|
||||||
|
|
||||||
await handleCommonWindowEvents(settingsWindow, titleBarOverlay);
|
await handleCommonWindowEvents(settingsWindow);
|
||||||
|
|
||||||
settingsWindow.on('closed', () => {
|
settingsWindow.on('closed', () => {
|
||||||
settingsWindow = undefined;
|
settingsWindow = undefined;
|
||||||
|
@ -1434,15 +1369,12 @@ async function showDebugLogWindow() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const titleBarOverlay = await getTitleBarOverlay();
|
|
||||||
|
|
||||||
const options: Electron.BrowserWindowConstructorOptions = {
|
const options: Electron.BrowserWindowConstructorOptions = {
|
||||||
width: 700,
|
width: 700,
|
||||||
height: 500,
|
height: 500,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
title: getResolvedMessagesLocale().i18n('icu:debugLog'),
|
title: getResolvedMessagesLocale().i18n('icu:debugLog'),
|
||||||
titleBarStyle: nonMainTitleBarStyle,
|
titleBarStyle: nonMainTitleBarStyle,
|
||||||
titleBarOverlay,
|
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
backgroundColor: await getBackgroundColor(),
|
backgroundColor: await getBackgroundColor(),
|
||||||
show: false,
|
show: false,
|
||||||
|
@ -1459,7 +1391,7 @@ async function showDebugLogWindow() {
|
||||||
|
|
||||||
debugLogWindow = new BrowserWindow(options);
|
debugLogWindow = new BrowserWindow(options);
|
||||||
|
|
||||||
await handleCommonWindowEvents(debugLogWindow, titleBarOverlay);
|
await handleCommonWindowEvents(debugLogWindow);
|
||||||
|
|
||||||
debugLogWindow.on('closed', () => {
|
debugLogWindow.on('closed', () => {
|
||||||
debugLogWindow = undefined;
|
debugLogWindow = undefined;
|
||||||
|
@ -2504,12 +2436,6 @@ ipc.on('locale-display-names', event => {
|
||||||
event.returnValue = getResolvedMessagesLocale().localeDisplayNames;
|
event.returnValue = getResolvedMessagesLocale().localeDisplayNames;
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO DESKTOP-5241
|
|
||||||
ipc.on('OS.getHasCustomTitleBar', event => {
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
|
||||||
event.returnValue = OS.hasCustomTitleBar();
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO DESKTOP-5241
|
// TODO DESKTOP-5241
|
||||||
ipc.on('OS.getClassName', event => {
|
ipc.on('OS.getClassName', event => {
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
@ -2836,46 +2762,6 @@ async function zoomReset() {
|
||||||
await zoomFactorService.zoomReset();
|
await zoomFactorService.zoomReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
ipc.handle('executeMenuAction', async (_event, action: MenuActionType) => {
|
|
||||||
if (action === 'forceUpdate') {
|
|
||||||
drop(forceUpdate());
|
|
||||||
} else if (action === 'openArtCreator') {
|
|
||||||
drop(openArtCreator());
|
|
||||||
} else if (action === 'openContactUs') {
|
|
||||||
openContactUs();
|
|
||||||
} else if (action === 'openForums') {
|
|
||||||
openForums();
|
|
||||||
} else if (action === 'openJoinTheBeta') {
|
|
||||||
openJoinTheBeta();
|
|
||||||
} else if (action === 'openReleaseNotes') {
|
|
||||||
openReleaseNotes();
|
|
||||||
} else if (action === 'openSupportPage') {
|
|
||||||
openSupportPage();
|
|
||||||
} else if (action === 'setupAsNewDevice') {
|
|
||||||
setupAsNewDevice();
|
|
||||||
} else if (action === 'setupAsStandalone') {
|
|
||||||
setupAsStandalone();
|
|
||||||
} else if (action === 'showAbout') {
|
|
||||||
drop(showAbout());
|
|
||||||
} else if (action === 'showDebugLog') {
|
|
||||||
drop(showDebugLogWindow());
|
|
||||||
} else if (action === 'showKeyboardShortcuts') {
|
|
||||||
showKeyboardShortcuts();
|
|
||||||
} else if (action === 'showSettings') {
|
|
||||||
drop(showSettingsWindow());
|
|
||||||
} else if (action === 'showWindow') {
|
|
||||||
showWindow();
|
|
||||||
} else if (action === 'zoomIn') {
|
|
||||||
drop(zoomIn());
|
|
||||||
} else if (action === 'zoomOut') {
|
|
||||||
drop(zoomOut());
|
|
||||||
} else if (action === 'zoomReset') {
|
|
||||||
drop(zoomReset());
|
|
||||||
} else {
|
|
||||||
throw missingCaseError(action);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ipc.handle(
|
ipc.handle(
|
||||||
'net.resolveHost',
|
'net.resolveHost',
|
||||||
(_event, hostname: string, queryType?: 'A' | 'AAAA') => {
|
(_event, hostname: string, queryType?: 'A' | 'AAAA') => {
|
||||||
|
|
|
@ -88,11 +88,6 @@
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
type="text/css"
|
type="text/css"
|
||||||
/>
|
/>
|
||||||
<link
|
|
||||||
href="node_modules/@indutny/frameless-titlebar/dist/styles.css"
|
|
||||||
rel="stylesheet"
|
|
||||||
type="text/css"
|
|
||||||
/>
|
|
||||||
<link href="stylesheets/manifest.css" rel="stylesheet" type="text/css" />
|
<link href="stylesheets/manifest.css" rel="stylesheet" type="text/css" />
|
||||||
</head>
|
</head>
|
||||||
<body class="overflow-hidden">
|
<body class="overflow-hidden">
|
||||||
|
|
|
@ -20,11 +20,6 @@
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
type="text/css"
|
type="text/css"
|
||||||
/>
|
/>
|
||||||
<link
|
|
||||||
href="node_modules/@indutny/frameless-titlebar/dist/styles.css"
|
|
||||||
rel="stylesheet"
|
|
||||||
type="text/css"
|
|
||||||
/>
|
|
||||||
<link href="stylesheets/manifest.css" rel="stylesheet" type="text/css" />
|
<link href="stylesheets/manifest.css" rel="stylesheet" type="text/css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -88,7 +88,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@formatjs/fast-memoize": "1.2.6",
|
"@formatjs/fast-memoize": "1.2.6",
|
||||||
"@formatjs/intl-localematcher": "0.2.32",
|
"@formatjs/intl-localematcher": "0.2.32",
|
||||||
"@indutny/frameless-titlebar": "2.3.5",
|
|
||||||
"@indutny/sneequals": "4.0.0",
|
"@indutny/sneequals": "4.0.0",
|
||||||
"@nodert-win10-rs4/windows.data.xml.dom": "0.4.4",
|
"@nodert-win10-rs4/windows.data.xml.dom": "0.4.4",
|
||||||
"@nodert-win10-rs4/windows.ui.notifications": "0.4.4",
|
"@nodert-win10-rs4/windows.ui.notifications": "0.4.4",
|
||||||
|
|
|
@ -20,11 +20,6 @@
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
type="text/css"
|
type="text/css"
|
||||||
/>
|
/>
|
||||||
<link
|
|
||||||
href="node_modules/@indutny/frameless-titlebar/dist/styles.css"
|
|
||||||
rel="stylesheet"
|
|
||||||
type="text/css"
|
|
||||||
/>
|
|
||||||
<link href="stylesheets/manifest.css" rel="stylesheet" type="text/css" />
|
<link href="stylesheets/manifest.css" rel="stylesheet" type="text/css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -784,8 +784,8 @@ $rtl-icon-map: (
|
||||||
@mixin install-screen {
|
@mixin install-screen {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
width: var(--window-width);
|
width: 100vw;
|
||||||
height: var(--window-height);
|
height: 100vh;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
|
@ -3586,7 +3586,7 @@ button.module-image__border-overlay:focus {
|
||||||
// - size themselves in relation to viewport (position: fixed)
|
// - size themselves in relation to viewport (position: fixed)
|
||||||
&__modal-container {
|
&__modal-container {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: var(--titlebar-height);
|
top: 0;
|
||||||
inset-inline-start: 0;
|
inset-inline-start: 0;
|
||||||
z-index: $z-index-calling-container;
|
z-index: $z-index-calling-container;
|
||||||
}
|
}
|
||||||
|
@ -3596,12 +3596,12 @@ button.module-image__border-overlay:focus {
|
||||||
background-color: $calling-background-color;
|
background-color: $calling-background-color;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: var(--window-height);
|
height: 100vh;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
/* stylelint-disable-next-line liberty/use-logical-spec */
|
/* stylelint-disable-next-line liberty/use-logical-spec */
|
||||||
left: 0;
|
left: 0;
|
||||||
top: var(--titlebar-height);
|
top: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: $z-index-calling;
|
z-index: $z-index-calling;
|
||||||
}
|
}
|
||||||
|
@ -3728,7 +3728,7 @@ button.module-image__border-overlay:focus {
|
||||||
|
|
||||||
&__remote-video-disabled {
|
&__remote-video-disabled {
|
||||||
background-color: $color-gray-95;
|
background-color: $color-gray-95;
|
||||||
height: var(--window-height);
|
height: 100vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -4299,8 +4299,8 @@ button.module-image__border-overlay:focus {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: var(--window-width);
|
width: 100vw;
|
||||||
height: var(--window-height);
|
height: 100vh;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
inset-inline-start: 0;
|
inset-inline-start: 0;
|
||||||
z-index: $z-index-calling;
|
z-index: $z-index-calling;
|
||||||
|
@ -4437,7 +4437,7 @@ button.module-image__border-overlay:focus {
|
||||||
color: $color-gray-05;
|
color: $color-gray-05;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: var(--window-height);
|
height: 100vh;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
@ -6777,10 +6777,10 @@ button.module-image__border-overlay:focus {
|
||||||
|
|
||||||
.module-modal-host__overlay {
|
.module-modal-host__overlay {
|
||||||
background: $color-black-alpha-40;
|
background: $color-black-alpha-40;
|
||||||
width: var(--window-width);
|
width: 100vw;
|
||||||
height: var(--window-height);
|
height: 100vh;
|
||||||
inset-inline-start: var(--window-border);
|
inset-inline-start: 0;
|
||||||
top: var(--titlebar-height);
|
top: 0;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: $z-index-modal-host;
|
z-index: $z-index-modal-host;
|
||||||
}
|
}
|
||||||
|
@ -6788,10 +6788,10 @@ button.module-image__border-overlay:focus {
|
||||||
.module-modal-host__overlay-container {
|
.module-modal-host__overlay-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
width: var(--window-width);
|
width: 100vw;
|
||||||
height: var(--window-height);
|
height: 100vh;
|
||||||
inset-inline-start: var(--window-border);
|
inset-inline-start: 0;
|
||||||
top: var(--titlebar-height);
|
top: 0;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -6937,10 +6937,10 @@ button.module-image__border-overlay:focus {
|
||||||
.module-progress-dialog__overlay {
|
.module-progress-dialog__overlay {
|
||||||
background: $color-black-alpha-40;
|
background: $color-black-alpha-40;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset-inline-start: var(--window-border);
|
inset-inline-start: 0;
|
||||||
top: var(--titlebar-height);
|
top: 0;
|
||||||
width: var(--window-width);
|
width: 100vw;
|
||||||
height: var(--window-height);
|
height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
@ -13,22 +13,4 @@ body {
|
||||||
&.os-macos:not(.full-screen) {
|
&.os-macos:not(.full-screen) {
|
||||||
--title-bar-drag-area-height: calc(28px / var(--zoom-factor));
|
--title-bar-drag-area-height: calc(28px / var(--zoom-factor));
|
||||||
}
|
}
|
||||||
|
|
||||||
--window-height: 100vh;
|
|
||||||
--window-width: 100vw;
|
|
||||||
--unscaled-window-border: 0px;
|
|
||||||
--window-border: calc(var(--unscaled-window-border) / var(--zoom-factor));
|
|
||||||
--titlebar-height: 0px;
|
|
||||||
|
|
||||||
&.os-has-custom-titlebar {
|
|
||||||
&:not(.maximized) {
|
|
||||||
--unscaled-window-border: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
--titlebar-height: calc(28px / var(--zoom-factor));
|
|
||||||
--window-width: calc(100vw - 2 * var(--window-border));
|
|
||||||
--window-height: calc(
|
|
||||||
100vh - var(--titlebar-height) - var(--window-border)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
color: $color-white;
|
color: $color-white;
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
height: var(--window-height);
|
height: 100vh;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
@ -130,7 +130,7 @@
|
||||||
.CallControls__MoreOptionsMenu {
|
.CallControls__MoreOptionsMenu {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
max-height: calc(var(--window-height) - 155px);
|
max-height: calc(100vh - 155px);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
filter: drop-shadow(0px 4px 3px $color-black-alpha-20);
|
filter: drop-shadow(0px 4px 3px $color-black-alpha-20);
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
|
@ -138,7 +138,7 @@
|
||||||
|
|
||||||
.CallControls__MoreOptionsMenu .module-emoji-picker {
|
.CallControls__MoreOptionsMenu .module-emoji-picker {
|
||||||
margin-bottom: auto;
|
margin-bottom: auto;
|
||||||
max-width: calc(var(--window-width) / 2 + 20px);
|
max-width: calc(100vw / 2 + 20px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.CallControls__MoreOptionsMenu
|
.CallControls__MoreOptionsMenu
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
inset-inline: 0;
|
inset-inline: 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: var(--titlebar-height);
|
top: 0;
|
||||||
z-index: $z-index-popup;
|
z-index: $z-index-popup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
background: $color-gray-95;
|
background: $color-gray-95;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: var(--window-width);
|
width: 100vw;
|
||||||
height: var(--window-height);
|
height: 100vh;
|
||||||
inset-inline-start: 0;
|
inset-inline-start: 0;
|
||||||
top: var(--titlebar-height);
|
top: 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-app-region: no-drag;
|
-webkit-app-region: no-drag;
|
||||||
|
|
|
@ -101,7 +101,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&__settings-pane {
|
&__settings-pane {
|
||||||
height: var(--window-height);
|
height: 100vh;
|
||||||
overflow: overlay;
|
overflow: overlay;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
|
|
||||||
max-height: calc(var(--window-height) - 40px);
|
max-height: calc(100vh - 40px);
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
.Stories {
|
.Stories {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: var(--window-height);
|
height: 100vh;
|
||||||
inset-inline-start: 0;
|
inset-inline-start: 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
background: $color-gray-95;
|
background: $color-gray-95;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: var(--window-width);
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
inset-inline-start: 0;
|
inset-inline-start: 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
// Copyright 2022 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
.TitleBarContainer {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100vh;
|
|
||||||
|
|
||||||
--border-color: transparent;
|
|
||||||
|
|
||||||
&--active {
|
|
||||||
--border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
border: var(--window-border) solid var(--border-color);
|
|
||||||
|
|
||||||
@mixin titlebar-position {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
inset-inline-start: 0;
|
|
||||||
|
|
||||||
width: calc(100vw * var(--zoom-factor));
|
|
||||||
z-index: $z-index-window-controls;
|
|
||||||
transform: scale(calc(1 / var(--zoom-factor)));
|
|
||||||
transform-origin: 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw bottom-less border frame around titlebar to prevent border-bottom
|
|
||||||
// color from leaking to corners.
|
|
||||||
&:after {
|
|
||||||
content: '';
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
@include titlebar-position;
|
|
||||||
|
|
||||||
height: calc(var(--titlebar-height) * var(--zoom-factor));
|
|
||||||
|
|
||||||
border: var(--unscaled-window-border) solid var(--border-color);
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__title {
|
|
||||||
@include titlebar-position;
|
|
||||||
border: var(--unscaled-window-border) solid transparent;
|
|
||||||
|
|
||||||
// This matches the inline styles of frameless-titlebar
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
|
|
||||||
Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', Arial,
|
|
||||||
sans-serif;
|
|
||||||
|
|
||||||
padding-inline-start: env(titlebar-area-x, 0);
|
|
||||||
|
|
||||||
& button {
|
|
||||||
font-family: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__padding {
|
|
||||||
height: calc(var(--titlebar-height) - var(--window-border));
|
|
||||||
}
|
|
||||||
|
|
||||||
&__content {
|
|
||||||
height: var(--window-height);
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -153,7 +153,6 @@
|
||||||
@import './components/TimelineFloatingHeader.scss';
|
@import './components/TimelineFloatingHeader.scss';
|
||||||
@import './components/TimelineWarning.scss';
|
@import './components/TimelineWarning.scss';
|
||||||
@import './components/TimelineWarnings.scss';
|
@import './components/TimelineWarnings.scss';
|
||||||
@import './components/TitleBarContainer.scss';
|
|
||||||
@import './components/Toast.scss';
|
@import './components/Toast.scss';
|
||||||
@import './components/Waveform.scss';
|
@import './components/Waveform.scss';
|
||||||
@import './components/WaveformScrubber.scss';
|
@import './components/WaveformScrubber.scss';
|
||||||
|
|
|
@ -3,17 +3,12 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import type { ExecuteMenuRoleType } from './TitleBarContainer';
|
|
||||||
import type { LocalizerType } from '../types/Util';
|
import type { LocalizerType } from '../types/Util';
|
||||||
import { TitleBarContainer } from './TitleBarContainer';
|
|
||||||
import { useEscapeHandling } from '../hooks/useEscapeHandling';
|
import { useEscapeHandling } from '../hooks/useEscapeHandling';
|
||||||
import { useTheme } from '../hooks/useTheme';
|
|
||||||
|
|
||||||
export type PropsType = {
|
export type PropsType = {
|
||||||
closeAbout: () => unknown;
|
closeAbout: () => unknown;
|
||||||
environment: string;
|
environment: string;
|
||||||
executeMenuRole: ExecuteMenuRoleType;
|
|
||||||
hasCustomTitleBar: boolean;
|
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
version: string;
|
version: string;
|
||||||
};
|
};
|
||||||
|
@ -21,46 +16,36 @@ export type PropsType = {
|
||||||
export function About({
|
export function About({
|
||||||
closeAbout,
|
closeAbout,
|
||||||
environment,
|
environment,
|
||||||
executeMenuRole,
|
|
||||||
hasCustomTitleBar,
|
|
||||||
i18n,
|
i18n,
|
||||||
version,
|
version,
|
||||||
}: PropsType): JSX.Element {
|
}: PropsType): JSX.Element {
|
||||||
useEscapeHandling(closeAbout);
|
useEscapeHandling(closeAbout);
|
||||||
|
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TitleBarContainer
|
<div className="About">
|
||||||
hasCustomTitleBar={hasCustomTitleBar}
|
<div className="module-splash-screen">
|
||||||
theme={theme}
|
<div className="module-splash-screen__logo module-img--150" />
|
||||||
executeMenuRole={executeMenuRole}
|
|
||||||
>
|
|
||||||
<div className="About">
|
|
||||||
<div className="module-splash-screen">
|
|
||||||
<div className="module-splash-screen__logo module-img--150" />
|
|
||||||
|
|
||||||
<div className="version">{version}</div>
|
<div className="version">{version}</div>
|
||||||
<div className="environment">{environment}</div>
|
<div className="environment">{environment}</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="https://signal.org">signal.org</a>
|
<a href="https://signal.org">signal.org</a>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
className="acknowledgments"
|
className="acknowledgments"
|
||||||
href="https://github.com/signalapp/Signal-Desktop/blob/main/ACKNOWLEDGMENTS.md"
|
href="https://github.com/signalapp/Signal-Desktop/blob/main/ACKNOWLEDGMENTS.md"
|
||||||
>
|
>
|
||||||
{i18n('icu:softwareAcknowledgments')}
|
{i18n('icu:softwareAcknowledgments')}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a className="privacy" href="https://signal.org/legal">
|
<a className="privacy" href="https://signal.org/legal">
|
||||||
{i18n('icu:privacyPolicy')}
|
{i18n('icu:privacyPolicy')}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TitleBarContainer>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,6 @@ import React, { useEffect } from 'react';
|
||||||
import { Globals } from '@react-spring/web';
|
import { Globals } from '@react-spring/web';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import type { ExecuteMenuRoleType } from './TitleBarContainer';
|
|
||||||
import type { MenuOptionsType, MenuActionType } from '../types/menu';
|
|
||||||
import type { AnyToast } from '../types/Toast';
|
import type { AnyToast } from '../types/Toast';
|
||||||
import type { ViewStoryActionCreatorType } from '../state/ducks/stories';
|
import type { ViewStoryActionCreatorType } from '../state/ducks/stories';
|
||||||
import type { LocalizerType } from '../types/Util';
|
import type { LocalizerType } from '../types/Util';
|
||||||
|
@ -15,7 +13,6 @@ import { ThemeType } from '../types/Util';
|
||||||
import { AppViewType } from '../state/ducks/app';
|
import { AppViewType } from '../state/ducks/app';
|
||||||
import { SmartInstallScreen } from '../state/smart/InstallScreen';
|
import { SmartInstallScreen } from '../state/smart/InstallScreen';
|
||||||
import { StandaloneRegistration } from './StandaloneRegistration';
|
import { StandaloneRegistration } from './StandaloneRegistration';
|
||||||
import { TitleBarContainer } from './TitleBarContainer';
|
|
||||||
import { ToastManager } from './ToastManager';
|
import { ToastManager } from './ToastManager';
|
||||||
import { usePageVisibility } from '../hooks/usePageVisibility';
|
import { usePageVisibility } from '../hooks/usePageVisibility';
|
||||||
import { useReducedMotion } from '../hooks/useReducedMotion';
|
import { useReducedMotion } from '../hooks/useReducedMotion';
|
||||||
|
@ -42,18 +39,12 @@ type PropsType = {
|
||||||
theme: ThemeType;
|
theme: ThemeType;
|
||||||
isMaximized: boolean;
|
isMaximized: boolean;
|
||||||
isFullScreen: boolean;
|
isFullScreen: boolean;
|
||||||
menuOptions: MenuOptionsType;
|
|
||||||
onUndoArchive: (conversationId: string) => unknown;
|
onUndoArchive: (conversationId: string) => unknown;
|
||||||
openFileInFolder: (target: string) => unknown;
|
openFileInFolder: (target: string) => unknown;
|
||||||
hasCustomTitleBar: boolean;
|
|
||||||
OS: string;
|
OS: string;
|
||||||
osClassName: string;
|
osClassName: string;
|
||||||
hideMenuBar: boolean;
|
|
||||||
|
|
||||||
executeMenuRole: ExecuteMenuRoleType;
|
|
||||||
executeMenuAction: (action: MenuActionType) => void;
|
|
||||||
hideToast: () => unknown;
|
hideToast: () => unknown;
|
||||||
titleBarDoubleClick: () => void;
|
|
||||||
toast?: AnyToast;
|
toast?: AnyToast;
|
||||||
scrollToMessage: (conversationId: string, messageId: string) => unknown;
|
scrollToMessage: (conversationId: string, messageId: string) => unknown;
|
||||||
viewStory: ViewStoryActionCreatorType;
|
viewStory: ViewStoryActionCreatorType;
|
||||||
|
@ -62,16 +53,11 @@ type PropsType = {
|
||||||
|
|
||||||
export function App({
|
export function App({
|
||||||
appView,
|
appView,
|
||||||
executeMenuAction,
|
|
||||||
executeMenuRole,
|
|
||||||
hasCustomTitleBar,
|
|
||||||
hasSelectedStoryData,
|
hasSelectedStoryData,
|
||||||
hideMenuBar,
|
|
||||||
hideToast,
|
hideToast,
|
||||||
i18n,
|
i18n,
|
||||||
isFullScreen,
|
isFullScreen,
|
||||||
isMaximized,
|
isMaximized,
|
||||||
menuOptions,
|
|
||||||
onUndoArchive,
|
onUndoArchive,
|
||||||
openFileInFolder,
|
openFileInFolder,
|
||||||
openInbox,
|
openInbox,
|
||||||
|
@ -85,7 +71,6 @@ export function App({
|
||||||
renderStoryViewer,
|
renderStoryViewer,
|
||||||
requestVerification,
|
requestVerification,
|
||||||
theme,
|
theme,
|
||||||
titleBarDoubleClick,
|
|
||||||
toast,
|
toast,
|
||||||
viewStory,
|
viewStory,
|
||||||
}: PropsType): JSX.Element {
|
}: PropsType): JSX.Element {
|
||||||
|
@ -127,10 +112,6 @@ export function App({
|
||||||
document.body.classList.add(osClassName);
|
document.body.classList.add(osClassName);
|
||||||
}, [osClassName]);
|
}, [osClassName]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
document.body.classList.toggle('os-has-custom-titlebar', hasCustomTitleBar);
|
|
||||||
}, [hasCustomTitleBar]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.body.classList.toggle('full-screen', isFullScreen);
|
document.body.classList.toggle('full-screen', isFullScreen);
|
||||||
document.body.classList.toggle('maximized', isMaximized);
|
document.body.classList.toggle('maximized', isMaximized);
|
||||||
|
@ -150,41 +131,27 @@ export function App({
|
||||||
}, [prefersReducedMotion]);
|
}, [prefersReducedMotion]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TitleBarContainer
|
<div
|
||||||
theme={theme}
|
className={classNames({
|
||||||
isMaximized={isMaximized}
|
App: true,
|
||||||
isFullScreen={isFullScreen}
|
'light-theme': theme === ThemeType.light,
|
||||||
hasCustomTitleBar={hasCustomTitleBar}
|
'dark-theme': theme === ThemeType.dark,
|
||||||
executeMenuRole={executeMenuRole}
|
})}
|
||||||
titleBarDoubleClick={titleBarDoubleClick}
|
|
||||||
hasMenu
|
|
||||||
hideMenuBar={hideMenuBar}
|
|
||||||
i18n={i18n}
|
|
||||||
menuOptions={menuOptions}
|
|
||||||
executeMenuAction={executeMenuAction}
|
|
||||||
>
|
>
|
||||||
<div
|
{contents}
|
||||||
className={classNames({
|
<ToastManager
|
||||||
App: true,
|
OS={OS}
|
||||||
'light-theme': theme === ThemeType.light,
|
hideToast={hideToast}
|
||||||
'dark-theme': theme === ThemeType.dark,
|
i18n={i18n}
|
||||||
})}
|
onUndoArchive={onUndoArchive}
|
||||||
>
|
openFileInFolder={openFileInFolder}
|
||||||
{contents}
|
toast={toast}
|
||||||
<ToastManager
|
/>
|
||||||
OS={OS}
|
{renderGlobalModalContainer()}
|
||||||
hideToast={hideToast}
|
{renderCallManager()}
|
||||||
i18n={i18n}
|
{renderLightbox()}
|
||||||
onUndoArchive={onUndoArchive}
|
{hasSelectedStoryData &&
|
||||||
openFileInFolder={openFileInFolder}
|
renderStoryViewer(() => viewStory({ closeViewer: true }))}
|
||||||
toast={toast}
|
</div>
|
||||||
/>
|
|
||||||
{renderGlobalModalContainer()}
|
|
||||||
{renderCallManager()}
|
|
||||||
{renderLightbox()}
|
|
||||||
{hasSelectedStoryData &&
|
|
||||||
renderStoryViewer(() => viewStory({ closeViewer: true }))}
|
|
||||||
</div>
|
|
||||||
</TitleBarContainer>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -294,7 +294,7 @@ export function CallingPip({
|
||||||
positionState.mode === PositionMode.BeingDragged
|
positionState.mode === PositionMode.BeingDragged
|
||||||
? '-webkit-grabbing'
|
? '-webkit-grabbing'
|
||||||
: '-webkit-grab',
|
: '-webkit-grab',
|
||||||
transform: `translate3d(${localizedTranslateX}px,calc(${translateY}px - var(--titlebar-height)), 0)`,
|
transform: `translate3d(${localizedTranslateX}px,calc(${translateY}px), 0)`,
|
||||||
transition:
|
transition:
|
||||||
positionState.mode === PositionMode.BeingDragged
|
positionState.mode === PositionMode.BeingDragged
|
||||||
? 'none'
|
? 'none'
|
||||||
|
|
|
@ -26,8 +26,6 @@ const createProps = (): PropsType => ({
|
||||||
await sleep(5000);
|
await sleep(5000);
|
||||||
return 'https://picsum.photos/1800/900';
|
return 'https://picsum.photos/1800/900';
|
||||||
},
|
},
|
||||||
executeMenuRole: action('executeMenuRole'),
|
|
||||||
hasCustomTitleBar: true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
|
@ -4,20 +4,17 @@
|
||||||
import type { MouseEvent } from 'react';
|
import type { MouseEvent } from 'react';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import copyText from 'copy-text-to-clipboard';
|
import copyText from 'copy-text-to-clipboard';
|
||||||
import type { ExecuteMenuRoleType } from './TitleBarContainer';
|
|
||||||
import type { LocalizerType } from '../types/Util';
|
import type { LocalizerType } from '../types/Util';
|
||||||
import * as Errors from '../types/errors';
|
import * as Errors from '../types/errors';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
import { Button, ButtonVariant } from './Button';
|
import { Button, ButtonVariant } from './Button';
|
||||||
import { Spinner } from './Spinner';
|
import { Spinner } from './Spinner';
|
||||||
import { TitleBarContainer } from './TitleBarContainer';
|
|
||||||
import { ToastDebugLogError } from './ToastDebugLogError';
|
import { ToastDebugLogError } from './ToastDebugLogError';
|
||||||
import { ToastLinkCopied } from './ToastLinkCopied';
|
import { ToastLinkCopied } from './ToastLinkCopied';
|
||||||
import { ToastLoadingFullLogs } from './ToastLoadingFullLogs';
|
import { ToastLoadingFullLogs } from './ToastLoadingFullLogs';
|
||||||
import { createSupportUrl } from '../util/createSupportUrl';
|
import { createSupportUrl } from '../util/createSupportUrl';
|
||||||
import { openLinkInWebBrowser } from '../util/openLinkInWebBrowser';
|
import { openLinkInWebBrowser } from '../util/openLinkInWebBrowser';
|
||||||
import { useEscapeHandling } from '../hooks/useEscapeHandling';
|
import { useEscapeHandling } from '../hooks/useEscapeHandling';
|
||||||
import { useTheme } from '../hooks/useTheme';
|
|
||||||
|
|
||||||
enum LoadState {
|
enum LoadState {
|
||||||
NotStarted,
|
NotStarted,
|
||||||
|
@ -32,8 +29,6 @@ export type PropsType = {
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
fetchLogs: () => Promise<string>;
|
fetchLogs: () => Promise<string>;
|
||||||
uploadLogs: (logs: string) => Promise<string>;
|
uploadLogs: (logs: string) => Promise<string>;
|
||||||
hasCustomTitleBar: boolean;
|
|
||||||
executeMenuRole: ExecuteMenuRoleType;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ToastType {
|
enum ToastType {
|
||||||
|
@ -48,8 +43,6 @@ export function DebugLogWindow({
|
||||||
i18n,
|
i18n,
|
||||||
fetchLogs,
|
fetchLogs,
|
||||||
uploadLogs,
|
uploadLogs,
|
||||||
hasCustomTitleBar,
|
|
||||||
executeMenuRole,
|
|
||||||
}: PropsType): JSX.Element {
|
}: PropsType): JSX.Element {
|
||||||
const [loadState, setLoadState] = useState<LoadState>(LoadState.NotStarted);
|
const [loadState, setLoadState] = useState<LoadState>(LoadState.NotStarted);
|
||||||
const [logText, setLogText] = useState<string | undefined>();
|
const [logText, setLogText] = useState<string | undefined>();
|
||||||
|
@ -59,8 +52,6 @@ export function DebugLogWindow({
|
||||||
);
|
);
|
||||||
const [toastType, setToastType] = useState<ToastType | undefined>();
|
const [toastType, setToastType] = useState<ToastType | undefined>();
|
||||||
|
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
useEscapeHandling(closeWindow);
|
useEscapeHandling(closeWindow);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -144,41 +135,35 @@ export function DebugLogWindow({
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TitleBarContainer
|
<div className="DebugLogWindow">
|
||||||
hasCustomTitleBar={hasCustomTitleBar}
|
<div>
|
||||||
theme={theme}
|
<div className="DebugLogWindow__title">
|
||||||
executeMenuRole={executeMenuRole}
|
{i18n('icu:debugLogSuccess')}
|
||||||
>
|
|
||||||
<div className="DebugLogWindow">
|
|
||||||
<div>
|
|
||||||
<div className="DebugLogWindow__title">
|
|
||||||
{i18n('icu:debugLogSuccess')}
|
|
||||||
</div>
|
|
||||||
<p className="DebugLogWindow__subtitle">
|
|
||||||
{i18n('icu:debugLogSuccessNextSteps')}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="DebugLogWindow__container">
|
<p className="DebugLogWindow__subtitle">
|
||||||
<input
|
{i18n('icu:debugLogSuccessNextSteps')}
|
||||||
className="DebugLogWindow__link"
|
</p>
|
||||||
readOnly
|
|
||||||
type="text"
|
|
||||||
dir="auto"
|
|
||||||
value={publicLogURL}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="DebugLogWindow__footer">
|
|
||||||
<Button
|
|
||||||
onClick={() => openLinkInWebBrowser(supportURL)}
|
|
||||||
variant={ButtonVariant.Secondary}
|
|
||||||
>
|
|
||||||
{i18n('icu:reportIssue')}
|
|
||||||
</Button>
|
|
||||||
<Button onClick={copyLog}>{i18n('icu:debugLogCopy')}</Button>
|
|
||||||
</div>
|
|
||||||
{toastElement}
|
|
||||||
</div>
|
</div>
|
||||||
</TitleBarContainer>
|
<div className="DebugLogWindow__container">
|
||||||
|
<input
|
||||||
|
className="DebugLogWindow__link"
|
||||||
|
readOnly
|
||||||
|
type="text"
|
||||||
|
dir="auto"
|
||||||
|
value={publicLogURL}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="DebugLogWindow__footer">
|
||||||
|
<Button
|
||||||
|
onClick={() => openLinkInWebBrowser(supportURL)}
|
||||||
|
variant={ButtonVariant.Secondary}
|
||||||
|
>
|
||||||
|
{i18n('icu:reportIssue')}
|
||||||
|
</Button>
|
||||||
|
<Button onClick={copyLog}>{i18n('icu:debugLogCopy')}</Button>
|
||||||
|
</div>
|
||||||
|
{toastElement}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,49 +173,43 @@ export function DebugLogWindow({
|
||||||
loadState === LoadState.Started || loadState === LoadState.Submitting;
|
loadState === LoadState.Started || loadState === LoadState.Submitting;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TitleBarContainer
|
<div className="DebugLogWindow">
|
||||||
hasCustomTitleBar={hasCustomTitleBar}
|
<div>
|
||||||
theme={theme}
|
<div className="DebugLogWindow__title">
|
||||||
executeMenuRole={executeMenuRole}
|
{i18n('icu:submitDebugLog')}
|
||||||
>
|
|
||||||
<div className="DebugLogWindow">
|
|
||||||
<div>
|
|
||||||
<div className="DebugLogWindow__title">
|
|
||||||
{i18n('icu:submitDebugLog')}
|
|
||||||
</div>
|
|
||||||
<p className="DebugLogWindow__subtitle">
|
|
||||||
{i18n('icu:debugLogExplanation')}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
{isLoading ? (
|
<p className="DebugLogWindow__subtitle">
|
||||||
<div className="DebugLogWindow__container">
|
{i18n('icu:debugLogExplanation')}
|
||||||
<Spinner svgSize="normal" />
|
</p>
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="DebugLogWindow__scroll_area">
|
|
||||||
<pre className="DebugLogWindow__scroll_area__text">
|
|
||||||
{textAreaValue}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="DebugLogWindow__footer">
|
|
||||||
<Button
|
|
||||||
disabled={!canSave}
|
|
||||||
onClick={() => {
|
|
||||||
if (logText) {
|
|
||||||
downloadLog(logText);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
variant={ButtonVariant.Secondary}
|
|
||||||
>
|
|
||||||
{i18n('icu:debugLogSave')}
|
|
||||||
</Button>
|
|
||||||
<Button disabled={!canSubmit} onClick={handleSubmit}>
|
|
||||||
{i18n('icu:submit')}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
{toastElement}
|
|
||||||
</div>
|
</div>
|
||||||
</TitleBarContainer>
|
{isLoading ? (
|
||||||
|
<div className="DebugLogWindow__container">
|
||||||
|
<Spinner svgSize="normal" />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="DebugLogWindow__scroll_area">
|
||||||
|
<pre className="DebugLogWindow__scroll_area__text">
|
||||||
|
{textAreaValue}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="DebugLogWindow__footer">
|
||||||
|
<Button
|
||||||
|
disabled={!canSave}
|
||||||
|
onClick={() => {
|
||||||
|
if (logText) {
|
||||||
|
downloadLog(logText);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
variant={ButtonVariant.Secondary}
|
||||||
|
>
|
||||||
|
{i18n('icu:debugLogSave')}
|
||||||
|
</Button>
|
||||||
|
<Button disabled={!canSubmit} onClick={handleSubmit}>
|
||||||
|
{i18n('icu:submit')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{toastElement}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,12 +127,10 @@ export const ModalHost = React.memo(function ModalHostInner({
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exemptions:
|
// Exemptions:
|
||||||
// - TitleBar should always receive clicks.
|
|
||||||
// - Quill suggestions since they are placed in the document.body
|
// - Quill suggestions since they are placed in the document.body
|
||||||
// - Calling module (and pip) are always above everything else
|
// - Calling module (and pip) are always above everything else
|
||||||
const exemptParent = target.closest(
|
const exemptParent = target.closest(
|
||||||
'.TitleBarContainer__title, ' +
|
'.module-composition-input__suggestions, ' +
|
||||||
'.module-composition-input__suggestions, ' +
|
|
||||||
'.module-composition-input__format-menu, ' +
|
'.module-composition-input__format-menu, ' +
|
||||||
'.module-calling__modal-container'
|
'.module-calling__modal-container'
|
||||||
);
|
);
|
||||||
|
|
|
@ -82,7 +82,6 @@ export default {
|
||||||
hasCallNotifications: true,
|
hasCallNotifications: true,
|
||||||
hasCallRingtoneNotification: false,
|
hasCallRingtoneNotification: false,
|
||||||
hasCountMutedConversations: false,
|
hasCountMutedConversations: false,
|
||||||
hasCustomTitleBar: true,
|
|
||||||
hasHideMenuBar: false,
|
hasHideMenuBar: false,
|
||||||
hasIncomingCallNotifications: true,
|
hasIncomingCallNotifications: true,
|
||||||
hasLinkPreviews: true,
|
hasLinkPreviews: true,
|
||||||
|
@ -131,7 +130,6 @@ export default {
|
||||||
doDeleteAllData: action('doDeleteAllData'),
|
doDeleteAllData: action('doDeleteAllData'),
|
||||||
doneRendering: action('doneRendering'),
|
doneRendering: action('doneRendering'),
|
||||||
editCustomColor: action('editCustomColor'),
|
editCustomColor: action('editCustomColor'),
|
||||||
executeMenuRole: action('executeMenuRole'),
|
|
||||||
makeSyncRequest: action('makeSyncRequest'),
|
makeSyncRequest: action('makeSyncRequest'),
|
||||||
onAudioNotificationsChange: action('onAudioNotificationsChange'),
|
onAudioNotificationsChange: action('onAudioNotificationsChange'),
|
||||||
onAutoConvertEmojiChange: action('onAutoConvertEmojiChange'),
|
onAutoConvertEmojiChange: action('onAutoConvertEmojiChange'),
|
||||||
|
|
|
@ -33,7 +33,6 @@ import type {
|
||||||
SentMediaQualityType,
|
SentMediaQualityType,
|
||||||
ThemeType,
|
ThemeType,
|
||||||
} from '../types/Util';
|
} from '../types/Util';
|
||||||
import type { ExecuteMenuRoleType } from './TitleBarContainer';
|
|
||||||
|
|
||||||
import { Button, ButtonVariant } from './Button';
|
import { Button, ButtonVariant } from './Button';
|
||||||
import { ChatColorPicker } from './ChatColorPicker';
|
import { ChatColorPicker } from './ChatColorPicker';
|
||||||
|
@ -48,7 +47,6 @@ import { PhoneNumberDiscoverability } from '../util/phoneNumberDiscoverability';
|
||||||
import { PhoneNumberSharingMode } from '../util/phoneNumberSharingMode';
|
import { PhoneNumberSharingMode } from '../util/phoneNumberSharingMode';
|
||||||
import { Select } from './Select';
|
import { Select } from './Select';
|
||||||
import { Spinner } from './Spinner';
|
import { Spinner } from './Spinner';
|
||||||
import { TitleBarContainer } from './TitleBarContainer';
|
|
||||||
import { getCustomColorStyle } from '../util/getCustomColorStyle';
|
import { getCustomColorStyle } from '../util/getCustomColorStyle';
|
||||||
import {
|
import {
|
||||||
DEFAULT_DURATIONS_IN_SECONDS,
|
DEFAULT_DURATIONS_IN_SECONDS,
|
||||||
|
@ -58,7 +56,6 @@ import {
|
||||||
import { DurationInSeconds } from '../util/durations';
|
import { DurationInSeconds } from '../util/durations';
|
||||||
import { useEscapeHandling } from '../hooks/useEscapeHandling';
|
import { useEscapeHandling } from '../hooks/useEscapeHandling';
|
||||||
import { useUniqueId } from '../hooks/useUniqueId';
|
import { useUniqueId } from '../hooks/useUniqueId';
|
||||||
import { useTheme } from '../hooks/useTheme';
|
|
||||||
import { focusableSelectors } from '../util/focusableSelectors';
|
import { focusableSelectors } from '../util/focusableSelectors';
|
||||||
import { Modal } from './Modal';
|
import { Modal } from './Modal';
|
||||||
import { SearchInput } from './SearchInput';
|
import { SearchInput } from './SearchInput';
|
||||||
|
@ -116,7 +113,6 @@ export type PropsDataType = {
|
||||||
resolvedLocale: string;
|
resolvedLocale: string;
|
||||||
|
|
||||||
// Other props
|
// Other props
|
||||||
hasCustomTitleBar: boolean;
|
|
||||||
initialSpellCheckSetting: boolean;
|
initialSpellCheckSetting: boolean;
|
||||||
|
|
||||||
// Limited support features
|
// Limited support features
|
||||||
|
@ -141,7 +137,6 @@ type PropsFunctionType = {
|
||||||
doDeleteAllData: () => unknown;
|
doDeleteAllData: () => unknown;
|
||||||
doneRendering: () => unknown;
|
doneRendering: () => unknown;
|
||||||
editCustomColor: (colorId: string, color: CustomColorType) => unknown;
|
editCustomColor: (colorId: string, color: CustomColorType) => unknown;
|
||||||
executeMenuRole: ExecuteMenuRoleType;
|
|
||||||
getConversationsWithCustomColor: (
|
getConversationsWithCustomColor: (
|
||||||
colorId: string
|
colorId: string
|
||||||
) => Promise<Array<ConversationType>>;
|
) => Promise<Array<ConversationType>>;
|
||||||
|
@ -256,7 +251,6 @@ export function Preferences({
|
||||||
doDeleteAllData,
|
doDeleteAllData,
|
||||||
doneRendering,
|
doneRendering,
|
||||||
editCustomColor,
|
editCustomColor,
|
||||||
executeMenuRole,
|
|
||||||
getConversationsWithCustomColor,
|
getConversationsWithCustomColor,
|
||||||
hasAudioNotifications,
|
hasAudioNotifications,
|
||||||
hasAutoConvertEmoji,
|
hasAutoConvertEmoji,
|
||||||
|
@ -291,7 +285,6 @@ export function Preferences({
|
||||||
isSyncSupported,
|
isSyncSupported,
|
||||||
isSystemTraySupported,
|
isSystemTraySupported,
|
||||||
isMinimizeToAndStartInSystemTraySupported,
|
isMinimizeToAndStartInSystemTraySupported,
|
||||||
hasCustomTitleBar,
|
|
||||||
lastSyncTime,
|
lastSyncTime,
|
||||||
makeSyncRequest,
|
makeSyncRequest,
|
||||||
notificationContent,
|
notificationContent,
|
||||||
|
@ -364,7 +357,6 @@ export function Preferences({
|
||||||
string | null
|
string | null
|
||||||
>(localeOverride);
|
>(localeOverride);
|
||||||
const [languageSearchInput, setLanguageSearchInput] = useState('');
|
const [languageSearchInput, setLanguageSearchInput] = useState('');
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
function closeLanguageDialog() {
|
function closeLanguageDialog() {
|
||||||
setLanguageDialog(null);
|
setLanguageDialog(null);
|
||||||
|
@ -1502,11 +1494,7 @@ export function Preferences({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TitleBarContainer
|
<>
|
||||||
hasCustomTitleBar={hasCustomTitleBar}
|
|
||||||
theme={theme}
|
|
||||||
executeMenuRole={executeMenuRole}
|
|
||||||
>
|
|
||||||
<div className="module-title-bar-drag-area" />
|
<div className="module-title-bar-drag-area" />
|
||||||
<div className="Preferences">
|
<div className="Preferences">
|
||||||
<div className="Preferences__page-selector">
|
<div className="Preferences__page-selector">
|
||||||
|
@ -1584,7 +1572,7 @@ export function Preferences({
|
||||||
{settings}
|
{settings}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TitleBarContainer>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,274 +0,0 @@
|
||||||
// Copyright 2021 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import React, { useMemo } from 'react';
|
|
||||||
import type { ReactNode } from 'react';
|
|
||||||
import TitleBar from '@indutny/frameless-titlebar';
|
|
||||||
import type { MenuItem } from '@indutny/frameless-titlebar';
|
|
||||||
import type { MenuItemConstructorOptions } from 'electron';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
import { createTemplate } from '../../app/menu';
|
|
||||||
import { ThemeType } from '../types/Util';
|
|
||||||
import type { LocalizerType } from '../types/I18N';
|
|
||||||
import type { MenuOptionsType, MenuActionType } from '../types/menu';
|
|
||||||
import { useIsWindowActive } from '../hooks/useIsWindowActive';
|
|
||||||
|
|
||||||
export type MenuPropsType = Readonly<{
|
|
||||||
hasMenu: true;
|
|
||||||
i18n: LocalizerType;
|
|
||||||
menuOptions: MenuOptionsType;
|
|
||||||
executeMenuAction: (action: MenuActionType) => void;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type ExecuteMenuRoleType = (
|
|
||||||
role: MenuItemConstructorOptions['role']
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
export type PropsType = Readonly<{
|
|
||||||
theme: ThemeType;
|
|
||||||
isMaximized?: boolean;
|
|
||||||
isFullScreen?: boolean;
|
|
||||||
hasCustomTitleBar: boolean;
|
|
||||||
hideMenuBar?: boolean;
|
|
||||||
executeMenuRole: ExecuteMenuRoleType;
|
|
||||||
titleBarDoubleClick?: () => void;
|
|
||||||
children: ReactNode;
|
|
||||||
}> &
|
|
||||||
(MenuPropsType | { hasMenu?: false });
|
|
||||||
|
|
||||||
const TITLEBAR_HEIGHT = 28;
|
|
||||||
|
|
||||||
// Windows only
|
|
||||||
const ROLE_TO_ACCELERATOR = new Map<
|
|
||||||
MenuItemConstructorOptions['role'],
|
|
||||||
string
|
|
||||||
>();
|
|
||||||
ROLE_TO_ACCELERATOR.set('undo', 'CmdOrCtrl+Z');
|
|
||||||
ROLE_TO_ACCELERATOR.set('redo', 'CmdOrCtrl+Y');
|
|
||||||
ROLE_TO_ACCELERATOR.set('cut', 'CmdOrCtrl+X');
|
|
||||||
ROLE_TO_ACCELERATOR.set('copy', 'CmdOrCtrl+C');
|
|
||||||
ROLE_TO_ACCELERATOR.set('paste', 'CmdOrCtrl+V');
|
|
||||||
ROLE_TO_ACCELERATOR.set('pasteAndMatchStyle', 'CmdOrCtrl+Shift+V');
|
|
||||||
ROLE_TO_ACCELERATOR.set('selectAll', 'CmdOrCtrl+A');
|
|
||||||
ROLE_TO_ACCELERATOR.set('resetZoom', 'CmdOrCtrl+0');
|
|
||||||
ROLE_TO_ACCELERATOR.set('zoomIn', 'CmdOrCtrl+=');
|
|
||||||
ROLE_TO_ACCELERATOR.set('zoomOut', 'CmdOrCtrl+-');
|
|
||||||
ROLE_TO_ACCELERATOR.set('togglefullscreen', 'F11');
|
|
||||||
ROLE_TO_ACCELERATOR.set('toggleDevTools', 'CmdOrCtrl+Shift+I');
|
|
||||||
ROLE_TO_ACCELERATOR.set('minimize', 'CmdOrCtrl+M');
|
|
||||||
|
|
||||||
function convertMenu(
|
|
||||||
menuList: ReadonlyArray<MenuItemConstructorOptions>,
|
|
||||||
executeMenuRole: (role: MenuItemConstructorOptions['role']) => void,
|
|
||||||
i18n: LocalizerType
|
|
||||||
): Array<MenuItem> {
|
|
||||||
return menuList.map(item => {
|
|
||||||
const {
|
|
||||||
type,
|
|
||||||
label,
|
|
||||||
accelerator: originalAccelerator,
|
|
||||||
click: originalClick,
|
|
||||||
submenu: originalSubmenu,
|
|
||||||
role,
|
|
||||||
} = item;
|
|
||||||
let submenu: Array<MenuItem> | undefined;
|
|
||||||
|
|
||||||
if (Array.isArray(originalSubmenu)) {
|
|
||||||
submenu = convertMenu(originalSubmenu, executeMenuRole, i18n);
|
|
||||||
} else if (originalSubmenu) {
|
|
||||||
throw new Error('Non-array submenu is not supported');
|
|
||||||
}
|
|
||||||
|
|
||||||
let click: (() => unknown) | undefined;
|
|
||||||
if (originalClick) {
|
|
||||||
if (role) {
|
|
||||||
throw new Error(`Menu item: ${label} has both click and role`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't use arguments in app/menu.ts
|
|
||||||
click = originalClick as () => unknown;
|
|
||||||
} else if (role) {
|
|
||||||
click = () => executeMenuRole(role);
|
|
||||||
}
|
|
||||||
|
|
||||||
let accelerator: string | undefined;
|
|
||||||
if (originalAccelerator) {
|
|
||||||
accelerator = originalAccelerator.toString();
|
|
||||||
} else if (role) {
|
|
||||||
accelerator = ROLE_TO_ACCELERATOR.get(role);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Custom titlebar is visible only on Windows and this string is used only
|
|
||||||
// in UI. Actual accelerator interception is handled by Electron through
|
|
||||||
// `app/main.ts`.
|
|
||||||
accelerator = accelerator?.replace(
|
|
||||||
/CommandOrControl|CmdOrCtrl/g,
|
|
||||||
i18n('icu:Keyboard--Key--ctrl')
|
|
||||||
);
|
|
||||||
accelerator = accelerator?.replace(
|
|
||||||
/Shift/g,
|
|
||||||
i18n('icu:Keyboard--Key--shift')
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
type,
|
|
||||||
label,
|
|
||||||
accelerator,
|
|
||||||
click,
|
|
||||||
submenu,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function TitleBarContainer(props: PropsType): JSX.Element {
|
|
||||||
const {
|
|
||||||
theme,
|
|
||||||
isMaximized,
|
|
||||||
isFullScreen,
|
|
||||||
hasCustomTitleBar,
|
|
||||||
hideMenuBar,
|
|
||||||
executeMenuRole,
|
|
||||||
titleBarDoubleClick,
|
|
||||||
children,
|
|
||||||
hasMenu,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const isWindowActive = useIsWindowActive();
|
|
||||||
|
|
||||||
const titleBarTheme = useMemo(
|
|
||||||
() => ({
|
|
||||||
bar: {
|
|
||||||
// See stylesheets/_global.scss
|
|
||||||
height: TITLEBAR_HEIGHT,
|
|
||||||
palette:
|
|
||||||
theme === ThemeType.light ? ('light' as const) : ('dark' as const),
|
|
||||||
...(theme === ThemeType.dark
|
|
||||||
? {
|
|
||||||
// $color-gray-05
|
|
||||||
color: '#e9e9e9',
|
|
||||||
// $color-gray-80
|
|
||||||
background: '#2e2e2e',
|
|
||||||
// $color-gray-95
|
|
||||||
borderBottom: '1px solid #121212',
|
|
||||||
//
|
|
||||||
button: {
|
|
||||||
active: {
|
|
||||||
// $color-gray-05
|
|
||||||
color: '#e9e9e9',
|
|
||||||
// $color-gray-75
|
|
||||||
background: '#3b3b3b',
|
|
||||||
},
|
|
||||||
hover: {
|
|
||||||
// $color-gray-05
|
|
||||||
color: '#e9e9e9',
|
|
||||||
// $color-gray-75
|
|
||||||
background: '#3b3b3b',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
},
|
|
||||||
|
|
||||||
// Hide overlay
|
|
||||||
menu: {
|
|
||||||
overlay: {
|
|
||||||
opacity: 0,
|
|
||||||
},
|
|
||||||
autoHide: hideMenuBar,
|
|
||||||
|
|
||||||
...(theme === ThemeType.dark
|
|
||||||
? {
|
|
||||||
separator: {
|
|
||||||
// $color-gray-95
|
|
||||||
color: '#5e5e5e',
|
|
||||||
},
|
|
||||||
accelerator: {
|
|
||||||
// $color-gray-25
|
|
||||||
color: '#b9b9b9',
|
|
||||||
},
|
|
||||||
list: {
|
|
||||||
// $color-gray-75
|
|
||||||
background: '#3b3b3b',
|
|
||||||
boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.12)',
|
|
||||||
borderRadius: '0px 0px 6px 6px',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
list: {
|
|
||||||
boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.12)',
|
|
||||||
borderRadius: '0px 0px 6px 6px',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
|
|
||||||
// Zoom support
|
|
||||||
enableOverflow: false,
|
|
||||||
scalingFunction(value: string) {
|
|
||||||
return `calc(${value} * var(--zoom-factor))`;
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
[theme, hideMenuBar]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!hasCustomTitleBar) {
|
|
||||||
return <>{children}</>;
|
|
||||||
}
|
|
||||||
|
|
||||||
let maybeMenu: Array<MenuItem> | undefined;
|
|
||||||
if (hasMenu) {
|
|
||||||
const { i18n, menuOptions, executeMenuAction } = props;
|
|
||||||
|
|
||||||
const menuTemplate = createTemplate(
|
|
||||||
{
|
|
||||||
...menuOptions,
|
|
||||||
|
|
||||||
// actions
|
|
||||||
forceUpdate: () => executeMenuAction('forceUpdate'),
|
|
||||||
openArtCreator: () => executeMenuAction('openArtCreator'),
|
|
||||||
openContactUs: () => executeMenuAction('openContactUs'),
|
|
||||||
openForums: () => executeMenuAction('openForums'),
|
|
||||||
openJoinTheBeta: () => executeMenuAction('openJoinTheBeta'),
|
|
||||||
openReleaseNotes: () => executeMenuAction('openReleaseNotes'),
|
|
||||||
openSupportPage: () => executeMenuAction('openSupportPage'),
|
|
||||||
setupAsNewDevice: () => executeMenuAction('setupAsNewDevice'),
|
|
||||||
setupAsStandalone: () => executeMenuAction('setupAsStandalone'),
|
|
||||||
showAbout: () => executeMenuAction('showAbout'),
|
|
||||||
showDebugLog: () => executeMenuAction('showDebugLog'),
|
|
||||||
showKeyboardShortcuts: () => executeMenuAction('showKeyboardShortcuts'),
|
|
||||||
showSettings: () => executeMenuAction('showSettings'),
|
|
||||||
showWindow: () => executeMenuAction('showWindow'),
|
|
||||||
zoomIn: () => executeMenuAction('zoomIn'),
|
|
||||||
zoomOut: () => executeMenuAction('zoomOut'),
|
|
||||||
zoomReset: () => executeMenuAction('zoomReset'),
|
|
||||||
},
|
|
||||||
i18n
|
|
||||||
);
|
|
||||||
|
|
||||||
maybeMenu = convertMenu(menuTemplate, executeMenuRole, i18n);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
'TitleBarContainer',
|
|
||||||
isWindowActive ? 'TitleBarContainer--active' : null,
|
|
||||||
isFullScreen ? 'TitleBarContainer--fullscreen' : null
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="TitleBarContainer__padding" />
|
|
||||||
<div className="TitleBarContainer__content">{children}</div>
|
|
||||||
|
|
||||||
<TitleBar
|
|
||||||
className="TitleBarContainer__title"
|
|
||||||
platform="win32"
|
|
||||||
iconSrc="images/titlebar_icon.svg"
|
|
||||||
theme={titleBarTheme}
|
|
||||||
maximized={isMaximized}
|
|
||||||
menu={maybeMenu}
|
|
||||||
onDoubleClick={titleBarDoubleClick}
|
|
||||||
hideControls
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -3,9 +3,7 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import type { MenuItemConstructorOptions } from 'electron';
|
|
||||||
|
|
||||||
import type { MenuActionType } from '../../types/menu';
|
|
||||||
import type { VerificationTransport } from '../../types/VerificationTransport';
|
import type { VerificationTransport } from '../../types/VerificationTransport';
|
||||||
import { App } from '../../components/App';
|
import { App } from '../../components/App';
|
||||||
import OS from '../../util/os/osMain';
|
import OS from '../../util/os/osMain';
|
||||||
|
@ -44,7 +42,6 @@ const mapStateToProps = (state: StateType) => {
|
||||||
isMaximized: getIsMainWindowMaximized(state),
|
isMaximized: getIsMainWindowMaximized(state),
|
||||||
isFullScreen: getIsMainWindowFullScreen(state),
|
isFullScreen: getIsMainWindowFullScreen(state),
|
||||||
menuOptions: getMenuOptions(state),
|
menuOptions: getMenuOptions(state),
|
||||||
hasCustomTitleBar: window.SignalContext.OS.hasCustomTitleBar(),
|
|
||||||
OS: OS.getName(),
|
OS: OS.getName(),
|
||||||
osClassName: OS.getClassName(),
|
osClassName: OS.getClassName(),
|
||||||
hideMenuBar: getHideMenuBar(state),
|
hideMenuBar: getHideMenuBar(state),
|
||||||
|
@ -83,15 +80,6 @@ const mapStateToProps = (state: StateType) => {
|
||||||
},
|
},
|
||||||
theme: getTheme(state),
|
theme: getTheme(state),
|
||||||
|
|
||||||
executeMenuRole: (role: MenuItemConstructorOptions['role']): void => {
|
|
||||||
void window.SignalContext.executeMenuRole(role);
|
|
||||||
},
|
|
||||||
executeMenuAction: (action: MenuActionType): void => {
|
|
||||||
void window.SignalContext.executeMenuAction(action);
|
|
||||||
},
|
|
||||||
titleBarDoubleClick: (): void => {
|
|
||||||
window.IPC.titleBarDoubleClick();
|
|
||||||
},
|
|
||||||
toast: state.toast.toast,
|
toast: state.toast.toast,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -97,160 +97,6 @@
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2023-10-03T18:55:06.301Z"
|
"updated": "2023-10-03T18:55:06.301Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"rule": "React-createRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.es.js",
|
|
||||||
"line": " .map(() => createRef());",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.es.js",
|
|
||||||
"line": " const ref = useRef(null);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.es.js",
|
|
||||||
"line": " const ref = useRef();",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.es.js",
|
|
||||||
"line": " const activeMenus = useRef((_a = menu === null || menu === void 0 ? void 0 : menu.length) !== null && _a !== void 0 ? _a : 0);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.es.js",
|
|
||||||
"line": " const savedCallback = useRef(onClickAway);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.es.js",
|
|
||||||
"line": " const menuRef = useRef(null);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.es.js",
|
|
||||||
"line": " const scrollRef = useRef(null);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.es.js",
|
|
||||||
"line": " myRef = myRef !== null && myRef !== void 0 ? myRef : useRef(null);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.es.js",
|
|
||||||
"line": " const overflowRef = useRef(null);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.es.js",
|
|
||||||
"line": " const menuBar = useRef(null);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.es.js",
|
|
||||||
"line": " const ref = useRef(null);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-createRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.js",
|
|
||||||
"line": " .map(() => React.createRef());",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.js",
|
|
||||||
"line": " const ref = React.useRef(null);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.js",
|
|
||||||
"line": " const ref = React.useRef();",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.js",
|
|
||||||
"line": " const activeMenus = React.useRef((_a = menu === null || menu === void 0 ? void 0 : menu.length) !== null && _a !== void 0 ? _a : 0);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.js",
|
|
||||||
"line": " const savedCallback = React.useRef(onClickAway);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.js",
|
|
||||||
"line": " const menuRef = React.useRef(null);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.js",
|
|
||||||
"line": " const scrollRef = React.useRef(null);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.js",
|
|
||||||
"line": " myRef = myRef !== null && myRef !== void 0 ? myRef : React.useRef(null);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.js",
|
|
||||||
"line": " const overflowRef = React.useRef(null);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.js",
|
|
||||||
"line": " const menuBar = React.useRef(null);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "node_modules/@indutny/frameless-titlebar/dist/index.js",
|
|
||||||
"line": " const ref = React.useRef(null);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2022-06-06T22:58:37.359Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"rule": "DOM-innerHTML",
|
"rule": "DOM-innerHTML",
|
||||||
"path": "node_modules/@ndelangen/get-tarball/dist/index.js",
|
"path": "node_modules/@ndelangen/get-tarball/dist/index.js",
|
||||||
|
|
|
@ -22,7 +22,6 @@ function createIsPlatform(
|
||||||
export type OSType = {
|
export type OSType = {
|
||||||
getClassName: () => string;
|
getClassName: () => string;
|
||||||
getName: () => string;
|
getName: () => string;
|
||||||
hasCustomTitleBar: () => boolean;
|
|
||||||
isLinux: (minVersion?: string) => boolean;
|
isLinux: (minVersion?: string) => boolean;
|
||||||
isMacOS: (minVersion?: string) => boolean;
|
isMacOS: (minVersion?: string) => boolean;
|
||||||
isWindows: (minVersion?: string) => boolean;
|
isWindows: (minVersion?: string) => boolean;
|
||||||
|
@ -33,10 +32,6 @@ export function getOSFunctions(osRelease: string): OSType {
|
||||||
const isLinux = createIsPlatform('linux', osRelease);
|
const isLinux = createIsPlatform('linux', osRelease);
|
||||||
const isWindows = createIsPlatform('win32', osRelease);
|
const isWindows = createIsPlatform('win32', osRelease);
|
||||||
|
|
||||||
// Windows 10 and above
|
|
||||||
const hasCustomTitleBar = (): boolean =>
|
|
||||||
isWindows('10.0.0') || Boolean(process.env.CUSTOM_TITLEBAR);
|
|
||||||
|
|
||||||
const getName = (): string => {
|
const getName = (): string => {
|
||||||
if (isMacOS()) {
|
if (isMacOS()) {
|
||||||
return 'macOS';
|
return 'macOS';
|
||||||
|
@ -60,7 +55,6 @@ export function getOSFunctions(osRelease: string): OSType {
|
||||||
return {
|
return {
|
||||||
getClassName,
|
getClassName,
|
||||||
getName,
|
getName,
|
||||||
hasCustomTitleBar,
|
|
||||||
isLinux,
|
isLinux,
|
||||||
isMacOS,
|
isMacOS,
|
||||||
isWindows,
|
isWindows,
|
||||||
|
|
|
@ -27,8 +27,6 @@ ReactDOM.render(
|
||||||
<About
|
<About
|
||||||
closeAbout={() => window.SignalContext.executeMenuRole('close')}
|
closeAbout={() => window.SignalContext.executeMenuRole('close')}
|
||||||
environment={environmentText}
|
environment={environmentText}
|
||||||
executeMenuRole={window.SignalContext.executeMenuRole}
|
|
||||||
hasCustomTitleBar={window.SignalContext.OS.hasCustomTitleBar()}
|
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
version={window.SignalContext.getVersion()}
|
version={window.SignalContext.getVersion()}
|
||||||
/>,
|
/>,
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { ipcRenderer } from 'electron';
|
||||||
import type { MenuItemConstructorOptions } from 'electron';
|
import type { MenuItemConstructorOptions } from 'electron';
|
||||||
import { usernames } from '@signalapp/libsignal-client';
|
import { usernames } from '@signalapp/libsignal-client';
|
||||||
|
|
||||||
import type { MenuOptionsType, MenuActionType } from '../types/menu';
|
import type { MenuOptionsType } from '../types/menu';
|
||||||
import type { IPCEventsValuesType } from '../util/createIPCEvents';
|
import type { IPCEventsValuesType } from '../util/createIPCEvents';
|
||||||
import type { LocalizerType } from '../types/Util';
|
import type { LocalizerType } from '../types/Util';
|
||||||
import type { LoggerType } from '../types/Logging';
|
import type { LoggerType } from '../types/Logging';
|
||||||
|
@ -37,7 +37,6 @@ export type MainWindowStatsType = Readonly<{
|
||||||
export type MinimalSignalContextType = {
|
export type MinimalSignalContextType = {
|
||||||
activeWindowService: ActiveWindowServiceType;
|
activeWindowService: ActiveWindowServiceType;
|
||||||
config: RendererConfigType;
|
config: RendererConfigType;
|
||||||
executeMenuAction: (action: MenuActionType) => Promise<void>;
|
|
||||||
executeMenuRole: (role: MenuItemConstructorOptions['role']) => Promise<void>;
|
executeMenuRole: (role: MenuItemConstructorOptions['role']) => Promise<void>;
|
||||||
getAppInstance: () => string | undefined;
|
getAppInstance: () => string | undefined;
|
||||||
getEnvironment: () => string;
|
getEnvironment: () => string;
|
||||||
|
@ -62,7 +61,6 @@ export type MinimalSignalContextType = {
|
||||||
waitForChange: () => Promise<void>;
|
waitForChange: () => Promise<void>;
|
||||||
};
|
};
|
||||||
OS: {
|
OS: {
|
||||||
hasCustomTitleBar: () => boolean;
|
|
||||||
getClassName: () => string;
|
getClassName: () => string;
|
||||||
platform: string;
|
platform: string;
|
||||||
release: string;
|
release: string;
|
||||||
|
|
|
@ -13,8 +13,6 @@ strictAssert(DebugLogWindowProps, 'window values not provided');
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<DebugLogWindow
|
<DebugLogWindow
|
||||||
hasCustomTitleBar={window.SignalContext.OS.hasCustomTitleBar()}
|
|
||||||
executeMenuRole={window.SignalContext.executeMenuRole}
|
|
||||||
closeWindow={() => window.SignalContext.executeMenuRole('close')}
|
closeWindow={() => window.SignalContext.executeMenuRole('close')}
|
||||||
downloadLog={DebugLogWindowProps.downloadLog}
|
downloadLog={DebugLogWindowProps.downloadLog}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
|
|
@ -2,9 +2,6 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
document.body.classList.add(window.SignalContext.OS.getClassName());
|
document.body.classList.add(window.SignalContext.OS.getClassName());
|
||||||
if (window.SignalContext.OS.hasCustomTitleBar()) {
|
|
||||||
document.body.classList.add('os-has-custom-titlebar');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window.SignalContext.renderWindow) {
|
if (window.SignalContext.renderWindow) {
|
||||||
window.SignalContext.renderWindow();
|
window.SignalContext.renderWindow();
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import type { MenuItemConstructorOptions } from 'electron';
|
import type { MenuItemConstructorOptions } from 'electron';
|
||||||
import { ipcRenderer } from 'electron';
|
import { ipcRenderer } from 'electron';
|
||||||
|
|
||||||
import type { MenuOptionsType, MenuActionType } from '../types/menu';
|
import type { MenuOptionsType } from '../types/menu';
|
||||||
import type { MainWindowStatsType, MinimalSignalContextType } from './context';
|
import type { MainWindowStatsType, MinimalSignalContextType } from './context';
|
||||||
import { activeWindowService } from '../context/activeWindowService';
|
import { activeWindowService } from '../context/activeWindowService';
|
||||||
import { config } from '../context/config';
|
import { config } from '../context/config';
|
||||||
|
@ -14,13 +14,9 @@ import { environment } from '../context/environment';
|
||||||
import { localeDisplayNames, localeMessages } from '../context/localeMessages';
|
import { localeDisplayNames, localeMessages } from '../context/localeMessages';
|
||||||
import { waitForSettingsChange } from '../context/waitForSettingsChange';
|
import { waitForSettingsChange } from '../context/waitForSettingsChange';
|
||||||
|
|
||||||
const hasCustomTitleBar = ipcRenderer.sendSync('OS.getHasCustomTitleBar');
|
|
||||||
export const MinimalSignalContext: MinimalSignalContextType = {
|
export const MinimalSignalContext: MinimalSignalContextType = {
|
||||||
activeWindowService,
|
activeWindowService,
|
||||||
config,
|
config,
|
||||||
async executeMenuAction(action: MenuActionType): Promise<void> {
|
|
||||||
return ipcRenderer.invoke('executeMenuAction', action);
|
|
||||||
},
|
|
||||||
async executeMenuRole(
|
async executeMenuRole(
|
||||||
role: MenuItemConstructorOptions['role']
|
role: MenuItemConstructorOptions['role']
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
@ -55,7 +51,6 @@ export const MinimalSignalContext: MinimalSignalContextType = {
|
||||||
restartApp: () => ipcRenderer.send('restart'),
|
restartApp: () => ipcRenderer.send('restart'),
|
||||||
OS: {
|
OS: {
|
||||||
getClassName: () => ipcRenderer.sendSync('OS.getClassName'),
|
getClassName: () => ipcRenderer.sendSync('OS.getClassName'),
|
||||||
hasCustomTitleBar: () => hasCustomTitleBar,
|
|
||||||
platform: process.platform,
|
platform: process.platform,
|
||||||
release: config.osRelease,
|
release: config.osRelease,
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,9 +5,6 @@ import './applyTheme';
|
||||||
import { setupI18n } from '../util/setupI18n';
|
import { setupI18n } from '../util/setupI18n';
|
||||||
|
|
||||||
document.body.classList.add(window.SignalContext.OS.getClassName());
|
document.body.classList.add(window.SignalContext.OS.getClassName());
|
||||||
if (window.SignalContext.OS.hasCustomTitleBar()) {
|
|
||||||
document.body.classList.add('os-has-custom-titlebar');
|
|
||||||
}
|
|
||||||
|
|
||||||
export const i18n = setupI18n(
|
export const i18n = setupI18n(
|
||||||
window.SignalContext.getI18nLocale(),
|
window.SignalContext.getI18nLocale(),
|
||||||
|
|
|
@ -31,7 +31,6 @@ SettingsWindowProps.onRender(
|
||||||
doDeleteAllData,
|
doDeleteAllData,
|
||||||
doneRendering,
|
doneRendering,
|
||||||
editCustomColor,
|
editCustomColor,
|
||||||
executeMenuRole,
|
|
||||||
getConversationsWithCustomColor,
|
getConversationsWithCustomColor,
|
||||||
hasAudioNotifications,
|
hasAudioNotifications,
|
||||||
hasAutoConvertEmoji,
|
hasAutoConvertEmoji,
|
||||||
|
@ -40,7 +39,6 @@ SettingsWindowProps.onRender(
|
||||||
hasCallNotifications,
|
hasCallNotifications,
|
||||||
hasCallRingtoneNotification,
|
hasCallRingtoneNotification,
|
||||||
hasCountMutedConversations,
|
hasCountMutedConversations,
|
||||||
hasCustomTitleBar,
|
|
||||||
hasHideMenuBar,
|
hasHideMenuBar,
|
||||||
hasIncomingCallNotifications,
|
hasIncomingCallNotifications,
|
||||||
hasLinkPreviews,
|
hasLinkPreviews,
|
||||||
|
@ -134,7 +132,6 @@ SettingsWindowProps.onRender(
|
||||||
doDeleteAllData={doDeleteAllData}
|
doDeleteAllData={doDeleteAllData}
|
||||||
doneRendering={doneRendering}
|
doneRendering={doneRendering}
|
||||||
editCustomColor={editCustomColor}
|
editCustomColor={editCustomColor}
|
||||||
executeMenuRole={executeMenuRole}
|
|
||||||
getConversationsWithCustomColor={getConversationsWithCustomColor}
|
getConversationsWithCustomColor={getConversationsWithCustomColor}
|
||||||
hasAudioNotifications={hasAudioNotifications}
|
hasAudioNotifications={hasAudioNotifications}
|
||||||
hasAutoConvertEmoji={hasAutoConvertEmoji}
|
hasAutoConvertEmoji={hasAutoConvertEmoji}
|
||||||
|
@ -143,7 +140,6 @@ SettingsWindowProps.onRender(
|
||||||
hasCallNotifications={hasCallNotifications}
|
hasCallNotifications={hasCallNotifications}
|
||||||
hasCallRingtoneNotification={hasCallRingtoneNotification}
|
hasCallRingtoneNotification={hasCallRingtoneNotification}
|
||||||
hasCountMutedConversations={hasCountMutedConversations}
|
hasCountMutedConversations={hasCountMutedConversations}
|
||||||
hasCustomTitleBar={hasCustomTitleBar}
|
|
||||||
hasHideMenuBar={hasHideMenuBar}
|
hasHideMenuBar={hasHideMenuBar}
|
||||||
hasIncomingCallNotifications={hasIncomingCallNotifications}
|
hasIncomingCallNotifications={hasIncomingCallNotifications}
|
||||||
hasLinkPreviews={hasLinkPreviews}
|
hasLinkPreviews={hasLinkPreviews}
|
||||||
|
|
|
@ -426,9 +426,6 @@ async function renderPreferences() {
|
||||||
onZoomFactorChange: (zoomFactorValue: number) => {
|
onZoomFactorChange: (zoomFactorValue: number) => {
|
||||||
ipcRenderer.send('setZoomFactor', zoomFactorValue);
|
ipcRenderer.send('setZoomFactor', zoomFactorValue);
|
||||||
},
|
},
|
||||||
|
|
||||||
hasCustomTitleBar: MinimalSignalContext.OS.hasCustomTitleBar(),
|
|
||||||
executeMenuRole: MinimalSignalContext.executeMenuRole,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
renderInBrowser(props);
|
renderInBrowser(props);
|
||||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -1893,14 +1893,6 @@
|
||||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
|
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
|
||||||
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
|
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
|
||||||
|
|
||||||
"@indutny/frameless-titlebar@2.3.5":
|
|
||||||
version "2.3.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/@indutny/frameless-titlebar/-/frameless-titlebar-2.3.5.tgz#7d4908d43a753629c7d48d97dbff56f93a4f64cd"
|
|
||||||
integrity sha512-RWKxnphS1Dvkms4E5DJcg4sjD6a0i/yuengruGM8uZJUE/2HIjlquPq9zTGvtB23If1RBNVqC3JXwoNHKKY0Kw==
|
|
||||||
dependencies:
|
|
||||||
classnames "^2.2.6"
|
|
||||||
deepmerge "^4.2.2"
|
|
||||||
|
|
||||||
"@indutny/sneequals@4.0.0":
|
"@indutny/sneequals@4.0.0":
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@indutny/sneequals/-/sneequals-4.0.0.tgz#94f74e577019759c5d12818e7c7ff1b9300653a4"
|
resolved "https://registry.yarnpkg.com/@indutny/sneequals/-/sneequals-4.0.0.tgz#94f74e577019759c5d12818e7c7ff1b9300653a4"
|
||||||
|
@ -7660,7 +7652,7 @@ classnames@2.2.5:
|
||||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
|
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
|
||||||
integrity sha1-+zgB1FNGdknvNgPH1hoCvRKb3m0=
|
integrity sha1-+zgB1FNGdknvNgPH1hoCvRKb3m0=
|
||||||
|
|
||||||
classnames@^2.2.5, classnames@^2.2.6:
|
classnames@^2.2.5:
|
||||||
version "2.3.1"
|
version "2.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
|
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
|
||||||
integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
|
integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue