diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 442a633ef..6e1f79dfc 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -150,6 +150,8 @@ "savedTheFile": "Media saved by $name$", "linkPreviewsTitle": "Send Link Previews", "linkPreviewDescription": "Previews are supported for most urls", + "startInTrayTitle": "Start in Tray", + "startInTrayDescription": "Start Session as a minified app ", "linkPreviewsConfirmMessage": "You will not have full metadata protection when sending or receiving link previews.", "mediaPermissionsTitle": "Microphone and Camera", "mediaPermissionsDescription": "Allow access to camera and microphone", diff --git a/js/background.js b/js/background.js index 4faea1237..0e017e593 100644 --- a/js/background.js +++ b/js/background.js @@ -334,7 +334,7 @@ // if not undefined, we take the opposite const newValue = currentValue !== undefined ? !currentValue : false; window.Events.setSpellCheck(newValue); - window.libsession.Utils.ToastUtils.pushSpellCheckDirty(); + window.libsession.Utils.ToastUtils.pushRestartNeeded(); }; window.toggleMediaPermissions = async () => { diff --git a/main.js b/main.js index c117f3c7a..e2c1f7f5f 100644 --- a/main.js +++ b/main.js @@ -46,8 +46,6 @@ function getMainWindow() { // Tray icon and related objects let tray = null; -const startInTray = process.argv.some(arg => arg === '--start-in-tray'); -const usingTrayIcon = startInTray || process.argv.some(arg => arg === '--use-tray-icon'); const config = require('./app/config'); @@ -231,13 +229,19 @@ function isVisible(window, bounds) { ); } +function getStartInTray() { + const startInTray = + process.argv.some(arg => arg === '--start-in-tray') || userConfig.get('startInTray'); + const usingTrayIcon = startInTray || process.argv.some(arg => arg === '--use-tray-icon'); + return { usingTrayIcon, startInTray }; +} async function createWindow() { const { screen } = electron; const { minWidth, minHeight, width, height } = getWindowSize(); const windowOptions = Object.assign( { - show: !startInTray, // allow to start minimised in tray + show: true, width, height, minWidth, @@ -378,7 +382,10 @@ async function createWindow() { // On Mac, or on other platforms when the tray icon is in use, the window // should be only hidden, not closed, when the user clicks the close button - if (!windowState.shouldQuit() && (usingTrayIcon || process.platform === 'darwin')) { + if ( + !windowState.shouldQuit() && + (getStartInTray().usingTrayIcon || process.platform === 'darwin') + ) { // toggle the visibility of the show/hide tray icon menu entries if (tray) { tray.updateContextMenu(); @@ -495,7 +502,10 @@ function showPasswordWindow() { // On Mac, or on other platforms when the tray icon is in use, the window // should be only hidden, not closed, when the user clicks the close button - if (!windowState.shouldQuit() && (usingTrayIcon || process.platform === 'darwin')) { + if ( + !windowState.shouldQuit() && + (getStartInTray().usingTrayIcon || process.platform === 'darwin') + ) { // toggle the visibility of the show/hide tray icon menu entries if (tray) { tray.updateContextMenu(); @@ -700,7 +710,7 @@ async function showMainWindow(sqlKey, passwordAttempt = false) { await createWindow(); - if (usingTrayIcon) { + if (getStartInTray().usingTrayIcon) { tray = createTrayIcon(getMainWindow, locale.messages); } @@ -885,6 +895,23 @@ ipc.on('password-window-login', async (event, passPhrase) => { sendResponse(localisedError || 'Invalid password'); } }); +ipc.on('start-in-tray-on-start', async (event, newValue) => { + try { + userConfig.set('startInTray', newValue); + event.sender.send('start-in-tray-on-start-response', null); + } catch (e) { + event.sender.send('start-in-tray-on-start-response', e); + } +}); + +ipc.on('get-start-in-tray', async (event, newValue) => { + try { + const val = userConfig.get('startInTray', newValue); + event.sender.send('get-start-in-tray-response', val); + } catch (e) { + event.sender.send('get-start-in-tray-response', false); + } +}); ipc.on('set-password', async (event, passPhrase, oldPhrase) => { const sendResponse = e => event.sender.send('set-password-response', e); diff --git a/preload.js b/preload.js index d300801b9..1b4ede67a 100644 --- a/preload.js +++ b/preload.js @@ -123,6 +123,23 @@ window.setPassword = (passPhrase, oldPhrase) => ipc.send('set-password', passPhrase, oldPhrase); }); +window.setStartInTray = startInTray => + new Promise((resolve, reject) => { + ipc.once('start-in-tray-on-start-response', (event, error) => { + if (error) { + return reject(error); + } + return resolve(); + }); + ipc.send('start-in-tray-on-start', startInTray); + }); + +window.getStartInTray = () => + new Promise(resolve => { + ipc.once('get-start-in-tray-response', (event, value) => resolve(value)); + ipc.send('get-start-in-tray'); + }); + window.libsession = require('./ts/session'); window.getConversationController = window.libsession.Conversations.getConversationController; diff --git a/ts/components/session/settings/SessionSettingListItem.tsx b/ts/components/session/settings/SessionSettingListItem.tsx index 451dd463a..a48e2d829 100644 --- a/ts/components/session/settings/SessionSettingListItem.tsx +++ b/ts/components/session/settings/SessionSettingListItem.tsx @@ -66,7 +66,7 @@ export const SessionSettingListItem = (props: Props) => { {type === SessionSettingType.Options && ( { diff --git a/ts/components/session/settings/SessionSettings.tsx b/ts/components/session/settings/SessionSettings.tsx index 4a285b060..12efbdd68 100644 --- a/ts/components/session/settings/SessionSettings.tsx +++ b/ts/components/session/settings/SessionSettings.tsx @@ -22,6 +22,7 @@ import { toggleAudioAutoplay } from '../../../state/ducks/userConfig'; import { sessionPassword } from '../../../state/ducks/modalDialog'; import { PasswordAction } from '../../dialog/SessionPasswordDialog'; import { SessionIconButton, SessionIconSize, SessionIconType } from '../icon'; +import { ToastUtils } from '../../../session/utils'; export enum SessionSettingCategory { Appearance = 'appearance', @@ -368,6 +369,26 @@ class SettingsViewInner extends React.Component { okTheme: SessionButtonColor.Danger, }, }, + + { + id: 'start-in-tray-setting', + title: window.i18n('startInTrayTitle'), + description: window.i18n('startInTrayDescription'), + hidden: false, + type: SessionSettingType.Toggle, + category: SessionSettingCategory.Appearance, + setFn: async () => { + const newValue = !(await window.getStartInTray()); + await window.setStartInTray(newValue); + // make sure to write it here too, as this is the value used on the UI to mark the toggle as true/false + window.setSettingValue('start-in-tray-setting', newValue); + ToastUtils.pushRestartNeeded(); + }, + content: undefined, + comparisonValue: undefined, + onClick: undefined, + confirmationDialogParams: undefined, + }, { id: 'audio-message-autoplay-setting', title: window.i18n('audioMessageAutoplayTitle'), @@ -385,6 +406,7 @@ class SettingsViewInner extends React.Component { onClick: undefined, confirmationDialogParams: undefined, }, + { id: 'notification-setting', title: window.i18n('notificationSettingsDialog'), @@ -400,7 +422,7 @@ class SettingsViewInner extends React.Component { content: { options: { group: 'notification-setting', - initalItem: window.getSettingValue('notification-setting') || 'message', + initialItem: window.getSettingValue('notification-setting') || 'message', items: [ { label: window.i18n('nameAndMessage'), diff --git a/ts/session/utils/Toast.tsx b/ts/session/utils/Toast.tsx index c90fbb5bf..e5cd4d56e 100644 --- a/ts/session/utils/Toast.tsx +++ b/ts/session/utils/Toast.tsx @@ -106,8 +106,8 @@ export function pushForceUnlinked() { pushToastInfo('successUnlinked', window.i18n('successUnlinked')); } -export function pushSpellCheckDirty() { - pushToastInfo('spellCheckDirty', window.i18n('spellCheckDirty')); +export function pushRestartNeeded() { + pushToastInfo('restartNeeded', window.i18n('spellCheckDirty')); } export function pushAlreadyMemberOpenGroup() { diff --git a/ts/window.d.ts b/ts/window.d.ts index c4a8c17ea..d984cf31d 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -81,5 +81,7 @@ declare global { globalOnlineStatus: boolean; confirmationDialog: any; callWorker: (fnName: string, ...args: any) => Promise; + setStartInTray: (val: boolean) => Promise; + getStartInTray: () => Promise; } }