mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2025-12-19 17:58:48 +00:00
Settings Tab: Educate user about change to bottom-left profile icon
This commit is contained in:
@@ -5272,6 +5272,15 @@
|
||||
"messageformat": "Tap on \"Donate to Signal\" and subscribe",
|
||||
"description": "In the instructions for becoming a sustainer. Third instruction."
|
||||
},
|
||||
"icu:ProfileMovedModal__title": {
|
||||
"messageformat": "Your profile has moved",
|
||||
"description": "Bolded text on modal that explains the move of Profile Editor into the new Settings Tab"
|
||||
},
|
||||
"icu:ProfileMovedModal__description": {
|
||||
"messageformat": "Open the Settings tab to view and edit your profile.",
|
||||
"description": "Description text on modal that explains the move of Profile Editor into the new Settings Tab"
|
||||
},
|
||||
|
||||
"icu:BackupImportScreen__title": {
|
||||
"messageformat": "Syncing messages",
|
||||
"description": "Title of backup import screen"
|
||||
|
||||
1
images/profile-moved-dark.svg
Normal file
1
images/profile-moved-dark.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="200" height="150" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#settings-moved-dark__a)"><g filter="url(#settings-moved-dark__b)"><path d="M56 0h128c8.837 0 16 7.163 16 16v101H72c-8.837 0-16-7.163-16-16V0Z" fill="color(display-p3 .4531 .4887 .6451)"/></g><path d="M63 82c0-5.523 4.477-10 10-10h28c5.523 0 10 4.477 10 10v18c0 5.523-4.477 10-10 10H73c-5.523 0-10-4.477-10-10V82Z" fill="color(display-p3 .5608 .5922 .7294)"/><path fill-rule="evenodd" clip-rule="evenodd" d="M85.836 82.284c-.55 0-1.036.36-1.196.887l-.398 1.31a.417.417 0 0 1-.19.24l-1.016.586a.417.417 0 0 1-.303.045l-1.334-.31a1.25 1.25 0 0 0-1.365.592L78.87 87.65a1.25 1.25 0 0 0 .17 1.48l.936 1a.417.417 0 0 1 .112.284v1.172c0 .106-.04.208-.112.285l-.936 1a1.25 1.25 0 0 0-.17 1.48l1.163 2.015c.276.477.83.717 1.367.592l1.333-.31a.417.417 0 0 1 .303.045l1.016.586c.091.053.16.139.19.24l.398 1.31c.16.527.646.887 1.196.887h2.328c.55 0 1.036-.36 1.196-.887l.398-1.31a.417.417 0 0 1 .19-.24l1.016-.586a.416.416 0 0 1 .302-.045l1.334.31a1.25 1.25 0 0 0 1.366-.592l1.164-2.016a1.25 1.25 0 0 0-.17-1.479l-.936-1a.417.417 0 0 1-.112-.285v-1.172c0-.106.04-.208.112-.285l.936-1a1.25 1.25 0 0 0 .17-1.48l-1.164-2.015a1.25 1.25 0 0 0-1.366-.592l-1.334.31a.416.416 0 0 1-.303-.045l-1.015-.586a.417.417 0 0 1-.19-.24l-.398-1.31a1.25 1.25 0 0 0-1.196-.887h-2.328ZM83.666 91a3.333 3.333 0 1 1 6.667 0 3.333 3.333 0 0 1-6.666 0Z" fill="color(display-p3 .9569 .9608 .9725)"/><path d="M118 0v116h-1V0h1Z" fill="color(display-p3 .5255 .5569 .702)"/><path d="M57 101c0 8.284 6.716 15 15 15h128v1H72l-.413-.005c-8.509-.216-15.367-7.074-15.582-15.582L56 101V0h1v101Z" fill="color(display-p3 .5255 .5569 .702)"/></g><defs><clipPath id="settings-moved-dark__a"><rect width="200" height="150" rx="16" fill="#fff"/></clipPath><filter id="settings-moved-dark__b" x="24" y="-24" width="208" height="181" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/><feOffset dy="8"/><feGaussianBlur stdDeviation="16"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0"/><feBlend in2="BackgroundImageFix" result="effect1_dropShadow_291_3997"/><feBlend in="SourceGraphic" in2="effect1_dropShadow_291_3997" result="shape"/></filter></defs></svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
1
images/profile-moved.svg
Normal file
1
images/profile-moved.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="200" height="150" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#settings-moved__a)"><g filter="url(#settings-moved__b)"><path d="M56 0h128c8.837 0 16 7.163 16 16v101H72c-8.837 0-16-7.163-16-16V0Z" fill="color(display-p3 .8902 .9098 .9961)"/></g><path d="M63 82c0-5.523 4.477-10 10-10h28c5.523 0 10 4.477 10 10v18c0 5.523-4.477 10-10 10H73c-5.523 0-10-4.477-10-10V82Z" fill="color(display-p3 .7843 .8039 .9569)"/><path fill-rule="evenodd" clip-rule="evenodd" d="M85.836 82.284c-.55 0-1.036.36-1.196.887l-.398 1.31a.417.417 0 0 1-.19.24l-1.016.586a.417.417 0 0 1-.303.045l-1.334-.31a1.25 1.25 0 0 0-1.365.592L78.87 87.65a1.25 1.25 0 0 0 .17 1.48l.936 1a.417.417 0 0 1 .112.284v1.172c0 .106-.04.208-.112.285l-.936 1a1.25 1.25 0 0 0-.17 1.48l1.163 2.015c.276.477.83.717 1.367.592l1.333-.31a.417.417 0 0 1 .303.045l1.016.586c.091.053.16.139.19.24l.398 1.31c.16.527.646.887 1.196.887h2.328c.55 0 1.036-.36 1.196-.887l.398-1.31a.417.417 0 0 1 .19-.24l1.016-.586a.416.416 0 0 1 .302-.045l1.334.31a1.25 1.25 0 0 0 1.366-.592l1.164-2.016a1.25 1.25 0 0 0-.17-1.479l-.936-1a.417.417 0 0 1-.112-.285v-1.172c0-.106.04-.208.112-.285l.936-1a1.25 1.25 0 0 0 .17-1.48l-1.164-2.015a1.25 1.25 0 0 0-1.366-.592l-1.334.31a.416.416 0 0 1-.303-.045l-1.015-.586a.417.417 0 0 1-.19-.24l-.398-1.31a1.25 1.25 0 0 0-1.196-.887h-2.328ZM83.666 91a3.333 3.333 0 1 1 6.667 0 3.333 3.333 0 0 1-6.666 0Z" fill="color(display-p3 .0068 .0431 .6732)"/><path d="M118 0v116h-1V0h1Z" fill="color(display-p3 .7137 .7373 .9333)"/><path d="M57 101c0 8.284 6.716 15 15 15h128v1H72l-.413-.005c-8.509-.216-15.367-7.074-15.582-15.582L56 101V0h1v101Z" fill="color(display-p3 .7137 .7373 .9333)"/></g><defs><clipPath id="settings-moved__a"><rect width="200" height="150" rx="16" fill="#fff"/></clipPath><filter id="settings-moved__b" x="24" y="-24" width="208" height="181" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/><feOffset dy="8"/><feGaussianBlur stdDeviation="16"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0"/><feBlend in2="BackgroundImageFix" result="effect1_dropShadow_281_3958"/><feBlend in="SourceGraphic" in2="effect1_dropShadow_281_3958" result="shape"/></filter></defs></svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -25,6 +25,7 @@ $NavTabs__ProfileAvatar__size: 28px;
|
||||
width: variables.$NavTabs__width;
|
||||
height: 100%;
|
||||
padding-top: var(--title-bar-drag-area-height);
|
||||
padding-bottom: 8px;
|
||||
@include mixins.light-theme {
|
||||
background-color: variables.$color-gray-04;
|
||||
border-inline-end: 1px solid variables.$color-black-alpha-16;
|
||||
@@ -240,7 +241,6 @@ $NavTabs__ProfileAvatar__size: 28px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.NavTabs__TabPanel {
|
||||
|
||||
37
stylesheets/components/ProfileMovedModal.scss
Normal file
37
stylesheets/components/ProfileMovedModal.scss
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2014 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
@use '../mixins';
|
||||
@use '../variables';
|
||||
|
||||
.ProfileMovedModal {
|
||||
width: 300px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ProfileMovedModal__image {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.ProfileMovedModal__title {
|
||||
@include mixins.font-body-1-bold;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.ProfileMovedModal__description {
|
||||
margin-bottom: 20px;
|
||||
margin-inline-start: 16px;
|
||||
margin-inline-end: 16px;
|
||||
|
||||
@include mixins.light-theme {
|
||||
color: variables.$color-black-alpha-50;
|
||||
}
|
||||
@include mixins.dark-theme {
|
||||
color: variables.$color-white-alpha-50;
|
||||
}
|
||||
}
|
||||
|
||||
.ProfileMovedModal__button {
|
||||
min-width: 236px;
|
||||
}
|
||||
@@ -144,6 +144,7 @@
|
||||
@use 'components/PlaybackRateButton.scss';
|
||||
@use 'components/Preferences.scss';
|
||||
@use 'components/ProfileEditor.scss';
|
||||
@use 'components/ProfileMovedModal.scss';
|
||||
@use 'components/ProfileNameWarningModal.scss';
|
||||
@use 'components/ProgressBar.scss';
|
||||
@use 'components/ProgressCircle.scss';
|
||||
|
||||
@@ -992,6 +992,13 @@ export async function startApp(): Promise<void> {
|
||||
if (window.isBeforeVersion(lastVersion, 'v7.56.0-beta.1')) {
|
||||
await window.storage.remove('backupMediaDownloadIdle');
|
||||
}
|
||||
|
||||
if (
|
||||
window.isBeforeVersion(lastVersion, 'v7.57.0') &&
|
||||
window.storage.get('needProfileMovedModal') === undefined
|
||||
) {
|
||||
await window.storage.put('needProfileMovedModal', true);
|
||||
}
|
||||
}
|
||||
|
||||
setAppLoadingScreenMessage(
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { Key, ReactNode } from 'react';
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { Tabs, TabList, Tab, TabPanel } from 'react-aria-components';
|
||||
import classNames from 'classnames';
|
||||
import { Avatar, AvatarSize } from './Avatar';
|
||||
@@ -16,6 +16,7 @@ import { Theme } from '../util/theme';
|
||||
import type { UnreadStats } from '../util/countUnreadStats';
|
||||
import { Page } from './Preferences';
|
||||
import { EditState } from './ProfileEditor';
|
||||
import { ProfileMovedModal } from './ProfileMovedModal';
|
||||
|
||||
type NavTabsItemBadgesProps = Readonly<{
|
||||
i18n: LocalizerType;
|
||||
@@ -199,7 +200,9 @@ export type NavTabsProps = Readonly<{
|
||||
me: ConversationType;
|
||||
navTabsCollapsed: boolean;
|
||||
onChangeLocation: (location: Location) => void;
|
||||
onDismissProfileMovedModal: () => void;
|
||||
onToggleNavTabsCollapse: (collapsed: boolean) => void;
|
||||
profileMovedModalNeeded: boolean;
|
||||
renderCallsTab: () => ReactNode;
|
||||
renderChatsTab: () => ReactNode;
|
||||
renderStoriesTab: () => ReactNode;
|
||||
@@ -221,7 +224,9 @@ export function NavTabs({
|
||||
me,
|
||||
navTabsCollapsed,
|
||||
onChangeLocation,
|
||||
onDismissProfileMovedModal,
|
||||
onToggleNavTabsCollapse,
|
||||
profileMovedModalNeeded,
|
||||
renderCallsTab,
|
||||
renderChatsTab,
|
||||
renderStoriesTab,
|
||||
@@ -234,6 +239,9 @@ export function NavTabs({
|
||||
unreadConversationsStats,
|
||||
unreadStoriesCount,
|
||||
}: NavTabsProps): JSX.Element {
|
||||
const [showingProfileMovedModal, setShowingProfileMovedModal] =
|
||||
useState(false);
|
||||
|
||||
function handleSelectionChange(key: Key) {
|
||||
const tab = key as NavTab;
|
||||
if (tab === NavTab.Settings) {
|
||||
@@ -258,6 +266,17 @@ export function NavTabs({
|
||||
selectedKey={selectedNavTab}
|
||||
onSelectionChange={handleSelectionChange}
|
||||
>
|
||||
{showingProfileMovedModal ? (
|
||||
<ProfileMovedModal
|
||||
i18n={i18n}
|
||||
onClose={() => {
|
||||
setShowingProfileMovedModal(false);
|
||||
handleSelectionChange(NavTab.Settings);
|
||||
onDismissProfileMovedModal();
|
||||
}}
|
||||
theme={theme}
|
||||
/>
|
||||
) : undefined}
|
||||
<nav
|
||||
data-supertab
|
||||
className={classNames('NavTabs', {
|
||||
@@ -329,7 +348,11 @@ export function NavTabs({
|
||||
type="button"
|
||||
className="NavTabs__Item NavTabs__Item--Profile"
|
||||
onClick={() => {
|
||||
handleSelectionChange(NavTab.Settings);
|
||||
if (profileMovedModalNeeded) {
|
||||
setShowingProfileMovedModal(true);
|
||||
} else {
|
||||
handleSelectionChange(NavTab.Settings);
|
||||
}
|
||||
}}
|
||||
aria-label={i18n('icu:NavTabs__ItemLabel--Profile')}
|
||||
>
|
||||
|
||||
29
ts/components/ProfileMovedModal.stories.tsx
Normal file
29
ts/components/ProfileMovedModal.stories.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React from 'react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
|
||||
import type { ComponentProps } from 'react';
|
||||
import type { Meta } from '@storybook/react';
|
||||
|
||||
import { ProfileMovedModal } from './ProfileMovedModal';
|
||||
import { ThemeType } from '../types/Util';
|
||||
|
||||
import type { PropsType } from './ProfileMovedModal';
|
||||
|
||||
const { i18n } = window.SignalContext;
|
||||
|
||||
export default {
|
||||
title: 'Components/ProfileMovedModal',
|
||||
} satisfies Meta<PropsType>;
|
||||
|
||||
const defaultProps: ComponentProps<typeof ProfileMovedModal> = {
|
||||
i18n,
|
||||
theme: ThemeType.light,
|
||||
onClose: action('onClose'),
|
||||
};
|
||||
|
||||
export function Default(): JSX.Element {
|
||||
return <ProfileMovedModal {...defaultProps} />;
|
||||
}
|
||||
53
ts/components/ProfileMovedModal.tsx
Normal file
53
ts/components/ProfileMovedModal.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Modal } from './Modal';
|
||||
import { Button } from './Button';
|
||||
import { ThemeType } from '../types/Util';
|
||||
|
||||
import type { LocalizerType } from '../types/Util';
|
||||
|
||||
export type PropsType = Readonly<{
|
||||
i18n: LocalizerType;
|
||||
onClose: () => unknown;
|
||||
theme: ThemeType;
|
||||
}>;
|
||||
|
||||
export function ProfileMovedModal({
|
||||
i18n,
|
||||
onClose,
|
||||
theme,
|
||||
}: PropsType): JSX.Element {
|
||||
const imagePath =
|
||||
theme === ThemeType.dark
|
||||
? 'images/profile-moved-dark.svg'
|
||||
: 'images/profile-moved.svg';
|
||||
|
||||
return (
|
||||
<Modal
|
||||
modalName="ProfileMovedModal"
|
||||
moduleClassName="ProfileMovedModal"
|
||||
i18n={i18n}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className="ProfileMovedModal__contents">
|
||||
<div className="ProfileMovedModal__main">
|
||||
<div className="ProfileMovedModal__image">
|
||||
<img src={imagePath} height="150" width="200" alt="" />
|
||||
</div>
|
||||
<div className="ProfileMovedModal__title">
|
||||
{i18n('icu:ProfileMovedModal__title')}
|
||||
</div>
|
||||
<div className="ProfileMovedModal__description">
|
||||
{i18n('icu:ProfileMovedModal__description')}
|
||||
</div>
|
||||
</div>
|
||||
<Button className="ProfileMovedModal__button" onClick={onClose}>
|
||||
{i18n('icu:ok')}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -34,6 +34,12 @@ export const getAreWeASubscriber = createSelector(
|
||||
Boolean(areWeASubscriber)
|
||||
);
|
||||
|
||||
export const getProfileMovedModalNeeded = createSelector(
|
||||
getItems,
|
||||
({ needProfileMovedModal }: Readonly<ItemsStateType>): boolean =>
|
||||
Boolean(needProfileMovedModal)
|
||||
);
|
||||
|
||||
export const getUserAgent = createSelector(
|
||||
getItems,
|
||||
(state: ItemsStateType): string => state.userAgent as string
|
||||
|
||||
@@ -15,13 +15,17 @@ import {
|
||||
getHasAnyFailedStorySends,
|
||||
getStoriesNotificationCount,
|
||||
} from '../selectors/stories';
|
||||
import { getStoriesEnabled } from '../selectors/items';
|
||||
import {
|
||||
getProfileMovedModalNeeded,
|
||||
getStoriesEnabled,
|
||||
} from '../selectors/items';
|
||||
import { getSelectedNavTab } from '../selectors/nav';
|
||||
import type { Location } from '../ducks/nav';
|
||||
import { useNavActions } from '../ducks/nav';
|
||||
import { getHasPendingUpdate } from '../selectors/updates';
|
||||
import { getCallHistoryUnreadCount } from '../selectors/callHistory';
|
||||
import { Environment } from '../../environment';
|
||||
import { useItemsActions } from '../ducks/items';
|
||||
|
||||
export type SmartNavTabsProps = Readonly<{
|
||||
navTabsCollapsed: boolean;
|
||||
@@ -42,7 +46,6 @@ export const SmartNavTabs = memo(function SmartNavTabs({
|
||||
}: SmartNavTabsProps): JSX.Element {
|
||||
const i18n = useSelector(getIntl);
|
||||
const selectedNavTab = useSelector(getSelectedNavTab);
|
||||
const { changeLocation } = useNavActions();
|
||||
const me = useSelector(getMe);
|
||||
const badge = useSelector(getPreferredBadgeSelector)(me.badges);
|
||||
const theme = useSelector(getTheme);
|
||||
@@ -52,10 +55,21 @@ export const SmartNavTabs = memo(function SmartNavTabs({
|
||||
const unreadCallsCount = useSelector(getCallHistoryUnreadCount);
|
||||
const hasFailedStorySends = useSelector(getHasAnyFailedStorySends);
|
||||
const hasPendingUpdate = useSelector(getHasPendingUpdate);
|
||||
const profileMovedModalNeeded = useSelector(getProfileMovedModalNeeded);
|
||||
const isNightly = useSelector(getIsNightly);
|
||||
|
||||
const { changeLocation } = useNavActions();
|
||||
const { putItem } = useItemsActions();
|
||||
|
||||
const shouldShowProfileIcon =
|
||||
useSelector(getIsNightly) ||
|
||||
profileMovedModalNeeded ||
|
||||
isNightly ||
|
||||
window.SignalContext.getEnvironment() !== Environment.PackagedApp;
|
||||
|
||||
const onDismissProfileMovedModal = useCallback(() => {
|
||||
putItem('needProfileMovedModal', false);
|
||||
}, [putItem]);
|
||||
|
||||
const onChangeLocation = useCallback(
|
||||
(location: Location) => {
|
||||
// For some reason react-aria will call this more often than the tab
|
||||
@@ -77,6 +91,8 @@ export const SmartNavTabs = memo(function SmartNavTabs({
|
||||
navTabsCollapsed={navTabsCollapsed}
|
||||
onChangeLocation={onChangeLocation}
|
||||
onToggleNavTabsCollapse={onToggleNavTabsCollapse}
|
||||
profileMovedModalNeeded={profileMovedModalNeeded}
|
||||
onDismissProfileMovedModal={onDismissProfileMovedModal}
|
||||
renderCallsTab={renderCallsTab}
|
||||
renderChatsTab={renderChatsTab}
|
||||
renderStoriesTab={renderStoriesTab}
|
||||
|
||||
1
ts/types/Storage.d.ts
vendored
1
ts/types/Storage.d.ts
vendored
@@ -201,6 +201,7 @@ export type StorageAccessType = {
|
||||
};
|
||||
serverAlerts: ServerAlertsType;
|
||||
needOrphanedAttachmentCheck: boolean;
|
||||
needProfileMovedModal: boolean;
|
||||
notificationProfileOverride: NotificationProfileOverride | undefined;
|
||||
observedCapabilities: {
|
||||
deleteSync?: true;
|
||||
|
||||
Reference in New Issue
Block a user