From decc93532b88597d81b32423d1116c27cc2e98cb Mon Sep 17 00:00:00 2001 From: Evan Hahn <69474926+EvanHahn-Signal@users.noreply.github.com> Date: Fri, 30 Oct 2020 12:52:21 -0500 Subject: [PATCH] Hide call buttons when on call --- js/expiring_messages.js | 58 ---- js/modules/signal.js | 8 +- ts/background.ts | 10 +- .../ConversationHeader.stories.tsx | 99 ++----- .../conversation/ConversationHeader.tsx | 132 ++++----- ts/models/conversations.ts | 11 +- ts/models/messages.ts | 8 +- ts/state/ducks/calling.ts | 17 +- ts/state/ducks/conversations.ts | 27 ++ ts/state/roots/createConversationHeader.tsx | 14 + ts/state/smart/ConversationHeader.tsx | 68 +++++ ts/test/state/ducks/calling_test.ts | 107 +++++++ ts/test/util/isMuted_test.ts | 19 ++ ts/util/ExpirationTimerOptions.ts | 74 +++++ ts/util/isMuted.ts | 3 + ts/util/lint/exceptions.json | 6 +- ts/views/conversation_view.ts | 263 ++++++++---------- ts/window.d.ts | 64 ++++- 18 files changed, 622 insertions(+), 366 deletions(-) create mode 100644 ts/state/roots/createConversationHeader.tsx create mode 100644 ts/state/smart/ConversationHeader.tsx create mode 100644 ts/test/state/ducks/calling_test.ts create mode 100644 ts/test/util/isMuted_test.ts create mode 100644 ts/util/ExpirationTimerOptions.ts create mode 100644 ts/util/isMuted.ts diff --git a/js/expiring_messages.js b/js/expiring_messages.js index 4c490921d..86e6588c2 100644 --- a/js/expiring_messages.js +++ b/js/expiring_messages.js @@ -1,9 +1,6 @@ /* global _, - Backbone, - i18n, MessageController, - moment, Whisper */ @@ -98,59 +95,4 @@ }, update: debouncedCheckExpiringMessages, }; - - const TimerOption = Backbone.Model.extend({ - getName() { - return ( - i18n(['timerOption', this.get('time'), this.get('unit')].join('_')) || - moment.duration(this.get('time'), this.get('unit')).humanize() - ); - }, - getAbbreviated() { - return i18n( - ['timerOption', this.get('time'), this.get('unit'), 'abbreviated'].join( - '_' - ) - ); - }, - }); - Whisper.ExpirationTimerOptions = new (Backbone.Collection.extend({ - model: TimerOption, - getName(seconds = 0) { - const o = this.findWhere({ seconds }); - if (o) { - return o.getName(); - } - return [seconds, 'seconds'].join(' '); - }, - getAbbreviated(seconds = 0) { - const o = this.findWhere({ seconds }); - if (o) { - return o.getAbbreviated(); - } - return [seconds, 's'].join(''); - }, - }))( - [ - [0, 'seconds'], - [5, 'seconds'], - [10, 'seconds'], - [30, 'seconds'], - [1, 'minute'], - [5, 'minutes'], - [30, 'minutes'], - [1, 'hour'], - [6, 'hours'], - [12, 'hours'], - [1, 'day'], - [1, 'week'], - ].map(o => { - const duration = moment.duration(o[0], o[1]); // 5, 'seconds' - return { - time: o[0], - unit: o[1], - seconds: duration.asSeconds(), - }; - }) - ); })(); diff --git a/js/modules/signal.js b/js/modules/signal.js index 578e50c80..e0bdf962d 100644 --- a/js/modules/signal.js +++ b/js/modules/signal.js @@ -33,9 +33,6 @@ const { ContactDetail, } = require('../../ts/components/conversation/ContactDetail'); const { ContactListItem } = require('../../ts/components/ContactListItem'); -const { - ConversationHeader, -} = require('../../ts/components/conversation/ConversationHeader'); const { Emojify } = require('../../ts/components/conversation/Emojify'); const { ErrorModal } = require('../../ts/components/ErrorModal'); const { Lightbox } = require('../../ts/components/Lightbox'); @@ -63,6 +60,9 @@ const { createTimeline } = require('../../ts/state/roots/createTimeline'); const { createCompositionArea, } = require('../../ts/state/roots/createCompositionArea'); +const { + createConversationHeader, +} = require('../../ts/state/roots/createConversationHeader'); const { createCallManager } = require('../../ts/state/roots/createCallManager'); const { createLeftPane } = require('../../ts/state/roots/createLeftPane'); const { @@ -295,7 +295,6 @@ exports.setup = (options = {}) => { ConfirmationModal, ContactDetail, ContactListItem, - ConversationHeader, Emojify, ErrorModal, getCallingNotificationText, @@ -315,6 +314,7 @@ exports.setup = (options = {}) => { const Roots = { createCallManager, createCompositionArea, + createConversationHeader, createLeftPane, createSafetyNumberViewer, createShortcutGuideModal, diff --git a/ts/background.ts b/ts/background.ts index 31d11d7dc..e3b7b0556 100644 --- a/ts/background.ts +++ b/ts/background.ts @@ -124,7 +124,7 @@ type WhatIsThis = typeof window.WhatIsThis; }; // Keyboard/mouse mode - let interactionMode = 'mouse'; + let interactionMode: 'mouse' | 'keyboard' = 'mouse'; $(document.body).addClass('mouse-mode'); window.enterKeyboardMode = () => { @@ -664,8 +664,8 @@ type WhatIsThis = typeof window.WhatIsThis; conversationLookup: window.Signal.Util.makeLookup(conversations, 'id'), messagesByConversation: {}, messagesLookup: {}, - selectedConversation: null, - selectedMessage: null, + selectedConversation: undefined, + selectedMessage: undefined, selectedMessageCounter: 0, showArchived: false, }, @@ -822,7 +822,7 @@ type WhatIsThis = typeof window.WhatIsThis; const conversationsToSearch = getConversationsToSearch(); const increment = direction === 'up' ? -1 : 1; - let startIndex; + let startIndex: WhatIsThis; if (conversationId) { const index = conversationsToSearch.findIndex( @@ -844,7 +844,7 @@ type WhatIsThis = typeof window.WhatIsThis; if (!unreadOnly) { return target.id; } - if (target.unreadCount > 0) { + if ((target.unreadCount || 0) > 0) { return target.id; } } diff --git a/ts/components/conversation/ConversationHeader.stories.tsx b/ts/components/conversation/ConversationHeader.stories.tsx index 1ba1c0cb7..c0db8d88c 100644 --- a/ts/components/conversation/ConversationHeader.stories.tsx +++ b/ts/components/conversation/ConversationHeader.stories.tsx @@ -1,16 +1,11 @@ -import * as React from 'react'; +import React, { ComponentProps } from 'react'; import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { setup as setupI18n } from '../../../js/modules/i18n'; import enMessages from '../../../_locales/en/messages.json'; -import { - ConversationHeader, - PropsActionsType, - PropsHousekeepingType, - PropsType, -} from './ConversationHeader'; +import { ConversationHeader } from './ConversationHeader'; import { gifUrl } from '../../storybook/Fixtures'; const book = storiesOf('Components/Conversation/ConversationHeader', module); @@ -21,11 +16,17 @@ type ConversationHeaderStory = { description: string; items: Array<{ title: string; - props: PropsType; + props: ComponentProps; }>; }; -const actionProps: PropsActionsType = { +const commonProps = { + showBackButton: false, + showCallButtons: true, + markedUnread: false, + + i18n, + onSetDisappearingMessages: action('onSetDisappearingMessages'), onDeleteMessages: action('onDeleteMessages'), onResetSession: action('onResetSession'), @@ -49,10 +50,6 @@ const actionProps: PropsActionsType = { onSetPin: action('onSetPin'), }; -const housekeepingProps: PropsHousekeepingType = { - i18n, -}; - const stories: Array = [ { title: '1:1 conversation', @@ -62,6 +59,7 @@ const stories: Array = [ { title: 'With name and profile, verified', props: { + ...commonProps, color: 'red', isVerified: true, avatarPath: gifUrl, @@ -72,13 +70,12 @@ const stories: Array = [ id: '1', profileName: '🔥Flames🔥', acceptedMessageRequest: true, - ...actionProps, - ...housekeepingProps, }, }, { title: 'With name, not verified, no avatar', props: { + ...commonProps, color: 'blue', isVerified: false, title: 'Someone 🔥 Somewhere', @@ -87,13 +84,12 @@ const stories: Array = [ type: 'direct', id: '2', acceptedMessageRequest: true, - ...actionProps, - ...housekeepingProps, }, }, { title: 'With name, not verified, descenders', props: { + ...commonProps, color: 'blue', isVerified: false, title: 'Joyrey 🔥 Leppey', @@ -102,13 +98,12 @@ const stories: Array = [ type: 'direct', id: '2', acceptedMessageRequest: true, - ...actionProps, - ...housekeepingProps, }, }, { title: 'Profile, no name', props: { + ...commonProps, color: 'teal', isVerified: false, phoneNumber: '(202) 555-0003', @@ -117,25 +112,23 @@ const stories: Array = [ title: '🔥Flames🔥', profileName: '🔥Flames🔥', acceptedMessageRequest: true, - ...actionProps, - ...housekeepingProps, }, }, { title: 'No name, no profile, no color', props: { + ...commonProps, title: '(202) 555-0011', phoneNumber: '(202) 555-0011', type: 'direct', id: '11', acceptedMessageRequest: true, - ...actionProps, - ...housekeepingProps, }, }, { title: 'With back button', props: { + ...commonProps, showBackButton: true, color: 'deep_orange', phoneNumber: '(202) 555-0004', @@ -143,46 +136,32 @@ const stories: Array = [ type: 'direct', id: '4', acceptedMessageRequest: true, - ...actionProps, - ...housekeepingProps, }, }, { title: 'Disappearing messages set', props: { + ...commonProps, color: 'indigo', title: '(202) 555-0005', phoneNumber: '(202) 555-0005', type: 'direct', id: '5', - expirationSettingName: '10 seconds', - timerOptions: [ - { - name: 'off', - value: 0, - }, - { - name: '10 seconds', - value: 10, - }, - ], + expireTimer: 10, acceptedMessageRequest: true, - ...actionProps, - ...housekeepingProps, }, }, { title: 'Muting Conversation', props: { + ...commonProps, color: 'ultramarine', title: '(202) 555-0006', phoneNumber: '(202) 555-0006', type: 'direct', id: '6', - muteExpirationLabel: '10/18/3000, 11:11 AM', acceptedMessageRequest: true, - ...actionProps, - ...housekeepingProps, + muteExpiresAt: new Date('3000-10-18T11:11:11Z').valueOf(), }, }, ], @@ -195,52 +174,30 @@ const stories: Array = [ { title: 'Basic', props: { + ...commonProps, color: 'signal-blue', title: 'Typescript support group', name: 'Typescript support group', phoneNumber: '', id: '1', type: 'group', - expirationSettingName: '10 seconds', - timerOptions: [ - { - name: 'off', - value: 0, - }, - { - name: '10 seconds', - value: 10, - }, - ], + expireTimer: 10, acceptedMessageRequest: true, - ...actionProps, - ...housekeepingProps, }, }, { title: 'In a group you left - no disappearing messages', props: { + ...commonProps, color: 'signal-blue', title: 'Typescript support group', name: 'Typescript support group', phoneNumber: '', id: '2', type: 'group', - disableTimerChanges: true, - expirationSettingName: '10 seconds', - timerOptions: [ - { - name: 'off', - value: 0, - }, - { - name: '10 seconds', - value: 10, - }, - ], + left: true, + expireTimer: 10, acceptedMessageRequest: true, - ...actionProps, - ...housekeepingProps, }, }, ], @@ -252,6 +209,7 @@ const stories: Array = [ { title: 'In chat with yourself', props: { + ...commonProps, color: 'blue', title: '(202) 555-0007', phoneNumber: '(202) 555-0007', @@ -259,8 +217,6 @@ const stories: Array = [ type: 'direct', isMe: true, acceptedMessageRequest: true, - ...actionProps, - ...housekeepingProps, }, }, ], @@ -272,6 +228,7 @@ const stories: Array = [ { title: '1:1 conversation', props: { + ...commonProps, color: 'blue', title: '(202) 555-0007', phoneNumber: '(202) 555-0007', @@ -279,8 +236,6 @@ const stories: Array = [ type: 'direct', isMe: false, acceptedMessageRequest: false, - ...actionProps, - ...housekeepingProps, }, }, ], diff --git a/ts/components/conversation/ConversationHeader.tsx b/ts/components/conversation/ConversationHeader.tsx index a81d21e54..523a98fa3 100644 --- a/ts/components/conversation/ConversationHeader.tsx +++ b/ts/components/conversation/ConversationHeader.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import moment from 'moment'; import classNames from 'classnames'; import { ContextMenu, @@ -14,11 +15,11 @@ import { InContactsIcon } from '../InContactsIcon'; import { LocalizerType } from '../../types/Util'; import { ColorType } from '../../types/Colors'; import { getMuteOptions } from '../../util/getMuteOptions'; - -interface TimerOption { - name: string; - value: number; -} +import { + ExpirationTimerOptions, + TimerOption, +} from '../../util/ExpirationTimerOptions'; +import { isMuted } from '../../util/isMuted'; export interface PropsDataType { id: string; @@ -36,13 +37,16 @@ export interface PropsDataType { isMe?: boolean; isArchived?: boolean; isPinned?: boolean; + isMissingMandatoryProfileSharing?: boolean; + left?: boolean; markedUnread?: boolean; - disableTimerChanges?: boolean; - expirationSettingName?: string; - muteExpirationLabel?: string; + canChangeTimer?: boolean; + expireTimer?: number; + muteExpiresAt?: number; + showBackButton?: boolean; - timerOptions?: Array; + showCallButtons?: boolean; } export interface PropsActionsType { @@ -186,8 +190,11 @@ export class ConversationHeader extends React.Component { } public renderExpirationLength(): JSX.Element | null { - const { expirationSettingName, showBackButton } = this.props; + const { i18n, expireTimer, showBackButton } = this.props; + const expirationSettingName = expireTimer + ? ExpirationTimerOptions.getName(i18n, expireTimer) + : undefined; if (!expirationSettingName) { return null; } @@ -249,71 +256,62 @@ export class ConversationHeader extends React.Component { ); } - public renderOutgoingAudioCallButton(): JSX.Element | null { + private renderOutgoingCallButtons(): JSX.Element | null { const { i18n, - isMe, onOutgoingAudioCallInConversation, + onOutgoingVideoCallInConversation, + showCallButtons, showBackButton, - type, } = this.props; - if (type === 'group' || isMe) { + if (!showCallButtons) { return null; } return ( -