Skip to content

Commit

Permalink
Minimize and start Signal in tray
Browse files Browse the repository at this point in the history
  • Loading branch information
indutny-signal committed Sep 6, 2022
1 parent aa86d8b commit b54c6f2
Show file tree
Hide file tree
Showing 13 changed files with 152 additions and 127 deletions.
8 changes: 8 additions & 0 deletions _locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3067,6 +3067,14 @@
"message": "Unanswered video call",
"description": "Shown in conversation history when your video call is missed or declined"
},
"minimizeToTrayNotification--title": {
"message": "Signal is still running",
"description": "Shown in a notification title when Signal is minimized to tray"
},
"minimizeToTrayNotification--body": {
"message": "Signal will keep running in the notification area. You can change this in Signal settings.",
"description": "Shown in a notification body when Signal is minimized to tray"
},
"incomingAudioCall": {
"message": "Incoming audio call...",
"description": "Shown in both the incoming call bar and notification for an incoming audio call"
Expand Down
2 changes: 1 addition & 1 deletion app/SystemTraySettingCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export class SystemTraySettingCache {
result = parseSystemTraySetting(value);
log.info(`getSystemTraySetting returning ${result}`);
} else {
result = SystemTraySetting.DoNotUseSystemTray;
result = SystemTraySetting.Uninitialized;
log.info(`getSystemTraySetting got no value, returning ${result}`);
}

Expand Down
111 changes: 107 additions & 4 deletions app/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ import {
session,
shell,
systemPreferences,
Notification,
} from 'electron';
import type {
MenuItemConstructorOptions,
TitleBarOverlayOptions,
LoginItemSettingsOptions,
} from 'electron';
import { z } from 'zod';

Expand Down Expand Up @@ -82,6 +84,7 @@ import {
shouldMinimizeToSystemTray,
parseSystemTraySetting,
} from '../ts/types/SystemTraySetting';
import { isSystemTraySupported } from '../ts/types/Settings';
import * as ephemeralConfig from './ephemeral_config';
import * as logging from '../ts/logging/main_process_logging';
import { MainSQL } from '../ts/sql/main';
Expand Down Expand Up @@ -856,6 +859,23 @@ async function createWindow() {
await systemTraySettingCache.get()
);
if (!windowState.shouldQuit() && (usingTrayIcon || OS.isMacOS())) {
if (usingTrayIcon) {
const shownTrayNotice = ephemeralConfig.get('shown-tray-notice');
if (shownTrayNotice) {
getLogger().info('close: not showing tray notice');
return;
}

ephemeralConfig.set('shown-tray-notice', true);
getLogger().info('close: showing tray notice');

const n = new Notification({
title: getLocale().i18n('minimizeToTrayNotification--title'),
body: getLocale().i18n('minimizeToTrayNotification--body'),
});

n.show();
}
return;
}

Expand All @@ -867,6 +887,22 @@ async function createWindow() {
app.quit();
});

mainWindow.on('minimize', async () => {
if (!mainWindow) {
getLogger().info('minimize event: no main window');
return;
}

// When tray icon is in use - close the window since it will be minimized
// to tray anyway.
const usingTrayIcon = shouldMinimizeToSystemTray(
await systemTraySettingCache.get()
);
if (usingTrayIcon) {
mainWindow.close();
}
});

