diff --git a/ts/components/GroupDialog.tsx b/ts/components/GroupDialog.tsx index 6c04eb821b..e675e677c9 100644 --- a/ts/components/GroupDialog.tsx +++ b/ts/components/GroupDialog.tsx @@ -4,8 +4,9 @@ import type { ReactChild, ReactNode } from 'react'; import React from 'react'; -import type { LocalizerType } from '../types/Util'; +import type { LocalizerType, ThemeType } from '../types/Util'; import type { ConversationType } from '../state/ducks/conversations'; +import type { PreferredBadgeSelectorType } from '../state/selectors/badges'; import { ModalHost } from './ModalHost'; import { Button, ButtonVariant } from './Button'; import { Avatar, AvatarSize } from './Avatar'; @@ -92,20 +93,29 @@ GroupDialog.Paragraph = ({ type ContactsPropsType = { contacts: Array; + getPreferredBadge: PreferredBadgeSelectorType; i18n: LocalizerType; + theme: ThemeType; }; -GroupDialog.Contacts = ({ contacts, i18n }: Readonly) => ( +GroupDialog.Contacts = ({ + contacts, + getPreferredBadge, + i18n, + theme, +}: Readonly) => (
    {contacts.map(contact => (
  • = {}): PropsType => ({ booleanOr(overrideProps.areWeInvited, false) ), droppedMembers: overrideProps.droppedMembers || [contact3, contact1], + getPreferredBadge: () => undefined, hasMigrated: boolean( 'hasMigrated', booleanOr(overrideProps.hasMigrated, false) @@ -52,6 +54,7 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ invitedMembers: overrideProps.invitedMembers || [contact2], migrate: action('migrate'), onClose: action('onClose'), + theme: ThemeType.light, }); const stories = storiesOf('Components/GroupV1MigrationDialog', module); diff --git a/ts/components/GroupV1MigrationDialog.tsx b/ts/components/GroupV1MigrationDialog.tsx index c95b01f253..96ae9dabae 100644 --- a/ts/components/GroupV1MigrationDialog.tsx +++ b/ts/components/GroupV1MigrationDialog.tsx @@ -1,9 +1,10 @@ -// Copyright 2019-2020 Signal Messenger, LLC +// Copyright 2019-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import type { LocalizerType } from '../types/Util'; +import type { LocalizerType, ThemeType } from '../types/Util'; import type { ConversationType } from '../state/ducks/conversations'; +import type { PreferredBadgeSelectorType } from '../state/selectors/badges'; import { GroupDialog } from './GroupDialog'; import { sortByTitle } from '../util/sortByTitle'; @@ -19,7 +20,9 @@ export type DataPropsType = { }; export type HousekeepingPropsType = { + readonly getPreferredBadge: PreferredBadgeSelectorType; readonly i18n: LocalizerType; + readonly theme: ThemeType; }; export type PropsType = DataPropsType & HousekeepingPropsType; @@ -29,11 +32,13 @@ export const GroupV1MigrationDialog: React.FunctionComponent = const { areWeInvited, droppedMembers, + getPreferredBadge, hasMigrated, i18n, invitedMembers, migrate, onClose, + theme, } = props; const title = hasMigrated @@ -84,23 +89,39 @@ export const GroupV1MigrationDialog: React.FunctionComponent = ) : ( <> - {renderMembers( - invitedMembers, - 'GroupV1--Migration--info--invited', - i18n - )} - {renderMembers(droppedMembers, droppedMembersKey, i18n)} + {renderMembers({ + getPreferredBadge, + i18n, + members: invitedMembers, + prefix: 'GroupV1--Migration--info--invited', + theme, + })} + {renderMembers({ + getPreferredBadge, + i18n, + members: droppedMembers, + prefix: droppedMembersKey, + theme, + })} )} ); }); -function renderMembers( - members: Array, - prefix: string, - i18n: LocalizerType -): React.ReactNode { +function renderMembers({ + getPreferredBadge, + i18n, + members, + prefix, + theme, +}: Readonly<{ + getPreferredBadge: PreferredBadgeSelectorType; + i18n: LocalizerType; + members: Array; + prefix: string; + theme: ThemeType; +}>): React.ReactNode { if (!members.length) { return null; } @@ -111,7 +132,12 @@ function renderMembers( return ( <> {i18n(key)} - + ); } diff --git a/ts/components/NewlyCreatedGroupInvitedContactsDialog.stories.tsx b/ts/components/NewlyCreatedGroupInvitedContactsDialog.stories.tsx index 110f44f54a..88efc68b2e 100644 --- a/ts/components/NewlyCreatedGroupInvitedContactsDialog.stories.tsx +++ b/ts/components/NewlyCreatedGroupInvitedContactsDialog.stories.tsx @@ -11,6 +11,7 @@ import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; import type { ConversationType } from '../state/ducks/conversations'; import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation'; +import { ThemeType } from '../types/Util'; const i18n = setupI18n('en', enMessages); @@ -27,15 +28,19 @@ const story = storiesOf( story.add('One contact', () => ( undefined} i18n={i18n} onClose={action('onClose')} + theme={ThemeType.light} /> )); story.add('Two contacts', () => ( undefined} i18n={i18n} onClose={action('onClose')} + theme={ThemeType.light} /> )); diff --git a/ts/components/NewlyCreatedGroupInvitedContactsDialog.tsx b/ts/components/NewlyCreatedGroupInvitedContactsDialog.tsx index 06b945a775..eccdd4c2a4 100644 --- a/ts/components/NewlyCreatedGroupInvitedContactsDialog.tsx +++ b/ts/components/NewlyCreatedGroupInvitedContactsDialog.tsx @@ -4,8 +4,9 @@ import type { FunctionComponent, ReactNode } from 'react'; import React from 'react'; -import type { LocalizerType } from '../types/Util'; +import type { LocalizerType, ThemeType } from '../types/Util'; import type { ConversationType } from '../state/ducks/conversations'; +import type { PreferredBadgeSelectorType } from '../state/selectors/badges'; import { Intl } from './Intl'; import { ContactName } from './conversation/ContactName'; import { GroupDialog } from './GroupDialog'; @@ -13,12 +14,14 @@ import { openLinkInWebBrowser } from '../util/openLinkInWebBrowser'; type PropsType = { contacts: Array; + getPreferredBadge: PreferredBadgeSelectorType; i18n: LocalizerType; onClose: () => void; + theme: ThemeType; }; export const NewlyCreatedGroupInvitedContactsDialog: FunctionComponent = - ({ contacts, i18n, onClose }) => { + ({ contacts, getPreferredBadge, i18n, onClose, theme }) => { let title: string; let body: ReactNode; if (contacts.length === 1) { @@ -57,7 +60,12 @@ export const NewlyCreatedGroupInvitedContactsDialog: FunctionComponent - + ); } diff --git a/ts/components/conversation/GroupV1Migration.stories.tsx b/ts/components/conversation/GroupV1Migration.stories.tsx index 4dad49fb4a..4d4547aeb6 100644 --- a/ts/components/conversation/GroupV1Migration.stories.tsx +++ b/ts/components/conversation/GroupV1Migration.stories.tsx @@ -12,6 +12,7 @@ import { setupI18n } from '../../util/setupI18n'; import enMessages from '../../../_locales/en/messages.json'; import type { PropsType } from './GroupV1Migration'; import { GroupV1Migration } from './GroupV1Migration'; +import { ThemeType } from '../../types/Util'; const i18n = setupI18n('en', enMessages); @@ -33,8 +34,10 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ isBoolean(overrideProps.areWeInvited) ? overrideProps.areWeInvited : false ), droppedMembers: overrideProps.droppedMembers || [contact1], + getPreferredBadge: () => undefined, i18n, invitedMembers: overrideProps.invitedMembers || [contact2], + theme: ThemeType.light, }); const stories = storiesOf('Components/Conversation/GroupV1Migration', module); diff --git a/ts/components/conversation/GroupV1Migration.tsx b/ts/components/conversation/GroupV1Migration.tsx index 9ea3f761de..99ae954a98 100644 --- a/ts/components/conversation/GroupV1Migration.tsx +++ b/ts/components/conversation/GroupV1Migration.tsx @@ -5,8 +5,9 @@ import * as React from 'react'; import { Button, ButtonSize, ButtonVariant } from '../Button'; import { SystemMessage } from './SystemMessage'; -import type { LocalizerType } from '../../types/Util'; +import type { LocalizerType, ThemeType } from '../../types/Util'; import type { ConversationType } from '../../state/ducks/conversations'; +import type { PreferredBadgeSelectorType } from '../../state/selectors/badges'; import { Intl } from '../Intl'; import { ContactName } from './ContactName'; import { GroupV1MigrationDialog } from '../GroupV1MigrationDialog'; @@ -19,13 +20,22 @@ export type PropsDataType = { }; export type PropsHousekeepingType = { + getPreferredBadge: PreferredBadgeSelectorType; i18n: LocalizerType; + theme: ThemeType; }; export type PropsType = PropsDataType & PropsHousekeepingType; export function GroupV1Migration(props: PropsType): React.ReactElement { - const { areWeInvited, droppedMembers, i18n, invitedMembers } = props; + const { + areWeInvited, + droppedMembers, + getPreferredBadge, + i18n, + invitedMembers, + theme, + } = props; const [showingDialog, setShowingDialog] = React.useState(false); const showDialog = React.useCallback(() => { @@ -77,11 +87,13 @@ export function GroupV1Migration(props: PropsType): React.ReactElement { log.warn('GroupV1Migration: Modal called migrate()')} onClose={dismissDialog} + theme={theme} /> ) : null} diff --git a/ts/components/conversation/Timeline.stories.tsx b/ts/components/conversation/Timeline.stories.tsx index b598e96fd3..2fdf7798b6 100644 --- a/ts/components/conversation/Timeline.stories.tsx +++ b/ts/components/conversation/Timeline.stories.tsx @@ -457,8 +457,10 @@ const renderTypingBubble = () => ( /> ); -const createProps = (overrideProps: Partial = {}): PropsType => ({ +const useProps = (overrideProps: Partial = {}): PropsType => ({ + getPreferredBadge: () => undefined, i18n, + theme: React.useContext(StorybookThemeContext), haveNewest: boolean('haveNewest', overrideProps.haveNewest !== false), haveOldest: boolean('haveOldest', overrideProps.haveOldest !== false), @@ -494,13 +496,13 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ }); story.add('Oldest and Newest', () => { - const props = createProps(); + const props = useProps(); return ; }); story.add('With active message request', () => { - const props = createProps({ + const props = useProps({ isIncomingMessageRequest: true, }); @@ -508,7 +510,7 @@ story.add('With active message request', () => { }); story.add('Without Newest Message', () => { - const props = createProps({ + const props = useProps({ haveNewest: false, }); @@ -516,7 +518,7 @@ story.add('Without Newest Message', () => { }); story.add('Without newest message, active message request', () => { - const props = createProps({ + const props = useProps({ haveOldest: false, isIncomingMessageRequest: true, }); @@ -525,7 +527,7 @@ story.add('Without newest message, active message request', () => { }); story.add('Without Oldest Message', () => { - const props = createProps({ + const props = useProps({ haveOldest: false, scrollToIndex: -1, }); @@ -534,7 +536,7 @@ story.add('Without Oldest Message', () => { }); story.add('Empty (just hero)', () => { - const props = createProps({ + const props = useProps({ items: [], }); @@ -542,7 +544,7 @@ story.add('Empty (just hero)', () => { }); story.add('Last Seen', () => { - const props = createProps({ + const props = useProps({ oldestUnreadIndex: 13, totalUnread: 2, }); @@ -551,7 +553,7 @@ story.add('Last Seen', () => { }); story.add('Target Index to Top', () => { - const props = createProps({ + const props = useProps({ scrollToIndex: 0, }); @@ -559,7 +561,7 @@ story.add('Target Index to Top', () => { }); story.add('Typing Indicator', () => { - const props = createProps({ + const props = useProps({ typingContactId: UUID.generate().toString(), }); @@ -567,7 +569,7 @@ story.add('Typing Indicator', () => { }); story.add('With invited contacts for a newly-created group', () => { - const props = createProps({ + const props = useProps({ invitedContactsForNewlyCreatedGroup: [ getDefaultConversation({ id: 'abc123', @@ -584,7 +586,7 @@ story.add('With invited contacts for a newly-created group', () => { }); story.add('With "same name in direct conversation" warning', () => { - const props = createProps({ + const props = useProps({ warning: { type: ContactSpoofingType.DirectConversationWithSameTitle, safeConversation: getDefaultConversation(), @@ -596,7 +598,7 @@ story.add('With "same name in direct conversation" warning', () => { }); story.add('With "same name in group conversation" warning', () => { - const props = createProps({ + const props = useProps({ warning: { type: ContactSpoofingType.MultipleGroupMembersWithSameTitle, acknowledgedGroupNameCollisions: {}, diff --git a/ts/components/conversation/Timeline.tsx b/ts/components/conversation/Timeline.tsx index 8a4fb7668c..f86ff18959 100644 --- a/ts/components/conversation/Timeline.tsx +++ b/ts/components/conversation/Timeline.tsx @@ -17,8 +17,9 @@ import Measure from 'react-measure'; import { ScrollDownButton } from './ScrollDownButton'; -import type { AssertProps, LocalizerType } from '../../types/Util'; +import type { AssertProps, LocalizerType, ThemeType } from '../../types/Util'; import type { ConversationType } from '../../state/ducks/conversations'; +import type { PreferredBadgeSelectorType } from '../../state/selectors/badges'; import { assert } from '../../util/assert'; import { missingCaseError } from '../../util/missingCaseError'; import { createRefMerger } from '../../util/refMerger'; @@ -102,7 +103,9 @@ type PropsHousekeepingType = { warning?: WarningType; contactSpoofingReview?: ContactSpoofingReviewPropType; + getPreferredBadge: PreferredBadgeSelectorType; i18n: LocalizerType; + theme: ThemeType; renderItem: (props: { actionProps: PropsActionsType; @@ -1312,6 +1315,7 @@ export class Timeline extends React.PureComponent { clearInvitedUuidsForNewlyCreatedGroup, closeContactSpoofingReview, contactSpoofingReview, + getPreferredBadge, i18n, id, invitedContactsForNewlyCreatedGroup, @@ -1325,6 +1329,7 @@ export class Timeline extends React.PureComponent { removeMember, reviewGroupMemberNameCollision, reviewMessageRequestNameCollision, + theme, } = this.props; const { shouldShowScrollDownButton, @@ -1561,8 +1566,10 @@ export class Timeline extends React.PureComponent { {Boolean(invitedContactsForNewlyCreatedGroup.length) && ( )} diff --git a/ts/state/smart/GroupV1MigrationDialog.tsx b/ts/state/smart/GroupV1MigrationDialog.tsx index 3fafa1bee0..27f4f28752 100644 --- a/ts/state/smart/GroupV1MigrationDialog.tsx +++ b/ts/state/smart/GroupV1MigrationDialog.tsx @@ -1,4 +1,4 @@ -// Copyright 2020 Signal Messenger, LLC +// Copyright 2020-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { connect } from 'react-redux'; @@ -7,9 +7,10 @@ import type { PropsType as GroupV1MigrationDialogPropsType } from '../../compone import { GroupV1MigrationDialog } from '../../components/GroupV1MigrationDialog'; import type { ConversationType } from '../ducks/conversations'; import type { StateType } from '../reducer'; +import { getPreferredBadgeSelector } from '../selectors/badges'; import { getConversationSelector } from '../selectors/conversations'; -import { getIntl } from '../selectors/user'; +import { getIntl, getTheme } from '../selectors/user'; import * as log from '../../logging/log'; export type PropsType = { @@ -17,7 +18,7 @@ export type PropsType = { readonly invitedMemberIds: Array; } & Omit< GroupV1MigrationDialogPropsType, - 'i18n' | 'droppedMembers' | 'invitedMembers' + 'i18n' | 'droppedMembers' | 'invitedMembers' | 'theme' | 'getPreferredBadge' >; const mapStateToProps = ( @@ -44,8 +45,10 @@ const mapStateToProps = ( return { ...props, droppedMembers, + getPreferredBadge: getPreferredBadgeSelector(state), invitedMembers, i18n: getIntl(state), + theme: getTheme(state), }; }; diff --git a/ts/state/smart/Timeline.tsx b/ts/state/smart/Timeline.tsx index 7e2978e368..cea247a7a5 100644 --- a/ts/state/smart/Timeline.tsx +++ b/ts/state/smart/Timeline.tsx @@ -18,7 +18,7 @@ import { Timeline } from '../../components/conversation/Timeline'; import type { StateType } from '../reducer'; import type { ConversationType } from '../ducks/conversations'; -import { getIntl } from '../selectors/user'; +import { getIntl, getTheme } from '../selectors/user'; import { getConversationByUuidSelector, getConversationMessagesSelector, @@ -48,6 +48,7 @@ import { } from '../../util/groupMemberNameCollisions'; import { ContactSpoofingType } from '../../util/contactSpoofing'; import type { WidthBreakpoint } from '../../components/_util'; +import { getPreferredBadgeSelector } from '../selectors/badges'; type ExternalProps = { id: string; @@ -313,7 +314,9 @@ const mapStateToProps = (state: StateType, props: ExternalProps) => { warning: getWarning(conversation, state), contactSpoofingReview: getContactSpoofingReview(id, state), + getPreferredBadge: getPreferredBadgeSelector(state), i18n: getIntl(state), + theme: getTheme(state), renderItem, renderLastSeenIndicator, renderHeroRow,