From 0ae23875b73ae09ab928650b7e8a33b06ce6b2df Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 22 Oct 2021 10:39:05 +1100 Subject: [PATCH] finish cleaning up Settings page --- ts/components/SessionMainPanel.tsx | 4 +- .../session/settings/SessionSettings.tsx | 320 ++---------------- .../settings/section/CategoryAppearance.tsx | 144 ++++++++ .../settings/section/CategoryPrivacy.tsx | 145 ++++++++ ts/session/utils/CallManager.ts | 2 +- ts/window.d.ts | 2 +- 6 files changed, 314 insertions(+), 303 deletions(-) create mode 100644 ts/components/session/settings/section/CategoryAppearance.tsx create mode 100644 ts/components/session/settings/section/CategoryPrivacy.tsx diff --git a/ts/components/SessionMainPanel.tsx b/ts/components/SessionMainPanel.tsx index 6fb233853..47e05a9a4 100644 --- a/ts/components/SessionMainPanel.tsx +++ b/ts/components/SessionMainPanel.tsx @@ -4,9 +4,9 @@ import { useAppIsFocused } from '../hooks/useAppFocused'; import { getFocusedSettingsSection } from '../state/selectors/section'; import { SmartSessionConversation } from '../state/smart/SessionConversation'; -import { SmartSettingsView } from './session/settings/SessionSettings'; +import { SessionSettingsView } from './session/settings/SessionSettings'; -const FilteredSettingsView = SmartSettingsView as any; +const FilteredSettingsView = SessionSettingsView as any; export const SessionMainPanel = () => { const focusedSettingsSection = useSelector(getFocusedSettingsSection); diff --git a/ts/components/session/settings/SessionSettings.tsx b/ts/components/session/settings/SessionSettings.tsx index e01174e11..224453e87 100644 --- a/ts/components/session/settings/SessionSettings.tsx +++ b/ts/components/session/settings/SessionSettings.tsx @@ -1,28 +1,17 @@ import React from 'react'; import { SettingsHeader } from './SessionSettingsHeader'; -import { SessionSettingButtonItem, SessionToggleWithDescription } from './SessionSettingListItem'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../SessionButton'; import { PasswordUtil } from '../../../util'; -import { useDispatch, useSelector } from 'react-redux'; -import { - createOrUpdateItem, - getPasswordHash, - hasLinkPreviewPopupBeenDisplayed, -} from '../../../../ts/data/data'; -import { ipcRenderer, shell } from 'electron'; +import { getPasswordHash } from '../../../../ts/data/data'; +import { shell } from 'electron'; import { SessionIconButton } from '../icon'; import autoBind from 'auto-bind'; import { SessionNotificationGroupSettings } from './SessionNotificationGroupSettings'; -import { sessionPassword, updateConfirmModal } from '../../../state/ducks/modalDialog'; -import { ToastUtils } from '../../../session/utils'; -import { getAudioAutoplay } from '../../../state/selectors/userConfig'; -import { toggleAudioAutoplay } from '../../../state/ducks/userConfig'; // tslint:disable-next-line: no-submodule-imports -import useUpdate from 'react-use/lib/useUpdate'; -import { PasswordAction } from '../../dialog/SessionPasswordDialog'; import { BlockedUserSettings } from './BlockedUserSettings'; -import { ZoomingSessionSlider } from './ZoomingSessionSlider'; +import { SettingsCategoryPrivacy } from './section/CategoryPrivacy'; +import { SettingsCategoryAppearance } from './section/CategoryAppearance'; export function getMediaPermissionsSettings() { return window.getSettingValue('media-permissions'); @@ -51,6 +40,21 @@ interface State { shouldLockSettings: boolean | null; } +const SessionInfo = () => { + const openOxenWebsite = () => { + void shell.openExternal('https://oxen.io/'); + }; + return ( +
+ v{window.versionInfo.version} + + + + {window.versionInfo.commitHash} +
+ ); +}; + export const PasswordLock = ({ pwdLockError, validatePasswordLock, @@ -77,268 +81,7 @@ export const PasswordLock = ({ ); }; -const SessionInfo = () => { - const openOxenWebsite = () => { - void shell.openExternal('https://oxen.io/'); - }; - return ( -
- v{window.versionInfo.version} - - - - {window.versionInfo.commitHash} -
- ); -}; - -async function toggleLinkPreviews() { - const newValue = !window.getSettingValue('link-preview-setting'); - window.setSettingValue('link-preview-setting', newValue); - if (!newValue) { - await createOrUpdateItem({ id: hasLinkPreviewPopupBeenDisplayed, value: false }); - } else { - window.inboxStore?.dispatch( - updateConfirmModal({ - title: window.i18n('linkPreviewsTitle'), - message: window.i18n('linkPreviewsConfirmMessage'), - okTheme: SessionButtonColor.Danger, - }) - ); - } -} - -async function toggleStartInTray() { - try { - const newValue = !(await window.getStartInTray()); - - // 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); - await window.setStartInTray(newValue); - if (!newValue) { - ToastUtils.pushRestartNeeded(); - } - } catch (e) { - window.log.warn('start in tray change error:', e); - } -} - -const toggleCallMediaPermissions = async (triggerUIUpdate: () => void) => { - const currentValue = window.getCallMediaPermissions(); - if (!currentValue) { - window.inboxStore?.dispatch( - updateConfirmModal({ - message: window.i18n('callMediaPermissionsDialogContent'), - okTheme: SessionButtonColor.Green, - onClickOk: async () => { - await window.toggleCallMediaPermissionsTo(true); - triggerUIUpdate(); - }, - onClickCancel: async () => { - await window.toggleCallMediaPermissionsTo(false); - triggerUIUpdate(); - }, - }) - ); - } else { - await window.toggleCallMediaPermissionsTo(false); - triggerUIUpdate(); - } -}; - -const SettingsCategoryAppearance = (props: { hasPassword: boolean | null }) => { - const dispatch = useDispatch(); - const forceUpdate = useUpdate(); - const audioAutoPlay = useSelector(getAudioAutoplay); - - if (props.hasPassword !== null) { - const isHideMenuBarActive = - window.getSettingValue('hide-menu-bar') === undefined - ? true - : window.getSettingValue('hide-menu-bar'); - - const isSpellCheckActive = - window.getSettingValue('spell-check') === undefined - ? true - : window.getSettingValue('spell-check'); - - const isLinkPreviewsOn = Boolean(window.getSettingValue('link-preview-setting')); - const isStartInTrayActive = Boolean(window.getSettingValue('start-in-tray-setting')); - - return ( - <> - {window.Signal.Types.Settings.isHideMenuBarSupported() && ( - { - window.toggleMenuBar(); - forceUpdate(); - }} - title={window.i18n('hideMenuBarTitle')} - description={window.i18n('hideMenuBarDescription')} - active={isHideMenuBarActive} - /> - )} - { - window.toggleSpellCheck(); - forceUpdate(); - }} - title={window.i18n('spellCheckTitle')} - description={window.i18n('spellCheckDescription')} - active={isSpellCheckActive} - /> - - { - await toggleLinkPreviews(); - forceUpdate(); - }} - title={window.i18n('linkPreviewsTitle')} - description={window.i18n('linkPreviewDescription')} - active={isLinkPreviewsOn} - /> - { - await toggleStartInTray(); - forceUpdate(); - }} - title={window.i18n('startInTrayTitle')} - description={window.i18n('startInTrayDescription')} - active={isStartInTrayActive} - /> - { - dispatch(toggleAudioAutoplay()); - forceUpdate(); - }} - title={window.i18n('audioMessageAutoplayTitle')} - description={window.i18n('audioMessageAutoplayDescription')} - active={audioAutoPlay} - /> - - void shell.openExternal('https://getsession.org/survey')} - buttonColor={SessionButtonColor.Primary} - buttonText={window.i18n('goToOurSurvey')} - /> - void shell.openExternal('https://crowdin.com/project/session-desktop/')} - buttonColor={SessionButtonColor.Primary} - buttonText={window.i18n('translation')} - /> - { - ipcRenderer.send('show-debug-log'); - }} - buttonColor={SessionButtonColor.Primary} - buttonText={window.i18n('showDebugLog')} - /> - - ); - } - return null; -}; - -const SettingsCategoryPrivacy = (props: { - hasPassword: boolean | null; - onPasswordUpdated: (action: string) => void; -}) => { - const forceUpdate = useUpdate(); - - if (props.hasPassword !== null) { - return ( - <> - { - await window.toggleMediaPermissions(); - forceUpdate(); - }} - title={window.i18n('mediaPermissionsTitle')} - description={window.i18n('mediaPermissionsDescription')} - active={Boolean(window.getSettingValue('media-permissions'))} - /> - - { - await toggleCallMediaPermissions(forceUpdate); - forceUpdate(); - }} - title={window.i18n('callMediaPermissionsTitle')} - description={window.i18n('callMediaPermissionsDescription')} - active={Boolean(window.getCallMediaPermissions())} - /> - { - const old = Boolean(window.getSettingValue('read-receipt-setting')); - window.setSettingValue('read-receipt-setting', !old); - forceUpdate(); - }} - title={window.i18n('readReceiptSettingTitle')} - description={window.i18n('readReceiptSettingDescription')} - active={window.getSettingValue('read-receipt-setting')} - /> - { - const old = Boolean(window.getSettingValue('typing-indicators-setting')); - window.setSettingValue('typing-indicators-setting', !old); - forceUpdate(); - }} - title={window.i18n('typingIndicatorsSettingTitle')} - description={window.i18n('typingIndicatorsSettingDescription')} - active={Boolean(window.getSettingValue('typing-indicators-setting'))} - /> - { - const old = Boolean(window.getSettingValue('auto-update')); - window.setSettingValue('auto-update', !old); - forceUpdate(); - }} - title={window.i18n('autoUpdateSettingTitle')} - description={window.i18n('autoUpdateSettingDescription')} - active={Boolean(window.getSettingValue('auto-update'))} - /> - {!props.hasPassword && ( - { - displayPasswordModal('set', props.onPasswordUpdated); - }} - buttonColor={SessionButtonColor.Primary} - buttonText={window.i18n('setPassword')} - /> - )} - {props.hasPassword && ( - { - displayPasswordModal('change', props.onPasswordUpdated); - }} - buttonColor={SessionButtonColor.Primary} - buttonText={window.i18n('changePassword')} - /> - )} - {props.hasPassword && ( - { - displayPasswordModal('remove', props.onPasswordUpdated); - }} - buttonColor={SessionButtonColor.Danger} - buttonText={window.i18n('removePassword')} - /> - )} - - ); - } - return null; -}; - -export class SmartSettingsView extends React.Component { +export class SessionSettingsView extends React.Component { public settingsViewRef: React.RefObject; public constructor(props: any) { @@ -372,13 +115,6 @@ export class SmartSettingsView extends React.Component window.removeEventListener('keyup', this.onKeyUp); } - public renderSettingsPrivacy() { - if (this.state.hasPassword !== null) { - return ; - } - return null; - } - /* tslint:disable-next-line:max-func-body-length */ public renderSettingInCategory() { const { category } = this.props; @@ -407,7 +143,7 @@ export class SmartSettingsView extends React.Component /> ); } - return ; + return null; } public async validatePasswordLock() { @@ -502,17 +238,3 @@ export class SmartSettingsView extends React.Component event.preventDefault(); } } - -function displayPasswordModal( - passwordAction: PasswordAction, - onPasswordUpdated: (action: string) => void -) { - window.inboxStore?.dispatch( - sessionPassword({ - passwordAction, - onOk: () => { - onPasswordUpdated(passwordAction); - }, - }) - ); -} diff --git a/ts/components/session/settings/section/CategoryAppearance.tsx b/ts/components/session/settings/section/CategoryAppearance.tsx new file mode 100644 index 000000000..31e5f66c2 --- /dev/null +++ b/ts/components/session/settings/section/CategoryAppearance.tsx @@ -0,0 +1,144 @@ +import { ipcRenderer, shell } from 'electron'; +import React from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +// tslint:disable-next-line: no-submodule-imports +import useUpdate from 'react-use/lib/useUpdate'; +import { createOrUpdateItem, hasLinkPreviewPopupBeenDisplayed } from '../../../../data/data'; +import { ToastUtils } from '../../../../session/utils'; +import { updateConfirmModal } from '../../../../state/ducks/modalDialog'; +import { toggleAudioAutoplay } from '../../../../state/ducks/userConfig'; +import { getAudioAutoplay } from '../../../../state/selectors/userConfig'; +import { SessionButtonColor } from '../../SessionButton'; +import { SessionSettingButtonItem, SessionToggleWithDescription } from '../SessionSettingListItem'; +import { ZoomingSessionSlider } from '../ZoomingSessionSlider'; + +async function toggleLinkPreviews() { + const newValue = !window.getSettingValue('link-preview-setting'); + window.setSettingValue('link-preview-setting', newValue); + if (!newValue) { + await createOrUpdateItem({ id: hasLinkPreviewPopupBeenDisplayed, value: false }); + } else { + window.inboxStore?.dispatch( + updateConfirmModal({ + title: window.i18n('linkPreviewsTitle'), + message: window.i18n('linkPreviewsConfirmMessage'), + okTheme: SessionButtonColor.Danger, + }) + ); + } +} + +async function toggleStartInTray() { + try { + const newValue = !(await window.getStartInTray()); + + // 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); + await window.setStartInTray(newValue); + if (!newValue) { + ToastUtils.pushRestartNeeded(); + } + } catch (e) { + window.log.warn('start in tray change error:', e); + } +} + +const settingsMenuBar = 'hide-menu-bar'; +const settingsSpellCheck = 'spell-check'; +const settingsLinkPreview = 'link-preview-setting'; +const settingsStartInTray = 'start-in-tray-setting'; + +export const SettingsCategoryAppearance = (props: { hasPassword: boolean | null }) => { + const dispatch = useDispatch(); + const forceUpdate = useUpdate(); + const audioAutoPlay = useSelector(getAudioAutoplay); + + if (props.hasPassword !== null) { + const isHideMenuBarActive = + window.getSettingValue(settingsMenuBar) === undefined + ? true + : window.getSettingValue(settingsMenuBar); + + const isSpellCheckActive = + window.getSettingValue(settingsSpellCheck) === undefined + ? true + : window.getSettingValue(settingsSpellCheck); + + const isLinkPreviewsOn = Boolean(window.getSettingValue(settingsLinkPreview)); + const isStartInTrayActive = Boolean(window.getSettingValue(settingsStartInTray)); + + return ( + <> + {window.Signal.Types.Settings.isHideMenuBarSupported() && ( + { + window.toggleMenuBar(); + forceUpdate(); + }} + title={window.i18n('hideMenuBarTitle')} + description={window.i18n('hideMenuBarDescription')} + active={isHideMenuBarActive} + /> + )} + { + window.toggleSpellCheck(); + forceUpdate(); + }} + title={window.i18n('spellCheckTitle')} + description={window.i18n('spellCheckDescription')} + active={isSpellCheckActive} + /> + + { + await toggleLinkPreviews(); + forceUpdate(); + }} + title={window.i18n('linkPreviewsTitle')} + description={window.i18n('linkPreviewDescription')} + active={isLinkPreviewsOn} + /> + { + await toggleStartInTray(); + forceUpdate(); + }} + title={window.i18n('startInTrayTitle')} + description={window.i18n('startInTrayDescription')} + active={isStartInTrayActive} + /> + { + dispatch(toggleAudioAutoplay()); + forceUpdate(); + }} + title={window.i18n('audioMessageAutoplayTitle')} + description={window.i18n('audioMessageAutoplayDescription')} + active={audioAutoPlay} + /> + + void shell.openExternal('https://getsession.org/survey')} + buttonColor={SessionButtonColor.Primary} + buttonText={window.i18n('goToOurSurvey')} + /> + void shell.openExternal('https://crowdin.com/project/session-desktop/')} + buttonColor={SessionButtonColor.Primary} + buttonText={window.i18n('translation')} + /> + { + ipcRenderer.send('show-debug-log'); + }} + buttonColor={SessionButtonColor.Primary} + buttonText={window.i18n('showDebugLog')} + /> + + ); + } + return null; +}; diff --git a/ts/components/session/settings/section/CategoryPrivacy.tsx b/ts/components/session/settings/section/CategoryPrivacy.tsx new file mode 100644 index 000000000..eecfda313 --- /dev/null +++ b/ts/components/session/settings/section/CategoryPrivacy.tsx @@ -0,0 +1,145 @@ +import React from 'react'; +// tslint:disable-next-line: no-submodule-imports +import useUpdate from 'react-use/lib/useUpdate'; +import { sessionPassword, updateConfirmModal } from '../../../../state/ducks/modalDialog'; +import { PasswordAction } from '../../../dialog/SessionPasswordDialog'; +import { SessionButtonColor } from '../../SessionButton'; +import { SessionSettingButtonItem, SessionToggleWithDescription } from '../SessionSettingListItem'; + +const settingsReadReceipt = 'read-receipt-setting'; +const settingsTypingIndicator = 'typing-indicators-setting'; +const settingsAutoUpdate = 'auto-update'; + +const toggleCallMediaPermissions = async (triggerUIUpdate: () => void) => { + const currentValue = window.getCallMediaPermissions(); + if (!currentValue) { + window.inboxStore?.dispatch( + updateConfirmModal({ + message: window.i18n('callMediaPermissionsDialogContent'), + okTheme: SessionButtonColor.Danger, + onClickOk: async () => { + await window.toggleCallMediaPermissionsTo(true); + triggerUIUpdate(); + }, + onClickCancel: async () => { + await window.toggleCallMediaPermissionsTo(false); + triggerUIUpdate(); + }, + }) + ); + } else { + await window.toggleCallMediaPermissionsTo(false); + triggerUIUpdate(); + } +}; + +function displayPasswordModal( + passwordAction: PasswordAction, + onPasswordUpdated: (action: string) => void +) { + window.inboxStore?.dispatch( + sessionPassword({ + passwordAction, + onOk: () => { + onPasswordUpdated(passwordAction); + }, + }) + ); +} + +export const SettingsCategoryPrivacy = (props: { + hasPassword: boolean | null; + onPasswordUpdated: (action: string) => void; +}) => { + const forceUpdate = useUpdate(); + + if (props.hasPassword !== null) { + return ( + <> + { + await window.toggleMediaPermissions(); + forceUpdate(); + }} + title={window.i18n('mediaPermissionsTitle')} + description={window.i18n('mediaPermissionsDescription')} + active={Boolean(window.getSettingValue('media-permissions'))} + /> + + { + await toggleCallMediaPermissions(forceUpdate); + forceUpdate(); + }} + title={window.i18n('callMediaPermissionsTitle')} + description={window.i18n('callMediaPermissionsDescription')} + active={Boolean(window.getCallMediaPermissions())} + /> + { + const old = Boolean(window.getSettingValue(settingsReadReceipt)); + window.setSettingValue(settingsReadReceipt, !old); + forceUpdate(); + }} + title={window.i18n('readReceiptSettingTitle')} + description={window.i18n('readReceiptSettingDescription')} + active={window.getSettingValue(settingsReadReceipt)} + /> + { + const old = Boolean(window.getSettingValue(settingsTypingIndicator)); + window.setSettingValue(settingsTypingIndicator, !old); + forceUpdate(); + }} + title={window.i18n('typingIndicatorsSettingTitle')} + description={window.i18n('typingIndicatorsSettingDescription')} + active={Boolean(window.getSettingValue(settingsTypingIndicator))} + /> + { + const old = Boolean(window.getSettingValue(settingsAutoUpdate)); + window.setSettingValue(settingsAutoUpdate, !old); + forceUpdate(); + }} + title={window.i18n('autoUpdateSettingTitle')} + description={window.i18n('autoUpdateSettingDescription')} + active={Boolean(window.getSettingValue(settingsAutoUpdate))} + /> + {!props.hasPassword && ( + { + displayPasswordModal('set', props.onPasswordUpdated); + }} + buttonColor={SessionButtonColor.Primary} + buttonText={window.i18n('setPassword')} + /> + )} + {props.hasPassword && ( + { + displayPasswordModal('change', props.onPasswordUpdated); + }} + buttonColor={SessionButtonColor.Primary} + buttonText={window.i18n('changePassword')} + /> + )} + {props.hasPassword && ( + { + displayPasswordModal('remove', props.onPasswordUpdated); + }} + buttonColor={SessionButtonColor.Danger} + buttonText={window.i18n('removePassword')} + /> + )} + + ); + } + return null; +}; diff --git a/ts/session/utils/CallManager.ts b/ts/session/utils/CallManager.ts index e27114994..09e8012d9 100644 --- a/ts/session/utils/CallManager.ts +++ b/ts/session/utils/CallManager.ts @@ -646,7 +646,7 @@ export async function handleCallTypeOffer( if (!getCallMediaPermissionsSettings()) { await handleMissedCall(sender, incomingOfferTimestamp); // TODO audric show where to turn it on - debugger; + throw new Error('TODO AUDRIC'); return; } diff --git a/ts/window.d.ts b/ts/window.d.ts index cf4c3fc50..7fb91f69e 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -35,7 +35,7 @@ declare global { friends: any; getConversations: any; getFriendsFromContacts: any; - getSettingValue: (id: string) => any; + getSettingValue: (id: string, comparisonValue?: any) => any; setSettingValue: (id: string, value: any) => void; i18n: LocalizerType;