// Emitted when the window is closed.
mainWindow.on('closed', () => {
// Dereference the window object, usually you would store windows
Expand Down Expand Up @@ -1566,6 +1602,26 @@ function getAppLocale(): string {
return getEnvironment() === Environment.Test ? 'en' : app.getLocale();
}

async function getDefaultLoginItemSettings(): Promise<LoginItemSettingsOptions> {
if (!OS.isWindows()) {
return {};
}

const systemTraySetting = await systemTraySettingCache.get();
if (
systemTraySetting !== SystemTraySetting.MinimizeToSystemTray &&
// This is true when we just started with `--start-in-tray`
systemTraySetting !== SystemTraySetting.MinimizeToAndStartInSystemTray
) {
return {};
}

// The effect of this is that if both auto-launch and minimize to system tray
// are enabled on Windows - we will start the app in tray automatically,
// letting the Desktop shortcuts still start the Signal not in tray.
return { args: ['--start-in-tray'] };
}

// Signal doesn't really use media keys so we set this switch here to unblock
// them so that other apps can use them if they need to.
app.commandLine.appendSwitch('disable-features', 'HardwareMediaKeyHandling');
Expand Down Expand Up @@ -1596,6 +1652,36 @@ app.on('ready', async () => {

sqlInitPromise = initializeSQL(userDataPath);

// First run: configure Signal to minimize to tray. Additionally, on Windows
// enable auto-start with start-in-tray so that starting from a Desktop icon
// would still show the window.
// (User can change these settings later)
if (
isSystemTraySupported(app.getVersion()) &&
(await systemTraySettingCache.get()) === SystemTraySetting.Uninitialized
) {
const newValue = SystemTraySetting.MinimizeToSystemTray;
getLogger().info(`app.ready: setting system-tray-setting to ${newValue}`);
systemTraySettingCache.set(newValue);

// Update both stores
ephemeralConfig.set('system-tray-setting', newValue);
await sql.sqlCall('createOrUpdateItem', [
{
id: 'system-tray-setting',
value: newValue,
},
]);

if (OS.isWindows()) {
getLogger().info('app.ready: enabling open at login');
app.setLoginItemSettings({
...(await getDefaultLoginItemSettings()),
openAtLogin: true,
});
}
}

const startTime = Date.now();

settingsChannel = new SettingsChannel();
Expand Down Expand Up @@ -2055,16 +2141,27 @@ ipc.on(
}
);

ipc.on(
ipc.handle(
'update-system-tray-setting',
(_event, rawSystemTraySetting /* : Readonly<unknown> */) => {
async (_event, rawSystemTraySetting /* : Readonly<unknown> */) => {
const { openAtLogin } = app.getLoginItemSettings(
await getDefaultLoginItemSettings()
);

const systemTraySetting = parseSystemTraySetting(rawSystemTraySetting);
systemTraySettingCache.set(systemTraySetting);

if (systemTrayService) {
const isEnabled = shouldMinimizeToSystemTray(systemTraySetting);
systemTrayService.setEnabled(isEnabled);
}

// Default login item settings might have changed, so update the object.
getLogger().info('refresh-auto-launch: new value', openAtLogin);
app.setLoginItemSettings({
...(await getDefaultLoginItemSettings()),
openAtLogin,
});
}
);

Expand Down Expand Up @@ -2290,11 +2387,17 @@ async function ensureFilePermissions(onlyFiles?: Array<string>) {
}

ipc.handle('get-auto-launch', async () => {
return app.getLoginItemSettings().openAtLogin;
return app.getLoginItemSettings(await getDefaultLoginItemSettings())
.openAtLogin;
});

ipc.handle('set-auto-launch', async (_event, value) => {
app.setLoginItemSettings({ openAtLogin: Boolean(value) });
const openAtLogin = Boolean(value);
getLogger().info('set-auto-launch: new value', openAtLogin);
app.setLoginItemSettings({
...(await getDefaultLoginItemSettings()),
openAtLogin,
});
});

ipc.on('show-message-box', (_event, { type, message }) => {
Expand Down
1 change: 1 addition & 0 deletions ts/components/Preferences.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ const getDefaultArgs = (): PropsDataType => ({
isPhoneNumberSharingSupported: false,
isSyncSupported: true,
isSystemTraySupported: true,
isMinimizeToAndStartInSystemTraySupported: true,
lastSyncTime: Date.now(),
notificationContent: 'name',
selectedCamera:
Expand Down
24 changes: 14 additions & 10 deletions ts/components/Preferences.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export type PropsDataType = {
isPhoneNumberSharingSupported: boolean;
isSyncSupported: boolean;
isSystemTraySupported: boolean;
isMinimizeToAndStartInSystemTraySupported: boolean;

availableCameras: Array<
Pick<MediaDeviceInfo, 'deviceId' | 'groupId' | 'kind' | 'label'>
Expand Down Expand Up @@ -239,6 +240,7 @@ export const Preferences = ({
isNotificationAttentionSupported,
isSyncSupported,
isSystemTraySupported,
isMinimizeToAndStartInSystemTraySupported,
hasCustomTitleBar,
lastSyncTime,
makeSyncRequest,
Expand Down Expand Up @@ -371,16 +373,18 @@ export const Preferences = ({
name="system-tray-setting-minimize-to-system-tray"
onChange={onMinimizeToSystemTrayChange}
/>
<Checkbox
checked={hasMinimizeToAndStartInSystemTray}
disabled={!hasMinimizeToSystemTray}
label={i18n(
'SystemTraySetting__minimize-to-and-start-in-system-tray'
)}
moduleClassName="Preferences__checkbox"
name="system-tray-setting-minimize-to-and-start-in-system-tray"
onChange={onMinimizeToAndStartInSystemTrayChange}
/>
{isMinimizeToAndStartInSystemTraySupported && (
<Checkbox
checked={hasMinimizeToAndStartInSystemTray}
disabled={!hasMinimizeToSystemTray}
label={i18n(
'SystemTraySetting__minimize-to-and-start-in-system-tray'
)}
moduleClassName="Preferences__checkbox"
name="system-tray-setting-minimize-to-and-start-in-system-tray"
onChange={onMinimizeToAndStartInSystemTrayChange}
/>
)}
</>
)}
</SettingsRow>
Expand Down
100 changes: 0 additions & 100 deletions ts/components/conversation/SystemTraySettingsCheckboxes.tsx

This file was deleted.

2 changes: 0 additions & 2 deletions ts/signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import { MessageDetail } from './components/conversation/MessageDetail';
import { Quote } from './components/conversation/Quote';
import { StagedLinkPreview } from './components/conversation/StagedLinkPreview';
import { DisappearingTimeDialog } from './components/DisappearingTimeDialog';
import { SystemTraySettingsCheckboxes } from './components/conversation/SystemTraySettingsCheckboxes';

// State
import { createChatColorPicker } from './state/roots/createChatColorPicker';
Expand Down Expand Up @@ -409,7 +408,6 @@ export const setup = (options: {
Quote,
StagedLinkPreview,
DisappearingTimeDialog,
SystemTraySettingsCheckboxes,
};

const Roots = {
Expand Down

0 comments on commit b54c6f2

Please sign in to comment.