From a0d3a00afa1da875e7b24bd85a412a32a430b6c9 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 19 Aug 2022 15:25:26 +1000 Subject: [PATCH] feat: start of settings screen redesign --- _locales/en/messages.json | 8 +- stylesheets/_session_group_panel.scss | 2 +- stylesheets/_session_left_pane.scss | 121 -------------- .../conversation/SessionRightPanel.tsx | 26 ++- .../leftpane/LeftPaneSectionHeader.tsx | 19 +-- .../leftpane/LeftPaneSettingSection.tsx | 158 ++++++++++-------- .../settings/BlockedUserSettings.tsx | 43 ----- .../settings/SessionSettingListItem.tsx | 2 +- ts/components/settings/SessionSettings.tsx | 62 ++++--- .../settings/section/CategoryAppearance.tsx | 118 +------------ .../section/CategoryConversations.tsx | 140 ++++++++++++++++ .../settings/section/CategoryHelp.tsx | 34 ++++ .../settings/section/CategoryPermissions.tsx | 98 +++++++++++ .../settings/section/CategoryPrivacy.tsx | 104 +++--------- ts/state/ducks/section.tsx | 2 +- ts/types/LocalizerKeys.ts | 15 +- 16 files changed, 453 insertions(+), 499 deletions(-) delete mode 100644 ts/components/settings/BlockedUserSettings.tsx create mode 100644 ts/components/settings/section/CategoryConversations.tsx create mode 100644 ts/components/settings/section/CategoryHelp.tsx create mode 100644 ts/components/settings/section/CategoryPermissions.tsx diff --git a/_locales/en/messages.json b/_locales/en/messages.json index e08cd4a0d..aedeb495e 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -224,7 +224,8 @@ "unblockUser": "Unblock", "unblocked": "Unblocked", "blocked": "Blocked", - "blockedSettingsTitle": "Blocked contacts", + "blockedSettingsTitle": "Blocked Contacts", + "conversationsSettingsTitle": "Conversations", "unbanUser": "Unban User", "userUnbanned": "User unbanned successfully", "userUnbanFailed": "Unban failed!", @@ -407,6 +408,7 @@ "surveyTitle": "Take our Session Survey", "goToOurSurvey": "Go to our survey", "clearAll": "Clear All", + "clearDataSettingsTitle": "Clear Data", "messageRequests": "Message Requests", "requestsSubtitle": "Pending Requests", "requestsPlaceholder": "No requests", @@ -417,6 +419,8 @@ "accept": "Accept", "decline": "Decline", "endCall": "End call", + "permissionsSettingsTitle": "Permissions", + "helpSettingsTitle": "Help", "cameraPermissionNeededTitle": "Voice/Video Call permissions required", "cameraPermissionNeeded": "You can enable the 'Voice and video calls' permission in the Privacy Settings.", "unableToCall": "Cancel your ongoing call first", @@ -444,7 +448,7 @@ "declineRequestMessage": "Are you sure you want to decline this message request?", "respondingToRequestWarning": "Sending a message to this user will automatically accept their message request and reveal your Session ID.", "hideRequestBanner": "Hide Message Request Banner", - "openMessageRequestInbox": "View Message Requests", + "openMessageRequestInbox": "Message Requests", "noMessageRequestsPending": "No pending message requests", "noMediaUntilApproved": "You cannot send attachments until the conversation is approved", "mustBeApproved": "This conversation must be accepted to use this feature", diff --git a/stylesheets/_session_group_panel.scss b/stylesheets/_session_group_panel.scss index 8f4163806..548dfde4d 100644 --- a/stylesheets/_session_group_panel.scss +++ b/stylesheets/_session_group_panel.scss @@ -9,7 +9,7 @@ align-items: center; &-header { - margin-top: $session-margin-lg; + margin-top: var(--margins-lg); margin-inline-start: $session-margin-sm; margin-inline-end: $session-margin-sm; width: -webkit-fill-available; diff --git a/stylesheets/_session_left_pane.scss b/stylesheets/_session_left_pane.scss index f07b21807..c8a0ba1bf 100644 --- a/stylesheets/_session_left_pane.scss +++ b/stylesheets/_session_left_pane.scss @@ -89,21 +89,6 @@ $session-compose-margin: 20px; height: $main-view-header-height; padding-inline-end: 7px; transition: $session-transition-duration; - - .session-button { - margin-inline-start: auto; - @include fontAccentBold(); - } - - &-buttons { - margin-bottom: $session-margin-sm; - display: inline-flex; - width: 100%; - - .session-button { - flex: 1; - } - } } &__title { @@ -192,109 +177,3 @@ $session-compose-margin: 20px; } } } - -@mixin bottom-buttons() { - display: flex; - flex-direction: row; - width: 100%; - background: none; - - .session-button.square-outline.square.green, - .session-button.square-outline.square.white, - .session-button.square-outline.square.danger { - flex-grow: 1; - height: $composition-container-height; - - border: var(--border-session); - } -} - -.left-pane-setting { - &-bottom-buttons { - @include bottom-buttons(); - - .session-button { - vertical-align: middle; - white-space: normal; - text-align: center; - } - } - - &-content, - &-section { - display: flex; - flex-direction: column; - flex: 1; - } - - &-category-list-item { - background: none; - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - height: 74px; - line-height: 1.4; - padding: 0px 12px; - flex-shrink: 0; - cursor: pointer; - transition: $session-transition-duration !important; - - & > div { - display: block; - } - - &.active { - background: var(--color-conversation-item-selected); - } - - &:hover { - background: var(--color-clickable-hovered); - } - - &__buttons { - display: flex; - - .session-button { - font-size: var(--font-size-xs); - padding: 6px; - height: auto; - margin: 0px; - line-height: 14px; - } - } - } - - &-input-group { - display: inline-flex; - } - - &-input-button .session-button.square { - display: flex; - justify-content: center; - align-items: center; - - height: $session-search-input-height; - width: $session-search-input-height; - - padding: 0px; - margin: 0px; - - svg { - transition: $session-transition-duration; - } - - &:hover { - svg { - fill: $session-color-green; - } - } - .session-button.square-outline.square.green, - .session-button.square-outline.square.white { - flex-grow: 1; - border: 1px solid $session-shade-8; - height: 50px; - // line-height: 50px; - } - } -} diff --git a/ts/components/conversation/SessionRightPanel.tsx b/ts/components/conversation/SessionRightPanel.tsx index 1bd4f7c70..83c840607 100644 --- a/ts/components/conversation/SessionRightPanel.tsx +++ b/ts/components/conversation/SessionRightPanel.tsx @@ -125,20 +125,18 @@ const HeaderItem = () => { dataTestId="back-button-conversation-options" /> -
- {showInviteContacts && ( - { - if (selectedConversation) { - showInviteContactByConvoId(selectedConversation.id); - } - }} - dataTestId="add-user-button" - /> - )} -
+ {showInviteContacts && ( + { + if (selectedConversation) { + showInviteContactByConvoId(selectedConversation.id); + } + }} + dataTestId="add-user-button" + /> + )} ); }; diff --git a/ts/components/leftpane/LeftPaneSectionHeader.tsx b/ts/components/leftpane/LeftPaneSectionHeader.tsx index 0b92959d5..18597a5a4 100644 --- a/ts/components/leftpane/LeftPaneSectionHeader.tsx +++ b/ts/components/leftpane/LeftPaneSectionHeader.tsx @@ -6,9 +6,8 @@ import { getShowRecoveryPhrasePrompt } from '../../state/selectors/userConfig'; import { recoveryPhraseModal } from '../../state/ducks/modalDialog'; import { Flex } from '../basic/Flex'; import { getFocusedSection, getOverlayMode } from '../../state/selectors/section'; -import { resetOverlayMode, SectionType } from '../../state/ducks/section'; +import { SectionType } from '../../state/ducks/section'; import { SessionButton, SessionButtonType } from '../basic/SessionButton'; -import { SessionIconButton } from '../icon'; import { isSignWithRecoveryPhrase } from '../../util/storage'; import { MenuButton } from '../button/MenuButton'; @@ -22,15 +21,12 @@ export const LeftPaneSectionHeader = () => { const showRecoveryPhrasePrompt = useSelector(getShowRecoveryPhrasePrompt); const focusedSection = useSelector(getFocusedSection); const overlayMode = useSelector(getOverlayMode); - const dispatch = useDispatch(); let label: string | undefined; const isMessageSection = focusedSection === SectionType.Message; const isMessageRequestOverlay = overlayMode && overlayMode === 'message-requests'; - const showBackButton = isMessageRequestOverlay && isMessageSection; - switch (focusedSection) { case SectionType.Settings: label = window.i18n('settingsHeader'); @@ -46,19 +42,8 @@ export const LeftPaneSectionHeader = () => { return (
- {showBackButton ? ( - { - dispatch(resetOverlayMode()); - }} - iconType="chevron" - iconRotation={90} - iconSize="medium" - margin="0 0 var(--margins-xs) var(--margins-xs)" - /> - ) : null} {label} - {isMessageSection && !isMessageRequestOverlay && } + {isMessageSection && }
{showRecoveryPhrasePrompt && }
diff --git a/ts/components/leftpane/LeftPaneSettingSection.tsx b/ts/components/leftpane/LeftPaneSettingSection.tsx index f53d1eec8..4eaa33e17 100644 --- a/ts/components/leftpane/LeftPaneSettingSection.tsx +++ b/ts/components/leftpane/LeftPaneSettingSection.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import classNames from 'classnames'; +import styled from 'styled-components'; import { LeftPaneSectionHeader } from './LeftPaneSectionHeader'; import { useDispatch, useSelector } from 'react-redux'; @@ -11,34 +11,48 @@ import { } from '../../state/ducks/section'; import { getFocusedSettingsSection } from '../../state/selectors/section'; import { recoveryPhraseModal, updateDeleteAccountModal } from '../../state/ducks/modalDialog'; -import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; import { SessionIcon } from '../icon'; import { SessionSettingCategory } from '../settings/SessionSettings'; import { resetConversationExternal } from '../../state/ducks/conversations'; -import { StyledLeftPaneList } from './LeftPaneList'; const getCategories = () => { return [ - { - id: SessionSettingCategory.Appearance, - title: window.i18n('appearanceSettingsTitle'), - }, { id: SessionSettingCategory.Privacy, title: window.i18n('privacySettingsTitle'), }, - { - id: SessionSettingCategory.Blocked, - title: window.i18n('blockedSettingsTitle'), - }, { id: SessionSettingCategory.Notifications, title: window.i18n('notificationsSettingsTitle'), }, + { + id: SessionSettingCategory.Conversations, + title: window.i18n('conversationsSettingsTitle'), + }, { id: SessionSettingCategory.MessageRequests, title: window.i18n('openMessageRequestInbox'), }, + { + id: SessionSettingCategory.Appearance, + title: window.i18n('appearanceSettingsTitle'), + }, + { + id: SessionSettingCategory.Permissions, + title: window.i18n('permissionsSettingsTitle'), + }, + { + id: SessionSettingCategory.Help, + title: window.i18n('helpSettingsTitle'), + }, + { + id: SessionSettingCategory.RecoveryPhrase, + title: window.i18n('recoveryPhrase'), + }, + { + id: SessionSettingCategory.ClearData, + title: window.i18n('clearDataSettingsTitle'), + }, ]; }; @@ -50,39 +64,44 @@ const LeftPaneSettingsCategoryRow = (props: { const dispatch = useDispatch(); const focusedSettingsSection = useSelector(getFocusedSettingsSection); - const isMessageRequestSetting = id === SessionSettingCategory.MessageRequests; - const dataTestId = `${title.toLowerCase()}-settings-menu-item`; + const isClearData = id === SessionSettingCategory.ClearData; + return ( -
{ - if (isMessageRequestSetting) { - dispatch(showLeftPaneSection(SectionType.Message)); - dispatch(setOverlayMode('message-requests')); - dispatch(resetConversationExternal()); - } else { - dispatch(showSettingsSection(id)); + switch (id) { + case SessionSettingCategory.MessageRequests: + dispatch(showLeftPaneSection(SectionType.Message)); + dispatch(setOverlayMode('message-requests')); + dispatch(resetConversationExternal()); + break; + case SessionSettingCategory.RecoveryPhrase: + dispatch(recoveryPhraseModal({})); + break; + case SessionSettingCategory.ClearData: + dispatch(updateDeleteAccountModal({})); + break; + default: + dispatch(showSettingsSection(id)); } }} > -
- {title} -
+ + {title} + -
- {id === focusedSettingsSection && ( - - )} -
-
+ {id === focusedSettingsSection && ( + + )} + ); }; @@ -90,53 +109,50 @@ const LeftPaneSettingsCategories = () => { const categories = getCategories(); return ( - -
- {categories.map(item => { - return ; - })} -
-
+ <> + {categories.map(item => { + return ; + })} + ); }; +const StyledContentSection = styled.div` + display: flex; + flex-direction: column; + flex: 1; + overflow-y: auto; +`; -const LeftPaneBottomButtons = () => { - const dangerButtonText = window.i18n('clearAllData'); - const showRecoveryPhrase = window.i18n('showRecoveryPhrase'); +const StyledSettingsSectionTitle = styled.strong` + font-family: var(--font-font-accent); + font-size: var(--font-size-md); +`; - const dispatch = useDispatch(); +const StyledSettingsListItem = styled.div<{ active: boolean }>` + background: ${props => (props.active ? 'var(--color-conversation-item-selected)' : 'none')}; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + height: 74px; + line-height: 1.4; + padding: 0px var(--margins-md); + flex-shrink: 0; + cursor: pointer; + transition: var(--default-duration) !important; - return ( -
- { - dispatch(updateDeleteAccountModal({})); - }} - /> - - { - dispatch(recoveryPhraseModal({})); - }} - /> -
- ); -}; + :hover { + background: var(--color-clickable-hovered); + } +`; export const LeftPaneSettingSection = () => { return ( -
+ -
+ - -
-
+ + ); }; diff --git a/ts/components/settings/BlockedUserSettings.tsx b/ts/components/settings/BlockedUserSettings.tsx deleted file mode 100644 index 5b6747aac..000000000 --- a/ts/components/settings/BlockedUserSettings.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -import { useSelector } from 'react-redux'; -import { unblockConvoById } from '../../interactions/conversationInteractions'; -import { getConversationController } from '../../session/conversations'; -import { getBlockedPubkeys } from '../../state/selectors/conversations'; -import { SessionButtonColor } from '../basic/SessionButton'; - -import { SessionSettingButtonItem, SessionSettingsItemWrapper } from './SessionSettingListItem'; - -export const BlockedUserSettings = () => { - const blockedNumbers = useSelector(getBlockedPubkeys); - - if (!blockedNumbers || blockedNumbers.length === 0) { - return ( - - {' '} - - ); - } - const blockedEntries = blockedNumbers.map(blockedEntry => { - const currentModel = getConversationController().get(blockedEntry); - const title = - currentModel?.getNicknameOrRealUsernameOrPlaceholder() || window.i18n('anonymous'); - - return ( - { - await unblockConvoById(blockedEntry); - }} - /> - ); - }); - - return <>{blockedEntries}; -}; diff --git a/ts/components/settings/SessionSettingListItem.tsx b/ts/components/settings/SessionSettingListItem.tsx index a778c5350..52a8ac79e 100644 --- a/ts/components/settings/SessionSettingListItem.tsx +++ b/ts/components/settings/SessionSettingListItem.tsx @@ -33,7 +33,7 @@ export const SessionSettingsItemWrapper = (props: { inline: boolean; title?: string; description?: string; - children: React.ReactNode; + children?: React.ReactNode; }) => { return (
diff --git a/ts/components/settings/SessionSettings.tsx b/ts/components/settings/SessionSettings.tsx index 882043e18..1cf4e65fc 100644 --- a/ts/components/settings/SessionSettings.tsx +++ b/ts/components/settings/SessionSettings.tsx @@ -6,13 +6,15 @@ import { SessionIconButton } from '../icon'; import autoBind from 'auto-bind'; import { SessionNotificationGroupSettings } from './SessionNotificationGroupSettings'; // tslint:disable-next-line: no-submodule-imports -import { BlockedUserSettings } from './BlockedUserSettings'; +import { CategoryConversations } from './section/CategoryConversations'; import { SettingsCategoryPrivacy } from './section/CategoryPrivacy'; import { SettingsCategoryAppearance } from './section/CategoryAppearance'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; import { Data } from '../../data/data'; import { LocalizerKeys } from '../../types/LocalizerKeys'; import { matchesHash } from '../../util/passwordUtils'; +import { SettingsCategoryPermissions } from './section/CategoryPermissions'; +import { SettingsCategoryHelp } from './section/CategoryHelp'; export function getMediaPermissionsSettings() { return window.getSettingValue('media-permissions'); @@ -23,11 +25,17 @@ export function getCallMediaPermissionsSettings() { } export enum SessionSettingCategory { - Appearance = 'appearance', Privacy = 'privacy', Notifications = 'notifications', + + Conversations = 'conversations', MessageRequests = 'messageRequests', - Blocked = 'blocked', + + Appearance = 'appearance', + Permissions = 'permissions', + Help = 'help', + RecoveryPhrase = 'recoveryPhrase', + ClearData = 'ClearData', } export interface SettingsViewProps { @@ -130,28 +138,34 @@ export class SessionSettingsView extends React.Component; - } - - if (category === SessionSettingCategory.Appearance) { - return ; - } - - if (category === SessionSettingCategory.Notifications) { - return ; - } - - if (category === SessionSettingCategory.Privacy) { - return ( - - ); + case SessionSettingCategory.Conversations: + return ; + case SessionSettingCategory.Appearance: + return ; + case SessionSettingCategory.Notifications: + return ; + case SessionSettingCategory.Privacy: + return ( + + ); + case SessionSettingCategory.Help: + return ; + case SessionSettingCategory.Permissions: + return ; + + // those three down there have no options, they are just a button + case SessionSettingCategory.ClearData: + case SessionSettingCategory.MessageRequests: + case SessionSettingCategory.RecoveryPhrase: + default: + return null; } - return null; } public async validatePasswordLock() { @@ -192,7 +206,7 @@ export class SessionSettingsView extends React.Component { - const dispatch = useDispatch(); const forceUpdate = useUpdate(); - const audioAutoPlay = useSelector(getAudioAutoplay); if (props.hasPassword !== null) { const isHideMenuBarActive = @@ -57,16 +16,10 @@ export const SettingsCategoryAppearance = (props: { hasPassword: boolean | null ? true : window.getSettingValue(SettingsKey.settingsMenuBar); - const isSpellCheckActive = - window.getSettingValue(SettingsKey.settingsSpellCheck) === undefined - ? true - : window.getSettingValue(SettingsKey.settingsSpellCheck); - - const isLinkPreviewsOn = Boolean(window.getSettingValue(SettingsKey.settingsLinkPreview)); - const isStartInTrayActive = Boolean(window.getSettingValue(SettingsKey.settingsStartInTray)); - return ( <> + {/* add theme switching here */} + {isHideMenuBarSupported() && ( { @@ -78,71 +31,6 @@ export const SettingsCategoryAppearance = (props: { hasPassword: boolean | null 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')} - /> - {/* { - await fillWithTestData(100, 1000); - }} - buttonColor={SessionButtonColor.Primary} - buttonText={'Spam fill DB using cached'} - /> */} ); } diff --git a/ts/components/settings/section/CategoryConversations.tsx b/ts/components/settings/section/CategoryConversations.tsx new file mode 100644 index 000000000..28a0b5693 --- /dev/null +++ b/ts/components/settings/section/CategoryConversations.tsx @@ -0,0 +1,140 @@ +import React from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import useUpdate from 'react-use/lib/useUpdate'; +import { SettingsKey } from '../../../data/settings-key'; +import { unblockConvoById } from '../../../interactions/conversationInteractions'; +import { getConversationController } from '../../../session/conversations'; +import { ToastUtils } from '../../../session/utils'; +import { toggleAudioAutoplay } from '../../../state/ducks/userConfig'; +import { getBlockedPubkeys } from '../../../state/selectors/conversations'; +import { getAudioAutoplay } from '../../../state/selectors/userConfig'; +import { SessionButtonColor } from '../../basic/SessionButton'; + +import { + SessionSettingButtonItem, + SessionSettingsItemWrapper, + SessionToggleWithDescription, +} from '../SessionSettingListItem'; + +async function toggleCommunitiesPruning() { + try { + const newValue = !(await window.getOpengroupPruning()); + + // 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(SettingsKey.settingsOpengroupPruning, newValue); + await window.setOpengroupPruning(newValue); + ToastUtils.pushRestartNeeded(); + } catch (e) { + window.log.warn('toggleCommunitiesPruning change error:', e); + } +} + +const CommunitiesPruningSetting = () => { + const forceUpdate = useUpdate(); + const isOpengroupPruningEnabled = Boolean( + window.getSettingValue(SettingsKey.settingsOpengroupPruning) + ); + return ( + { + await toggleCommunitiesPruning(); + forceUpdate(); + }} + title={window.i18n('pruneSettingTitle')} + description={window.i18n('pruneSettingDescription')} + active={isOpengroupPruningEnabled} + /> + ); +}; + +const SpellCheckSetting = () => { + const forceUpdate = useUpdate(); + + const isSpellCheckActive = + window.getSettingValue(SettingsKey.settingsSpellCheck) === undefined + ? true + : window.getSettingValue(SettingsKey.settingsSpellCheck); + return ( + { + window.toggleSpellCheck(); + forceUpdate(); + }} + title={window.i18n('spellCheckTitle')} + description={window.i18n('spellCheckDescription')} + active={isSpellCheckActive} + /> + ); +}; + +const AudioMessageAutoPlaySetting = () => { + const audioAutoPlay = useSelector(getAudioAutoplay); + const dispatch = useDispatch(); + const forceUpdate = useUpdate(); + + return ( + { + dispatch(toggleAudioAutoplay()); + forceUpdate(); + }} + title={window.i18n('audioMessageAutoplayTitle')} + description={window.i18n('audioMessageAutoplayDescription')} + active={audioAutoPlay} + /> + ); +}; + +const NoBlockedContacts = () => { + return ( + + ); +}; + +const BlockedEntry = (props: { blockedEntry: string; title: string }) => { + return ( + { + await unblockConvoById(props.blockedEntry); + }} + /> + ); +}; + +const BlockedContactsList = (props: { blockedNumbers: Array }) => { + const blockedEntries = props.blockedNumbers.map(blockedEntry => { + const currentModel = getConversationController().get(blockedEntry); + const title = + currentModel?.getNicknameOrRealUsernameOrPlaceholder() || window.i18n('anonymous'); + + return ; + }); + + return <>{blockedEntries}; +}; + +export const CategoryConversations = () => { + const blockedNumbers = useSelector(getBlockedPubkeys); + + return ( + <> + + + + + {blockedNumbers?.length ? ( + + ) : ( + + )} + + ); +}; diff --git a/ts/components/settings/section/CategoryHelp.tsx b/ts/components/settings/section/CategoryHelp.tsx new file mode 100644 index 000000000..9bbc76362 --- /dev/null +++ b/ts/components/settings/section/CategoryHelp.tsx @@ -0,0 +1,34 @@ +import { ipcRenderer, shell } from 'electron'; +import React from 'react'; +import { SessionButtonColor } from '../../basic/SessionButton'; + +import { SessionSettingButtonItem } from '../SessionSettingListItem'; + +export const SettingsCategoryHelp = (props: { hasPassword: boolean | null }) => { + if (props.hasPassword !== null) { + return ( + <> + 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/settings/section/CategoryPermissions.tsx b/ts/components/settings/section/CategoryPermissions.tsx new file mode 100644 index 000000000..b13bdd36a --- /dev/null +++ b/ts/components/settings/section/CategoryPermissions.tsx @@ -0,0 +1,98 @@ +import React from 'react'; +// tslint:disable-next-line: no-submodule-imports +import useUpdate from 'react-use/lib/useUpdate'; +import { SettingsKey } from '../../../data/settings-key'; +import { CallManager, ToastUtils } from '../../../session/utils'; +import { updateConfirmModal } from '../../../state/ducks/modalDialog'; +import { SessionButtonColor } from '../../basic/SessionButton'; + +import { SessionToggleWithDescription } from '../SessionSettingListItem'; + +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(); + CallManager.onTurnedOnCallMediaPermissions(); + }, + onClickCancel: async () => { + await window.toggleCallMediaPermissionsTo(false); + triggerUIUpdate(); + }, + }) + ); + } else { + await window.toggleCallMediaPermissionsTo(false); + triggerUIUpdate(); + } +}; + +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(SettingsKey.settingsStartInTray, newValue); + await window.setStartInTray(newValue); + if (!newValue) { + ToastUtils.pushRestartNeeded(); + } + } catch (e) { + window.log.warn('start in tray change error:', e); + } +} + +export const SettingsCategoryPermissions = (props: { hasPassword: boolean | null }) => { + const forceUpdate = useUpdate(); + const isStartInTrayActive = Boolean(window.getSettingValue(SettingsKey.settingsStartInTray)); + + 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(SettingsKey.settingsAutoUpdate)); + window.setSettingValue(SettingsKey.settingsAutoUpdate, !old); + forceUpdate(); + }} + title={window.i18n('autoUpdateSettingTitle')} + description={window.i18n('autoUpdateSettingDescription')} + active={Boolean(window.getSettingValue(SettingsKey.settingsAutoUpdate))} + /> + { + await toggleStartInTray(); + forceUpdate(); + }} + title={window.i18n('startInTrayTitle')} + description={window.i18n('startInTrayDescription')} + active={isStartInTrayActive} + /> + + ); + } + return null; +}; diff --git a/ts/components/settings/section/CategoryPrivacy.tsx b/ts/components/settings/section/CategoryPrivacy.tsx index 1922895c0..ed09f259d 100644 --- a/ts/components/settings/section/CategoryPrivacy.tsx +++ b/ts/components/settings/section/CategoryPrivacy.tsx @@ -1,41 +1,14 @@ 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 { Data, hasLinkPreviewPopupBeenDisplayed } from '../../../data/data'; import { SettingsKey } from '../../../data/settings-key'; -import { CallManager, ToastUtils } from '../../../session/utils'; import { sessionPassword, updateConfirmModal } from '../../../state/ducks/modalDialog'; -import { toggleMessageRequests } from '../../../state/ducks/userConfig'; -import { getHideMessageRequestBanner } from '../../../state/selectors/userConfig'; import { SessionButtonColor } from '../../basic/SessionButton'; import { PasswordAction } from '../../dialog/SessionPasswordDialog'; import { SessionSettingButtonItem, SessionToggleWithDescription } from '../SessionSettingListItem'; -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(); - CallManager.onTurnedOnCallMediaPermissions(); - }, - onClickCancel: async () => { - await window.toggleCallMediaPermissionsTo(false); - triggerUIUpdate(); - }, - }) - ); - } else { - await window.toggleCallMediaPermissionsTo(false); - triggerUIUpdate(); - } -}; - function displayPasswordModal( passwordAction: PasswordAction, onPasswordUpdated: (action: string) => void @@ -50,16 +23,19 @@ function displayPasswordModal( ); } -async function toggleOpengroupPruning() { - try { - const newValue = !(await window.getOpengroupPruning()); - - // 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(SettingsKey.settingsOpengroupPruning, newValue); - await window.setOpengroupPruning(newValue); - ToastUtils.pushRestartNeeded(); - } catch (e) { - window.log.warn('toggleOpengroupPruning change error:', e); +async function toggleLinkPreviews() { + const newValue = !window.getSettingValue(SettingsKey.settingsLinkPreview); + window.setSettingValue(SettingsKey.settingsLinkPreview, newValue); + if (!newValue) { + await Data.createOrUpdateItem({ id: hasLinkPreviewPopupBeenDisplayed, value: false }); + } else { + window.inboxStore?.dispatch( + updateConfirmModal({ + title: window.i18n('linkPreviewsTitle'), + message: window.i18n('linkPreviewsConfirmMessage'), + okTheme: SessionButtonColor.Danger, + }) + ); } } @@ -68,32 +44,11 @@ export const SettingsCategoryPrivacy = (props: { onPasswordUpdated: (action: string) => void; }) => { const forceUpdate = useUpdate(); - const dispatch = useDispatch(); - const isOpengroupPruningEnabled = Boolean( - window.getSettingValue(SettingsKey.settingsOpengroupPruning) - ); + const isLinkPreviewsOn = Boolean(window.getSettingValue(SettingsKey.settingsLinkPreview)); + 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(SettingsKey.settingsReadReceipt)); @@ -114,33 +69,16 @@ export const SettingsCategoryPrivacy = (props: { description={window.i18n('typingIndicatorsSettingDescription')} active={Boolean(window.getSettingValue(SettingsKey.settingsTypingIndicator))} /> - { - const old = Boolean(window.getSettingValue(SettingsKey.settingsAutoUpdate)); - window.setSettingValue(SettingsKey.settingsAutoUpdate, !old); - forceUpdate(); - }} - title={window.i18n('autoUpdateSettingTitle')} - description={window.i18n('autoUpdateSettingDescription')} - active={Boolean(window.getSettingValue(SettingsKey.settingsAutoUpdate))} - /> - { - dispatch(toggleMessageRequests()); - }} - title={window.i18n('hideRequestBanner')} - description={window.i18n('hideRequestBannerDescription')} - active={useSelector(getHideMessageRequestBanner)} - /> { - await toggleOpengroupPruning(); + await toggleLinkPreviews(); forceUpdate(); }} - title={window.i18n('pruneSettingTitle')} - description={window.i18n('pruneSettingDescription')} - active={isOpengroupPruningEnabled} + title={window.i18n('linkPreviewsTitle')} + description={window.i18n('linkPreviewDescription')} + active={isLinkPreviewsOn} /> + {!props.hasPassword && (