diff --git a/stylesheets/components/Preferences.scss b/stylesheets/components/Preferences.scss index a1908ccc462..0ce59b0faf7 100644 --- a/stylesheets/components/Preferences.scss +++ b/stylesheets/components/Preferences.scss @@ -34,6 +34,19 @@ $secondary-text-color: light-dark( } &__header { + display: flex; + flex-direction: row; + } + + &__header__toggle { + flex-grow: 0; + min-width: 80px; + width: 80px; + margin-inline-end: -24px; + } + + &__header__text { + flex-grow: 1; margin-inline-start: 24px; @include mixins.font-title-medium; line-height: 20px; diff --git a/ts/components/Preferences.stories.tsx b/ts/components/Preferences.stories.tsx index d0724b62b87..6cf13a97a13 100644 --- a/ts/components/Preferences.stories.tsx +++ b/ts/components/Preferences.stories.tsx @@ -137,6 +137,7 @@ export default { hasCallRingtoneNotification: false, hasContentProtection: false, hasCountMutedConversations: false, + hasFailedStorySends: false, hasHideMenuBar: false, hasIncomingCallNotifications: true, hasLinkPreviews: true, @@ -168,7 +169,13 @@ export default { isUpdateDownloaded: false, lastSyncTime: Date.now(), localeOverride: null, + navTabsCollapsed: false, notificationContent: 'name', + otherTabsUnreadStats: { + unreadCount: 0, + unreadMentionsCount: 0, + markedUnread: false, + }, preferredSystemLocales: ['en'], resolvedLocale: 'en', selectedCamera: @@ -239,6 +246,7 @@ export default { onStartUpdate: action('onStartUpdate'), onTextFormattingChange: action('onTextFormattingChange'), onThemeChange: action('onThemeChange'), + onToggleNavTabsCollapse: action('onToggleNavTabsCollapse'), onUniversalExpireTimerChange: action('onUniversalExpireTimerChange'), onWhoCanSeeMeChange: action('onWhoCanSeeMeChange'), onWhoCanFindMeChange: action('onWhoCanFindMeChange'), @@ -386,3 +394,30 @@ export const UpdateDownloaded = Template.bind({}); UpdateDownloaded.args = { isUpdateDownloaded: true, }; + +export const NavTabsCollapsed = Template.bind({}); +NavTabsCollapsed.args = { + navTabsCollapsed: true, +}; + +export const NavTabsCollapsedWithBadges = Template.bind({}); +NavTabsCollapsedWithBadges.args = { + navTabsCollapsed: true, + hasFailedStorySends: false, + otherTabsUnreadStats: { + unreadCount: 1, + unreadMentionsCount: 2, + markedUnread: false, + }, +}; + +export const NavTabsCollapsedWithExclamation = Template.bind({}); +NavTabsCollapsedWithExclamation.args = { + navTabsCollapsed: true, + hasFailedStorySends: true, + otherTabsUnreadStats: { + unreadCount: 1, + unreadMentionsCount: 2, + markedUnread: true, + }, +}; diff --git a/ts/components/Preferences.tsx b/ts/components/Preferences.tsx index 6cf97690a55..8023787578b 100644 --- a/ts/components/Preferences.tsx +++ b/ts/components/Preferences.tsx @@ -74,6 +74,8 @@ import { PreferencesBackups } from './PreferencesBackups'; import { PreferencesInternal } from './PreferencesInternal'; import { FunEmojiLocalizationProvider } from './fun/FunEmojiLocalizationProvider'; import type { ValidateLocalBackupStructureResultType } from '../services/backups/util/localBackup'; +import { NavTabsToggle } from './NavTabs'; +import type { UnreadStats } from '../util/countUnreadStats'; type CheckboxChangeHandlerType = (value: boolean) => unknown; type SelectChangeHandlerType = (value: T) => unknown; @@ -134,9 +136,12 @@ export type PropsDataType = { resolvedLocale: string; // Other props + hasFailedStorySends: boolean; hasPendingUpdate: boolean; initialSpellCheckSetting: boolean; isUpdateDownloaded: boolean; + navTabsCollapsed: boolean; + otherTabsUnreadStats: UnreadStats; // Limited support features isAutoDownloadUpdatesSupported: boolean; @@ -220,6 +225,7 @@ type PropsFunctionType = { onSpellCheckChange: CheckboxChangeHandlerType; onTextFormattingChange: CheckboxChangeHandlerType; onThemeChange: SelectChangeHandlerType; + onToggleNavTabsCollapse: (navTabsCollapsed: boolean) => void; onUniversalExpireTimerChange: SelectChangeHandlerType; onWhoCanSeeMeChange: SelectChangeHandlerType; onWhoCanFindMeChange: SelectChangeHandlerType; @@ -305,6 +311,7 @@ export function Preferences({ hasCallRingtoneNotification, hasContentProtection, hasCountMutedConversations, + hasFailedStorySends, hasHideMenuBar, hasIncomingCallNotifications, hasLinkPreviews, @@ -339,6 +346,7 @@ export function Preferences({ isUpdateDownloaded, lastSyncTime, makeSyncRequest, + navTabsCollapsed, notificationContent, onAudioNotificationsChange, onAutoConvertEmojiChange, @@ -371,10 +379,12 @@ export function Preferences({ onSpellCheckChange, onTextFormattingChange, onThemeChange, + onToggleNavTabsCollapse, onUniversalExpireTimerChange, onWhoCanSeeMeChange, onWhoCanFindMeChange, onZoomFactorChange, + otherTabsUnreadStats, phoneNumber = '', preferredSystemLocales, refreshCloudBackupStatus, @@ -1837,9 +1847,23 @@ export function Preferences({
-

- {i18n('icu:Preferences--header')} -

+
+ {navTabsCollapsed ? ( +
+ +
+ ) : undefined} +

+ {i18n('icu:Preferences--header')} +

+
{maybeUpdateDialog ? (
{maybeUpdateDialog}
) : null} diff --git a/ts/state/smart/Preferences.tsx b/ts/state/smart/Preferences.tsx index 628354677d7..2a9cefddf9b 100644 --- a/ts/state/smart/Preferences.tsx +++ b/ts/state/smart/Preferences.tsx @@ -8,7 +8,11 @@ import type { AudioDevice } from '@signalapp/ringrtc'; import { useItemsActions } from '../ducks/items'; import { useConversationsActions } from '../ducks/conversations'; import { getConversationsWithCustomColorSelector } from '../selectors/conversations'; -import { getCustomColors, getItems } from '../selectors/items'; +import { + getCustomColors, + getItems, + getNavTabsCollapsed, +} from '../selectors/items'; import { DEFAULT_AUTO_DOWNLOAD_ATTACHMENT } from '../../textsecure/Storage'; import { DEFAULT_CONVERSATION_COLOR } from '../../types/Colors'; import { isBackupFeatureEnabledForRedux } from '../../util/isBackupEnabled'; @@ -49,6 +53,8 @@ import { getHasPendingUpdate, isUpdateDownloaded as getIsUpdateDownloaded, } from '../selectors/updates'; +import { getHasAnyFailedStorySends } from '../selectors/stories'; +import { getOtherTabsUnreadStats } from '../selectors/nav'; const DEFAULT_NOTIFICATION_SETTING = 'message'; @@ -94,6 +100,7 @@ export function SmartPreferences(): JSX.Element { resetDefaultChatColor, setEmojiSkinToneDefault: onEmojiSkinToneDefaultChange, setGlobalDefaultConversationColor, + toggleNavTabsCollapse, } = useItemsActions(); const { removeCustomColorOnConversations, resetAllChatColors } = useConversationsActions(); @@ -109,6 +116,9 @@ export function SmartPreferences(): JSX.Element { const i18n = useSelector(getIntl); const hasPendingUpdate = useSelector(getHasPendingUpdate); const isUpdateDownloaded = useSelector(getIsUpdateDownloaded); + const navTabsCollapsed = useSelector(getNavTabsCollapsed); + const hasFailedStorySends = useSelector(getHasAnyFailedStorySends); + const otherTabsUnreadStats = useSelector(getOtherTabsUnreadStats); // The weird ones @@ -604,6 +614,7 @@ export function SmartPreferences(): JSX.Element { hasCallRingtoneNotification={hasCallRingtoneNotification} hasContentProtection={hasContentProtection} hasCountMutedConversations={hasCountMutedConversations} + hasFailedStorySends={hasFailedStorySends} hasHideMenuBar={hasHideMenuBar} hasIncomingCallNotifications={hasIncomingCallNotifications} hasLinkPreviews={hasLinkPreviews} @@ -640,6 +651,7 @@ export function SmartPreferences(): JSX.Element { lastSyncTime={lastSyncTime} localeOverride={localeOverride} makeSyncRequest={makeSyncRequest} + navTabsCollapsed={navTabsCollapsed} notificationContent={notificationContent} onAudioNotificationsChange={onAudioNotificationsChange} onAutoConvertEmojiChange={onAutoConvertEmojiChange} @@ -675,10 +687,12 @@ export function SmartPreferences(): JSX.Element { onSpellCheckChange={onSpellCheckChange} onTextFormattingChange={onTextFormattingChange} onThemeChange={onThemeChange} + onToggleNavTabsCollapse={toggleNavTabsCollapse} onUniversalExpireTimerChange={onUniversalExpireTimerChange} onWhoCanFindMeChange={onWhoCanFindMeChange} onWhoCanSeeMeChange={onWhoCanSeeMeChange} onZoomFactorChange={onZoomFactorChange} + otherTabsUnreadStats={otherTabsUnreadStats} preferredSystemLocales={preferredSystemLocales} refreshCloudBackupStatus={refreshCloudBackupStatus} refreshBackupSubscriptionStatus={refreshBackupSubscriptionStatus}