441 lines
16 KiB
TypeScript
441 lines
16 KiB
TypeScript
// Copyright 2021 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
import { contextBridge, ipcRenderer } from 'electron';
|
|
import { MinimalSignalContext } from '../minimalContext';
|
|
|
|
import type { PropsPreloadType } from '../../components/Preferences';
|
|
import OS from '../../util/os/osPreload';
|
|
import * as Settings from '../../types/Settings';
|
|
import {
|
|
SystemTraySetting,
|
|
parseSystemTraySetting,
|
|
shouldMinimizeToSystemTray,
|
|
} from '../../types/SystemTraySetting';
|
|
import { awaitObject } from '../../util/awaitObject';
|
|
import { DurationInSeconds } from '../../util/durations';
|
|
import { createSetting, createCallback } from '../../util/preload';
|
|
|
|
function doneRendering() {
|
|
ipcRenderer.send('settings-done-rendering');
|
|
}
|
|
|
|
const settingMessageAudio = createSetting('audioMessage');
|
|
const settingAudioNotification = createSetting('audioNotification');
|
|
const settingAutoDownloadUpdate = createSetting('autoDownloadUpdate');
|
|
const settingAutoLaunch = createSetting('autoLaunch');
|
|
const settingCallRingtoneNotification = createSetting(
|
|
'callRingtoneNotification'
|
|
);
|
|
const settingCallSystemNotification = createSetting('callSystemNotification');
|
|
const settingCountMutedConversations = createSetting('countMutedConversations');
|
|
const settingDeviceName = createSetting('deviceName', { setter: false });
|
|
const settingHideMenuBar = createSetting('hideMenuBar');
|
|
const settingIncomingCallNotification = createSetting(
|
|
'incomingCallNotification'
|
|
);
|
|
const settingMediaCameraPermissions = createSetting('mediaCameraPermissions');
|
|
const settingMediaPermissions = createSetting('mediaPermissions');
|
|
const settingNotificationDrawAttention = createSetting(
|
|
'notificationDrawAttention'
|
|
);
|
|
const settingNotificationSetting = createSetting('notificationSetting');
|
|
const settingRelayCalls = createSetting('alwaysRelayCalls');
|
|
const settingSentMediaQuality = createSetting('sentMediaQualitySetting');
|
|
const settingSpellCheck = createSetting('spellCheck');
|
|
const settingTextFormatting = createSetting('textFormatting');
|
|
const settingTheme = createSetting('themeSetting');
|
|
const settingSystemTraySetting = createSetting('systemTraySetting');
|
|
|
|
const settingLastSyncTime = createSetting('lastSyncTime');
|
|
|
|
const settingHasStoriesDisabled = createSetting('hasStoriesDisabled');
|
|
const settingZoomFactor = createSetting('zoomFactor');
|
|
|
|
// Getters only.
|
|
const settingBlockedCount = createSetting('blockedCount');
|
|
const settingLinkPreview = createSetting('linkPreviewSetting', {
|
|
setter: false,
|
|
});
|
|
const settingPhoneNumberDiscoverability = createSetting(
|
|
'phoneNumberDiscoverabilitySetting'
|
|
);
|
|
const settingPhoneNumberSharing = createSetting('phoneNumberSharingSetting');
|
|
const settingReadReceipts = createSetting('readReceiptSetting', {
|
|
setter: false,
|
|
});
|
|
const settingTypingIndicators = createSetting('typingIndicatorSetting', {
|
|
setter: false,
|
|
});
|
|
|
|
// Media settings
|
|
const settingAudioInput = createSetting('preferredAudioInputDevice');
|
|
const settingAudioOutput = createSetting('preferredAudioOutputDevice');
|
|
const settingVideoInput = createSetting('preferredVideoInputDevice');
|
|
|
|
const settingUniversalExpireTimer = createSetting('universalExpireTimer');
|
|
|
|
// Callbacks
|
|
const ipcGetAvailableIODevices = createCallback('getAvailableIODevices');
|
|
const ipcGetCustomColors = createCallback('getCustomColors');
|
|
const ipcIsFormattingFlagEnabled = createCallback('isFormattingFlagEnabled');
|
|
const ipcIsSyncNotSupported = createCallback('isPrimary');
|
|
const ipcMakeSyncRequest = createCallback('syncRequest');
|
|
const ipcPNP = createCallback('isPhoneNumberSharingEnabled');
|
|
const ipcShouldShowStoriesSettings = createCallback(
|
|
'shouldShowStoriesSettings'
|
|
);
|
|
const ipcDeleteAllMyStories = createCallback('deleteAllMyStories');
|
|
|
|
// ChatColorPicker redux hookups
|
|
// The redux actions update over IPC through a preferences re-render
|
|
const ipcGetDefaultConversationColor = createCallback(
|
|
'getDefaultConversationColor'
|
|
);
|
|
const ipcGetConversationsWithCustomColor = createCallback(
|
|
'getConversationsWithCustomColor'
|
|
);
|
|
const ipcAddCustomColor = createCallback('addCustomColor');
|
|
const ipcEditCustomColor = createCallback('editCustomColor');
|
|
const ipcRemoveCustomColor = createCallback('removeCustomColor');
|
|
const ipcRemoveCustomColorOnConversations = createCallback(
|
|
'removeCustomColorOnConversations'
|
|
);
|
|
const ipcResetAllChatColors = createCallback('resetAllChatColors');
|
|
const ipcResetDefaultChatColor = createCallback('resetDefaultChatColor');
|
|
const ipcSetGlobalDefaultConversationColor = createCallback(
|
|
'setGlobalDefaultConversationColor'
|
|
);
|
|
|
|
const DEFAULT_NOTIFICATION_SETTING = 'message';
|
|
|
|
function getSystemTraySettingValues(systemTraySetting: SystemTraySetting): {
|
|
hasMinimizeToAndStartInSystemTray: boolean;
|
|
hasMinimizeToSystemTray: boolean;
|
|
} {
|
|
const parsedSystemTraySetting = parseSystemTraySetting(systemTraySetting);
|
|
const hasMinimizeToAndStartInSystemTray =
|
|
parsedSystemTraySetting ===
|
|
SystemTraySetting.MinimizeToAndStartInSystemTray;
|
|
const hasMinimizeToSystemTray = shouldMinimizeToSystemTray(
|
|
parsedSystemTraySetting
|
|
);
|
|
|
|
return {
|
|
hasMinimizeToAndStartInSystemTray,
|
|
hasMinimizeToSystemTray,
|
|
};
|
|
}
|
|
|
|
let renderInBrowser = (_props: PropsPreloadType): void => {
|
|
throw new Error('render is not defined');
|
|
};
|
|
|
|
function attachRenderCallback<Value>(f: (value: Value) => Promise<Value>) {
|
|
return async (value: Value) => {
|
|
await f(value);
|
|
void renderPreferences();
|
|
};
|
|
}
|
|
|
|
async function renderPreferences() {
|
|
const {
|
|
blockedCount,
|
|
deviceName,
|
|
hasAudioNotifications,
|
|
hasAutoDownloadUpdate,
|
|
hasAutoLaunch,
|
|
hasCallNotifications,
|
|
hasCallRingtoneNotification,
|
|
hasCountMutedConversations,
|
|
hasHideMenuBar,
|
|
hasIncomingCallNotifications,
|
|
hasLinkPreviews,
|
|
hasMediaCameraPermissions,
|
|
hasMediaPermissions,
|
|
hasMessageAudio,
|
|
hasNotificationAttention,
|
|
hasReadReceipts,
|
|
hasRelayCalls,
|
|
hasSpellCheck,
|
|
hasStoriesDisabled,
|
|
hasTextFormatting,
|
|
hasTypingIndicators,
|
|
isFormattingFlagEnabled,
|
|
isPhoneNumberSharingSupported,
|
|
lastSyncTime,
|
|
notificationContent,
|
|
selectedCamera,
|
|
selectedMicrophone,
|
|
selectedSpeaker,
|
|
sentMediaQualitySetting,
|
|
systemTraySetting,
|
|
themeSetting,
|
|
universalExpireTimer,
|
|
whoCanFindMe,
|
|
whoCanSeeMe,
|
|
zoomFactor,
|
|
|
|
availableIODevices,
|
|
customColors,
|
|
defaultConversationColor,
|
|
isSyncNotSupported,
|
|
shouldShowStoriesSettings,
|
|
} = await awaitObject({
|
|
blockedCount: settingBlockedCount.getValue(),
|
|
deviceName: settingDeviceName.getValue(),
|
|
hasAudioNotifications: settingAudioNotification.getValue(),
|
|
hasAutoDownloadUpdate: settingAutoDownloadUpdate.getValue(),
|
|
hasAutoLaunch: settingAutoLaunch.getValue(),
|
|
hasCallNotifications: settingCallSystemNotification.getValue(),
|
|
hasCallRingtoneNotification: settingCallRingtoneNotification.getValue(),
|
|
hasCountMutedConversations: settingCountMutedConversations.getValue(),
|
|
hasHideMenuBar: settingHideMenuBar.getValue(),
|
|
hasIncomingCallNotifications: settingIncomingCallNotification.getValue(),
|
|
hasLinkPreviews: settingLinkPreview.getValue(),
|
|
hasMediaCameraPermissions: settingMediaCameraPermissions.getValue(),
|
|
hasMediaPermissions: settingMediaPermissions.getValue(),
|
|
hasMessageAudio: settingMessageAudio.getValue(),
|
|
hasNotificationAttention: settingNotificationDrawAttention.getValue(),
|
|
hasReadReceipts: settingReadReceipts.getValue(),
|
|
hasRelayCalls: settingRelayCalls.getValue(),
|
|
hasSpellCheck: settingSpellCheck.getValue(),
|
|
hasStoriesDisabled: settingHasStoriesDisabled.getValue(),
|
|
hasTextFormatting: settingTextFormatting.getValue(),
|
|
hasTypingIndicators: settingTypingIndicators.getValue(),
|
|
isPhoneNumberSharingSupported: ipcPNP(),
|
|
lastSyncTime: settingLastSyncTime.getValue(),
|
|
notificationContent: settingNotificationSetting.getValue(),
|
|
selectedCamera: settingVideoInput.getValue(),
|
|
selectedMicrophone: settingAudioInput.getValue(),
|
|
selectedSpeaker: settingAudioOutput.getValue(),
|
|
sentMediaQualitySetting: settingSentMediaQuality.getValue(),
|
|
systemTraySetting: settingSystemTraySetting.getValue(),
|
|
themeSetting: settingTheme.getValue(),
|
|
universalExpireTimer: settingUniversalExpireTimer.getValue(),
|
|
whoCanFindMe: settingPhoneNumberDiscoverability.getValue(),
|
|
whoCanSeeMe: settingPhoneNumberSharing.getValue(),
|
|
zoomFactor: settingZoomFactor.getValue(),
|
|
|
|
// Callbacks
|
|
availableIODevices: ipcGetAvailableIODevices(),
|
|
customColors: ipcGetCustomColors(),
|
|
defaultConversationColor: ipcGetDefaultConversationColor(),
|
|
isFormattingFlagEnabled: ipcIsFormattingFlagEnabled(),
|
|
isSyncNotSupported: ipcIsSyncNotSupported(),
|
|
shouldShowStoriesSettings: ipcShouldShowStoriesSettings(),
|
|
});
|
|
|
|
const { availableCameras, availableMicrophones, availableSpeakers } =
|
|
availableIODevices;
|
|
|
|
const { hasMinimizeToAndStartInSystemTray, hasMinimizeToSystemTray } =
|
|
getSystemTraySettingValues(systemTraySetting);
|
|
|
|
const onUniversalExpireTimerChange = attachRenderCallback(
|
|
settingUniversalExpireTimer.setValue
|
|
);
|
|
|
|
const props = {
|
|
// Settings
|
|
availableCameras,
|
|
availableMicrophones,
|
|
availableSpeakers,
|
|
blockedCount,
|
|
customColors,
|
|
defaultConversationColor,
|
|
deviceName,
|
|
hasAudioNotifications,
|
|
hasAutoDownloadUpdate,
|
|
hasAutoLaunch,
|
|
hasCallNotifications,
|
|
hasCallRingtoneNotification,
|
|
hasCountMutedConversations,
|
|
hasHideMenuBar,
|
|
hasIncomingCallNotifications,
|
|
hasLinkPreviews,
|
|
hasMediaCameraPermissions,
|
|
hasMediaPermissions,
|
|
hasMessageAudio,
|
|
hasMinimizeToAndStartInSystemTray,
|
|
hasMinimizeToSystemTray,
|
|
hasNotificationAttention,
|
|
hasNotifications: notificationContent !== 'off',
|
|
hasReadReceipts,
|
|
hasRelayCalls,
|
|
hasSpellCheck,
|
|
hasStoriesDisabled,
|
|
hasTextFormatting,
|
|
hasTypingIndicators,
|
|
lastSyncTime,
|
|
notificationContent,
|
|
selectedCamera,
|
|
selectedMicrophone,
|
|
selectedSpeaker,
|
|
sentMediaQualitySetting,
|
|
themeSetting,
|
|
universalExpireTimer: DurationInSeconds.fromSeconds(universalExpireTimer),
|
|
whoCanFindMe,
|
|
whoCanSeeMe,
|
|
zoomFactor,
|
|
|
|
// Actions and other props
|
|
addCustomColor: ipcAddCustomColor,
|
|
closeSettings: () => MinimalSignalContext.executeMenuRole('close'),
|
|
doDeleteAllData: () => ipcRenderer.send('delete-all-data'),
|
|
doneRendering,
|
|
editCustomColor: ipcEditCustomColor,
|
|
getConversationsWithCustomColor: ipcGetConversationsWithCustomColor,
|
|
initialSpellCheckSetting:
|
|
MinimalSignalContext.config.appStartInitialSpellcheckSetting,
|
|
makeSyncRequest: ipcMakeSyncRequest,
|
|
removeCustomColor: ipcRemoveCustomColor,
|
|
removeCustomColorOnConversations: ipcRemoveCustomColorOnConversations,
|
|
resetAllChatColors: ipcResetAllChatColors,
|
|
resetDefaultChatColor: ipcResetDefaultChatColor,
|
|
setGlobalDefaultConversationColor: ipcSetGlobalDefaultConversationColor,
|
|
shouldShowStoriesSettings,
|
|
|
|
// Limited support features
|
|
isAutoDownloadUpdatesSupported: Settings.isAutoDownloadUpdatesSupported(OS),
|
|
isAutoLaunchSupported: Settings.isAutoLaunchSupported(OS),
|
|
isHideMenuBarSupported: Settings.isHideMenuBarSupported(OS),
|
|
isNotificationAttentionSupported: Settings.isDrawAttentionSupported(OS),
|
|
isPhoneNumberSharingSupported,
|
|
isSyncSupported: !isSyncNotSupported,
|
|
isSystemTraySupported: Settings.isSystemTraySupported(
|
|
OS,
|
|
MinimalSignalContext.getVersion()
|
|
),
|
|
isMinimizeToAndStartInSystemTraySupported:
|
|
Settings.isMinimizeToAndStartInSystemTraySupported(
|
|
OS,
|
|
MinimalSignalContext.getVersion()
|
|
),
|
|
|
|
// Feature flags
|
|
isFormattingFlagEnabled,
|
|
|
|
// Change handlers
|
|
onAudioNotificationsChange: attachRenderCallback(
|
|
settingAudioNotification.setValue
|
|
),
|
|
onAutoDownloadUpdateChange: attachRenderCallback(
|
|
settingAutoDownloadUpdate.setValue
|
|
),
|
|
onAutoLaunchChange: attachRenderCallback(settingAutoLaunch.setValue),
|
|
onCallNotificationsChange: attachRenderCallback(
|
|
settingCallSystemNotification.setValue
|
|
),
|
|
onCallRingtoneNotificationChange: attachRenderCallback(
|
|
settingCallRingtoneNotification.setValue
|
|
),
|
|
onCountMutedConversationsChange: attachRenderCallback(
|
|
settingCountMutedConversations.setValue
|
|
),
|
|
onHasStoriesDisabledChanged: attachRenderCallback(
|
|
async (value: boolean) => {
|
|
await settingHasStoriesDisabled.setValue(value);
|
|
if (!value) {
|
|
void ipcDeleteAllMyStories();
|
|
}
|
|
return value;
|
|
}
|
|
),
|
|
onHideMenuBarChange: attachRenderCallback(settingHideMenuBar.setValue),
|
|
onIncomingCallNotificationsChange: attachRenderCallback(
|
|
settingIncomingCallNotification.setValue
|
|
),
|
|
onLastSyncTimeChange: attachRenderCallback(settingLastSyncTime.setValue),
|
|
onMediaCameraPermissionsChange: attachRenderCallback(
|
|
settingMediaCameraPermissions.setValue
|
|
),
|
|
onMessageAudioChange: attachRenderCallback(settingMessageAudio.setValue),
|
|
onMinimizeToAndStartInSystemTrayChange: attachRenderCallback(
|
|
async (value: boolean) => {
|
|
await settingSystemTraySetting.setValue(
|
|
value
|
|
? SystemTraySetting.MinimizeToAndStartInSystemTray
|
|
: SystemTraySetting.MinimizeToSystemTray
|
|
);
|
|
return value;
|
|
}
|
|
),
|
|
onMinimizeToSystemTrayChange: attachRenderCallback(
|
|
async (value: boolean) => {
|
|
await settingSystemTraySetting.setValue(
|
|
value
|
|
? SystemTraySetting.MinimizeToSystemTray
|
|
: SystemTraySetting.DoNotUseSystemTray
|
|
);
|
|
return value;
|
|
}
|
|
),
|
|
onMediaPermissionsChange: attachRenderCallback(
|
|
settingMediaPermissions.setValue
|
|
),
|
|
onNotificationAttentionChange: attachRenderCallback(
|
|
settingNotificationDrawAttention.setValue
|
|
),
|
|
onNotificationContentChange: attachRenderCallback(
|
|
settingNotificationSetting.setValue
|
|
),
|
|
onNotificationsChange: attachRenderCallback(async (value: boolean) => {
|
|
await settingNotificationSetting.setValue(
|
|
value ? DEFAULT_NOTIFICATION_SETTING : 'off'
|
|
);
|
|
return value;
|
|
}),
|
|
onRelayCallsChange: attachRenderCallback(settingRelayCalls.setValue),
|
|
onSelectedCameraChange: attachRenderCallback(settingVideoInput.setValue),
|
|
onSelectedMicrophoneChange: attachRenderCallback(
|
|
settingAudioInput.setValue
|
|
),
|
|
onSelectedSpeakerChange: attachRenderCallback(settingAudioOutput.setValue),
|
|
onSentMediaQualityChange: attachRenderCallback(
|
|
settingSentMediaQuality.setValue
|
|
),
|
|
onSpellCheckChange: attachRenderCallback(settingSpellCheck.setValue),
|
|
onTextFormattingChange: attachRenderCallback(
|
|
settingTextFormatting.setValue
|
|
),
|
|
onThemeChange: attachRenderCallback(settingTheme.setValue),
|
|
onUniversalExpireTimerChange: (newValue: number): Promise<void> => {
|
|
return onUniversalExpireTimerChange(
|
|
DurationInSeconds.fromSeconds(newValue)
|
|
);
|
|
},
|
|
|
|
onWhoCanFindMeChange: attachRenderCallback(
|
|
settingPhoneNumberDiscoverability.setValue
|
|
),
|
|
onWhoCanSeeMeChange: attachRenderCallback(
|
|
settingPhoneNumberSharing.setValue
|
|
),
|
|
|
|
// Zoom factor change doesn't require immediate rerender since it will:
|
|
// 1. Update the zoom factor in the main window
|
|
// 2. Trigger `preferred-size-changed` in the main process
|
|
// 3. Finally result in `window.storage` update which will cause the
|
|
// rerender.
|
|
onZoomFactorChange: settingZoomFactor.setValue,
|
|
|
|
hasCustomTitleBar: MinimalSignalContext.OS.hasCustomTitleBar(),
|
|
executeMenuRole: MinimalSignalContext.executeMenuRole,
|
|
};
|
|
|
|
renderInBrowser(props);
|
|
}
|
|
|
|
ipcRenderer.on('preferences-changed', () => renderPreferences());
|
|
|
|
const Signal = {
|
|
SettingsWindowProps: {
|
|
onRender: (renderer: (_props: PropsPreloadType) => void) => {
|
|
renderInBrowser = renderer;
|
|
void renderPreferences();
|
|
},
|
|
},
|
|
};
|
|
contextBridge.exposeInMainWorld('Signal', Signal);
|
|
contextBridge.exposeInMainWorld('SignalContext', MinimalSignalContext);
|