Dark theme loading screen
This commit is contained in:
parent
af2c884c9f
commit
b30c7f9c46
7 changed files with 114 additions and 18 deletions
92
app/main.ts
92
app/main.ts
|
@ -19,6 +19,7 @@ import {
|
||||||
dialog,
|
dialog,
|
||||||
ipcMain as ipc,
|
ipcMain as ipc,
|
||||||
Menu,
|
Menu,
|
||||||
|
nativeTheme,
|
||||||
powerSaveBlocker,
|
powerSaveBlocker,
|
||||||
protocol as electronProtocol,
|
protocol as electronProtocol,
|
||||||
screen,
|
screen,
|
||||||
|
@ -33,8 +34,11 @@ import * as GlobalErrors from './global_errors';
|
||||||
import { setup as setupCrashReports } from './crashReports';
|
import { setup as setupCrashReports } from './crashReports';
|
||||||
import { setup as setupSpellChecker } from './spell_check';
|
import { setup as setupSpellChecker } from './spell_check';
|
||||||
import { redactAll, addSensitivePath } from '../ts/util/privacy';
|
import { redactAll, addSensitivePath } from '../ts/util/privacy';
|
||||||
|
import { missingCaseError } from '../ts/util/missingCaseError';
|
||||||
import { strictAssert } from '../ts/util/assert';
|
import { strictAssert } from '../ts/util/assert';
|
||||||
import { consoleLogger } from '../ts/util/consoleLogger';
|
import { consoleLogger } from '../ts/util/consoleLogger';
|
||||||
|
import type { ThemeSettingType } from '../ts/types/Storage.d';
|
||||||
|
import { ThemeType } from '../ts/types/Util';
|
||||||
|
|
||||||
import './startup_config';
|
import './startup_config';
|
||||||
|
|
||||||
|
@ -230,6 +234,61 @@ async function getSpellCheckSetting() {
|
||||||
return slowValue;
|
return slowValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GetThemeSettingOptionsType = Readonly<{
|
||||||
|
ephemeralOnly?: boolean;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
async function getThemeSetting({
|
||||||
|
ephemeralOnly = false,
|
||||||
|
}: GetThemeSettingOptionsType = {}): Promise<ThemeSettingType> {
|
||||||
|
const fastValue = ephemeralConfig.get('theme-setting');
|
||||||
|
if (fastValue !== undefined) {
|
||||||
|
getLogger().info('got fast theme-setting value', fastValue);
|
||||||
|
return fastValue as ThemeSettingType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ephemeralOnly) {
|
||||||
|
return 'system';
|
||||||
|
}
|
||||||
|
|
||||||
|
const json = await sql.sqlCall('getItemById', ['theme-setting']);
|
||||||
|
|
||||||
|
// Default to `system` if setting doesn't exist yet
|
||||||
|
const slowValue = json ? json.value : 'system';
|
||||||
|
|
||||||
|
ephemeralConfig.set('theme-setting', slowValue);
|
||||||
|
|
||||||
|
getLogger().info('got slow theme-setting value', slowValue);
|
||||||
|
|
||||||
|
return slowValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getResolvedThemeSetting(
|
||||||
|
options?: GetThemeSettingOptionsType
|
||||||
|
): Promise<ThemeType> {
|
||||||
|
const theme = await getThemeSetting(options);
|
||||||
|
if (theme === 'system') {
|
||||||
|
return nativeTheme.shouldUseDarkColors ? ThemeType.dark : ThemeType.light;
|
||||||
|
}
|
||||||
|
return ThemeType[theme];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getBackgroundColor(
|
||||||
|
options?: GetThemeSettingOptionsType
|
||||||
|
): Promise<string> {
|
||||||
|
const theme = await getResolvedThemeSetting(options);
|
||||||
|
|
||||||
|
if (theme === 'light') {
|
||||||
|
return '#3a76f0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theme === 'dark') {
|
||||||
|
return '#121212';
|
||||||
|
}
|
||||||
|
|
||||||
|
throw missingCaseError(theme);
|
||||||
|
}
|
||||||
|
|
||||||
let systemTrayService: SystemTrayService | undefined;
|
let systemTrayService: SystemTrayService | undefined;
|
||||||
const systemTraySettingCache = new SystemTraySettingCache(
|
const systemTraySettingCache = new SystemTraySettingCache(
|
||||||
sql,
|
sql,
|
||||||
|
@ -479,7 +538,7 @@ async function createWindow() {
|
||||||
: 'default',
|
: 'default',
|
||||||
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
|
||||||
: '#3a76f0',
|
: await getBackgroundColor(),
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
...defaultWebPrefs,
|
...defaultWebPrefs,
|
||||||
nodeIntegration: false,
|
nodeIntegration: false,
|
||||||
|
@ -599,6 +658,7 @@ async function createWindow() {
|
||||||
|
|
||||||
const moreKeys = {
|
const moreKeys = {
|
||||||
isFullScreen: String(Boolean(mainWindow.isFullScreen())),
|
isFullScreen: String(Boolean(mainWindow.isFullScreen())),
|
||||||
|
resolvedTheme: await getResolvedThemeSetting(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (getEnvironment() === Environment.Test) {
|
if (getEnvironment() === Environment.Test) {
|
||||||
|
@ -996,7 +1056,7 @@ function showScreenShareWindow(sourceName: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let aboutWindow: BrowserWindow | undefined;
|
let aboutWindow: BrowserWindow | undefined;
|
||||||
function showAbout() {
|
async function showAbout() {
|
||||||
if (aboutWindow) {
|
if (aboutWindow) {
|
||||||
aboutWindow.show();
|
aboutWindow.show();
|
||||||
return;
|
return;
|
||||||
|
@ -1008,7 +1068,7 @@ function showAbout() {
|
||||||
resizable: false,
|
resizable: false,
|
||||||
title: getLocale().i18n('aboutSignalDesktop'),
|
title: getLocale().i18n('aboutSignalDesktop'),
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
backgroundColor: '#3a76f0',
|
backgroundColor: await getBackgroundColor(),
|
||||||
show: false,
|
show: false,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
...defaultWebPrefs,
|
...defaultWebPrefs,
|
||||||
|
@ -1038,7 +1098,7 @@ function showAbout() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let settingsWindow: BrowserWindow | undefined;
|
let settingsWindow: BrowserWindow | undefined;
|
||||||
function showSettingsWindow() {
|
async function showSettingsWindow() {
|
||||||
if (settingsWindow) {
|
if (settingsWindow) {
|
||||||
settingsWindow.show();
|
settingsWindow.show();
|
||||||
return;
|
return;
|
||||||
|
@ -1051,7 +1111,7 @@ function showSettingsWindow() {
|
||||||
resizable: false,
|
resizable: false,
|
||||||
title: getLocale().i18n('signalDesktopPreferences'),
|
title: getLocale().i18n('signalDesktopPreferences'),
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
backgroundColor: '#3a76f0',
|
backgroundColor: await getBackgroundColor(),
|
||||||
show: false,
|
show: false,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
...defaultWebPrefs,
|
...defaultWebPrefs,
|
||||||
|
@ -1121,7 +1181,7 @@ async function showStickerCreator() {
|
||||||
height: 650,
|
height: 650,
|
||||||
title: getLocale().i18n('signalDesktopStickerCreator'),
|
title: getLocale().i18n('signalDesktopStickerCreator'),
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
backgroundColor: '#3a76f0',
|
backgroundColor: await getBackgroundColor(),
|
||||||
show: false,
|
show: false,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
...defaultWebPrefs,
|
...defaultWebPrefs,
|
||||||
|
@ -1172,16 +1232,14 @@ async function showDebugLogWindow() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const theme = settingsChannel
|
const theme = await getThemeSetting();
|
||||||
? await settingsChannel.getSettingFromMainWindow('themeSetting')
|
|
||||||
: undefined;
|
|
||||||
const options = {
|
const options = {
|
||||||
width: 700,
|
width: 700,
|
||||||
height: 500,
|
height: 500,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
title: getLocale().i18n('debugLog'),
|
title: getLocale().i18n('debugLog'),
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
backgroundColor: '#3a76f0',
|
backgroundColor: await getBackgroundColor(),
|
||||||
show: false,
|
show: false,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
...defaultWebPrefs,
|
...defaultWebPrefs,
|
||||||
|
@ -1235,9 +1293,7 @@ function showPermissionsPopupWindow(forCalling: boolean, forCamera: boolean) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const theme = settingsChannel
|
const theme = await getThemeSetting();
|
||||||
? await settingsChannel.getSettingFromMainWindow('themeSetting')
|
|
||||||
: undefined;
|
|
||||||
const size = mainWindow.getSize();
|
const size = mainWindow.getSize();
|
||||||
const options = {
|
const options = {
|
||||||
width: Math.min(400, size[0]),
|
width: Math.min(400, size[0]),
|
||||||
|
@ -1245,7 +1301,7 @@ function showPermissionsPopupWindow(forCalling: boolean, forCamera: boolean) {
|
||||||
resizable: false,
|
resizable: false,
|
||||||
title: getLocale().i18n('allowAccess'),
|
title: getLocale().i18n('allowAccess'),
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
backgroundColor: '#3a76f0',
|
backgroundColor: await getBackgroundColor(),
|
||||||
show: false,
|
show: false,
|
||||||
modal: true,
|
modal: true,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
|
@ -1509,6 +1565,12 @@ app.on('ready', async () => {
|
||||||
const timeout = new Promise(resolveFn =>
|
const timeout = new Promise(resolveFn =>
|
||||||
setTimeout(resolveFn, 3000, 'timeout')
|
setTimeout(resolveFn, 3000, 'timeout')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// This color is to be used only in loading screen and in this case we should
|
||||||
|
// never wait for the database to be initialized. Thus the theme setting
|
||||||
|
// lookup should be done only in ephemeral config.
|
||||||
|
const backgroundColor = await getBackgroundColor({ ephemeralOnly: true });
|
||||||
|
|
||||||
// eslint-disable-next-line more/no-then
|
// eslint-disable-next-line more/no-then
|
||||||
Promise.race([sqlInitPromise, timeout]).then(maybeTimeout => {
|
Promise.race([sqlInitPromise, timeout]).then(maybeTimeout => {
|
||||||
if (maybeTimeout !== 'timeout') {
|
if (maybeTimeout !== 'timeout') {
|
||||||
|
@ -1525,7 +1587,7 @@ app.on('ready', async () => {
|
||||||
height: 265,
|
height: 265,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
frame: false,
|
frame: false,
|
||||||
backgroundColor: '#3a76f0',
|
backgroundColor,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
...defaultWebPrefs,
|
...defaultWebPrefs,
|
||||||
nodeIntegration: false,
|
nodeIntegration: false,
|
||||||
|
|
|
@ -15,6 +15,7 @@ try {
|
||||||
const { strictAssert } = require('./ts/util/assert');
|
const { strictAssert } = require('./ts/util/assert');
|
||||||
const { parseIntWithFallback } = require('./ts/util/parseIntWithFallback');
|
const { parseIntWithFallback } = require('./ts/util/parseIntWithFallback');
|
||||||
const { UUIDKind } = require('./ts/types/UUID');
|
const { UUIDKind } = require('./ts/types/UUID');
|
||||||
|
const { ThemeType } = require('./ts/types/Util');
|
||||||
|
|
||||||
// It is important to call this as early as possible
|
// It is important to call this as early as possible
|
||||||
const { SignalContext } = require('./ts/windows/context');
|
const { SignalContext } = require('./ts/windows/context');
|
||||||
|
@ -247,6 +248,12 @@ try {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.resolvedTheme === 'light') {
|
||||||
|
window.initialTheme = ThemeType.light;
|
||||||
|
} else if (config.resolvedTheme === 'dark') {
|
||||||
|
window.initialTheme = ThemeType.dark;
|
||||||
|
}
|
||||||
|
|
||||||
// Settings-related events
|
// Settings-related events
|
||||||
|
|
||||||
window.showSettings = () => ipc.send('show-settings');
|
window.showSettings = () => ipc.send('show-settings');
|
||||||
|
|
|
@ -235,7 +235,16 @@ $loading-height: 16px;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background-color: $color-ultramarine-icon;
|
|
||||||
|
/* Note: background-color is intentionally transparent until body has the
|
||||||
|
* theme class.
|
||||||
|
*/
|
||||||
|
@include explicit-light-theme {
|
||||||
|
background-color: $color-ultramarine-icon;
|
||||||
|
}
|
||||||
|
@include dark-theme {
|
||||||
|
background-color: $color-gray-95;
|
||||||
|
}
|
||||||
color: $color-white;
|
color: $color-white;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
@ -97,6 +97,12 @@
|
||||||
@content;
|
@content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin explicit-light-theme() {
|
||||||
|
.light-theme & {
|
||||||
|
@content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@mixin dark-theme() {
|
@mixin dark-theme() {
|
||||||
.dark-theme & {
|
.dark-theme & {
|
||||||
@content;
|
@content;
|
||||||
|
|
|
@ -29,6 +29,7 @@ import type { Receipt } from './types/Receipt';
|
||||||
import { getTitleBarVisibility, TitleBarVisibility } from './types/Settings';
|
import { getTitleBarVisibility, TitleBarVisibility } from './types/Settings';
|
||||||
import { SocketStatus } from './types/SocketStatus';
|
import { SocketStatus } from './types/SocketStatus';
|
||||||
import { DEFAULT_CONVERSATION_COLOR } from './types/Colors';
|
import { DEFAULT_CONVERSATION_COLOR } from './types/Colors';
|
||||||
|
import { ThemeType } from './types/Util';
|
||||||
import { ChallengeHandler } from './challenge';
|
import { ChallengeHandler } from './challenge';
|
||||||
import * as durations from './util/durations';
|
import * as durations from './util/durations';
|
||||||
import { explodePromise } from './util/explodePromise';
|
import { explodePromise } from './util/explodePromise';
|
||||||
|
@ -166,6 +167,13 @@ export async function cleanupSessionResets(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function startApp(): Promise<void> {
|
export async function startApp(): Promise<void> {
|
||||||
|
if (window.initialTheme === ThemeType.light) {
|
||||||
|
document.body.classList.add('light-theme');
|
||||||
|
}
|
||||||
|
if (window.initialTheme === ThemeType.dark) {
|
||||||
|
document.body.classList.add('dark-theme');
|
||||||
|
}
|
||||||
|
|
||||||
const idleDetector = new IdleDetector();
|
const idleDetector = new IdleDetector();
|
||||||
|
|
||||||
await KeyboardLayout.initialize();
|
await KeyboardLayout.initialize();
|
||||||
|
|
|
@ -17,6 +17,7 @@ import type {
|
||||||
const EPHEMERAL_NAME_MAP = new Map([
|
const EPHEMERAL_NAME_MAP = new Map([
|
||||||
['spellCheck', 'spell-check'],
|
['spellCheck', 'spell-check'],
|
||||||
['systemTraySetting', 'system-tray-setting'],
|
['systemTraySetting', 'system-tray-setting'],
|
||||||
|
['themeSetting', 'theme-setting'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
type ResponseQueueEntry = Readonly<{
|
type ResponseQueueEntry = Readonly<{
|
||||||
|
@ -68,7 +69,9 @@ export class SettingsChannel {
|
||||||
this.installSetting('readReceiptSetting', { setter: false });
|
this.installSetting('readReceiptSetting', { setter: false });
|
||||||
this.installSetting('typingIndicatorSetting', { setter: false });
|
this.installSetting('typingIndicatorSetting', { setter: false });
|
||||||
|
|
||||||
this.installSetting('themeSetting');
|
this.installSetting('themeSetting', {
|
||||||
|
isEphemeral: true,
|
||||||
|
});
|
||||||
this.installSetting('hideMenuBar');
|
this.installSetting('hideMenuBar');
|
||||||
this.installSetting('systemTraySetting', {
|
this.installSetting('systemTraySetting', {
|
||||||
isEphemeral: true,
|
isEphemeral: true,
|
||||||
|
|
3
ts/window.d.ts
vendored
3
ts/window.d.ts
vendored
|
@ -29,7 +29,7 @@ import * as Curve from './Curve';
|
||||||
import * as RemoteConfig from './RemoteConfig';
|
import * as RemoteConfig from './RemoteConfig';
|
||||||
import * as OS from './OS';
|
import * as OS from './OS';
|
||||||
import { getEnvironment } from './environment';
|
import { getEnvironment } from './environment';
|
||||||
import { LocalizerType } from './types/Util';
|
import { LocalizerType, ThemeType } from './types/Util';
|
||||||
import type { Receipt } from './types/Receipt';
|
import type { Receipt } from './types/Receipt';
|
||||||
import { ConversationController } from './ConversationController';
|
import { ConversationController } from './ConversationController';
|
||||||
import { ReduxActions } from './state/types';
|
import { ReduxActions } from './state/types';
|
||||||
|
@ -212,6 +212,7 @@ declare global {
|
||||||
isAfterVersion: (version: string, anotherVersion: string) => boolean;
|
isAfterVersion: (version: string, anotherVersion: string) => boolean;
|
||||||
isBeforeVersion: (version: string, anotherVersion: string) => boolean;
|
isBeforeVersion: (version: string, anotherVersion: string) => boolean;
|
||||||
isFullScreen: () => boolean;
|
isFullScreen: () => boolean;
|
||||||
|
initialTheme?: ThemeType;
|
||||||
libphonenumber: {
|
libphonenumber: {
|
||||||
util: {
|
util: {
|
||||||
getRegionCodeForNumber: (number: string) => string;
|
getRegionCodeForNumber: (number: string) => string;
|
||||||
|
|
Loading…
Reference in a new issue