From 53d6065c008f646380c23d7f1bebac2a05dac0c3 Mon Sep 17 00:00:00 2001 From: Josh Perez <60019601+josh-signal@users.noreply.github.com> Date: Thu, 3 Jun 2021 17:34:36 -0400 Subject: [PATCH] Selects custom color when created --- ts/components/ChatColorPicker.stories.tsx | 6 +- ts/components/ChatColorPicker.tsx | 76 ++++++++++++++----- ts/components/GlobalModalContainer.tsx | 13 +--- ts/state/ducks/conversations.ts | 89 +++++++++++++++++++++++ ts/state/ducks/items.ts | 6 +- ts/state/smart/ChatColorPicker.tsx | 10 --- ts/state/smart/GlobalModalContainer.tsx | 14 +--- ts/views/conversation_view.ts | 23 ------ 8 files changed, 158 insertions(+), 79 deletions(-) diff --git a/ts/components/ChatColorPicker.stories.tsx b/ts/components/ChatColorPicker.stories.tsx index c51fc7e79b..1da43063b8 100644 --- a/ts/components/ChatColorPicker.stories.tsx +++ b/ts/components/ChatColorPicker.stories.tsx @@ -24,17 +24,19 @@ const SAMPLE_CUSTOM_COLOR = { const createProps = (): PropsType => ({ addCustomColor: action('addCustomColor'), + colorSelected: action('colorSelected'), editCustomColor: action('editCustomColor'), getConversationsWithCustomColor: (_: string) => [], i18n, - onChatColorReset: action('onChatColorReset'), - onSelectColor: action('onSelectColor'), removeCustomColor: action('removeCustomColor'), removeCustomColorOnConversations: action('removeCustomColorOnConversations'), resetAllChatColors: action('resetAllChatColors'), resetDefaultChatColor: action('resetDefaultChatColor'), selectedColor: select('selectedColor', ConversationColors, 'basil' as const), selectedCustomColor: {}, + setGlobalDefaultConversationColor: action( + 'setGlobalDefaultConversationColor' + ), }); story.add('Default', () => ); diff --git a/ts/components/ChatColorPicker.tsx b/ts/components/ChatColorPicker.tsx index ef22555782..631a76fedd 100644 --- a/ts/components/ChatColorPicker.tsx +++ b/ts/components/ChatColorPicker.tsx @@ -24,48 +24,60 @@ type CustomColorDataType = { }; export type PropsDataType = { + conversationId?: string; customColors?: Record; getConversationsWithCustomColor: (colorId: string) => Array; i18n: LocalizerType; isGlobal?: boolean; - onChatColorReset?: () => unknown; - onSelectColor: ( + selectedColor?: ConversationColorType; + selectedCustomColor: CustomColorDataType; +}; + +type PropsActionType = { + addCustomColor: ( + color: CustomColorType, + nextAction: (uuid: string) => unknown + ) => unknown; + colorSelected: (payload: { + conversationId: string; + conversationColor?: ConversationColorType; + customColorData?: { + id: string; + value: CustomColorType; + }; + }) => unknown; + editCustomColor: (colorId: string, color: CustomColorType) => unknown; + removeCustomColor: (colorId: string) => unknown; + removeCustomColorOnConversations: (colorId: string) => unknown; + resetAllChatColors: () => unknown; + resetDefaultChatColor: () => unknown; + setGlobalDefaultConversationColor: ( color: ConversationColorType, customColorData?: { id: string; value: CustomColorType; } ) => unknown; - selectedColor?: ConversationColorType; - selectedCustomColor: CustomColorDataType; -}; - -type PropsActionType = { - addCustomColor: (color: CustomColorType) => unknown; - editCustomColor: (colorId: string, color: CustomColorType) => unknown; - removeCustomColor: (colorId: string) => unknown; - removeCustomColorOnConversations: (colorId: string) => unknown; - resetAllChatColors: () => unknown; - resetDefaultChatColor: () => unknown; }; export type PropsType = PropsDataType & PropsActionType; export const ChatColorPicker = ({ addCustomColor, + colorSelected, + conversationId, customColors = {}, editCustomColor, getConversationsWithCustomColor, i18n, isGlobal = false, - onChatColorReset, - onSelectColor, removeCustomColor, removeCustomColorOnConversations, resetAllChatColors, resetDefaultChatColor, selectedColor = ConversationColors[0], selectedCustomColor, + setGlobalDefaultConversationColor, }: PropsType): JSX.Element => { const [confirmResetAll, setConfirmResetAll] = useState(false); const [confirmResetWhat, setConfirmResetWhat] = useState(false); @@ -73,6 +85,30 @@ export const ChatColorPicker = ({ CustomColorDataType | undefined >(undefined); + const onSelectColor = ( + conversationColor: ConversationColorType, + customColorData?: { id: string; value: CustomColorType } + ): void => { + if (conversationId) { + colorSelected({ + conversationId, + conversationColor, + customColorData, + }); + } else { + setGlobalDefaultConversationColor(conversationColor, customColorData); + } + }; + + const onColorAdded = (value: CustomColorType) => { + return (id: string) => { + onSelectColor('custom', { + id, + value, + }); + }; + }; + const renderCustomColorEditorWrapper = () => ( @@ -192,7 +228,7 @@ export const ChatColorPicker = ({ removeCustomColorOnConversations(colorId); }} onDupe={() => { - addCustomColor(colorValues); + addCustomColor(colorValues, onColorAdded(colorValues)); }} onEdit={() => { setCustomColorToEdit({ id: colorId, value: colorValues }); @@ -218,10 +254,12 @@ export const ChatColorPicker = ({
- {onChatColorReset ? ( + {conversationId ? ( { + colorSelected({ conversationId }); + }} /> ) : null} unknown; - }) => JSX.Element; - setGlobalDefaultConversationColor: (color: ConversationColorType) => unknown; + renderChatColorPicker: () => JSX.Element; toggleChatColorEditor: () => unknown; }; @@ -22,7 +16,6 @@ export const GlobalModalContainer = ({ i18n, isChatColorEditorVisible, renderChatColorPicker, - setGlobalDefaultConversationColor, toggleChatColorEditor, }: PropsType): JSX.Element | null => { if (isChatColorEditorVisible) { @@ -35,9 +28,7 @@ export const GlobalModalContainer = ({ onClose={toggleChatColorEditor} title={i18n('ChatColorPicker__global-chat-color')} > - {renderChatColorPicker({ - setGlobalDefaultConversationColor, - })} + {renderChatColorPicker()} ); } diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index 5f88b3b2aa..a42c212402 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -342,6 +342,7 @@ export const getConversationCallMode = ( // Actions +const COLOR_SELECTED = 'conversations/COLOR_SELECTED'; const COLORS_CHANGED = 'conversations/COLORS_CHANGED'; const CUSTOM_COLOR_REMOVED = 'conversations/CUSTOM_COLOR_REMOVED'; @@ -377,6 +378,18 @@ type ColorsChangedActionType = { }; }; }; +type ColorSelectedPayloadType = { + conversationId: string; + conversationColor?: ConversationColorType; + customColorData?: { + id: string; + value: CustomColorType; + }; +}; +export type ColorSelectedActionType = { + type: typeof COLOR_SELECTED; + payload: ColorSelectedPayloadType; +}; type CustomColorRemovedActionType = { type: typeof CUSTOM_COLOR_REMOVED; payload: { @@ -637,6 +650,7 @@ export type ConversationActionType = | ConversationRemovedActionType | ConversationUnloadedActionType | ColorsChangedActionType + | ColorSelectedActionType | CustomColorRemovedActionType | CreateGroupFulfilledActionType | CreateGroupPendingActionType @@ -689,6 +703,7 @@ export const actions = { conversationChanged, conversationRemoved, conversationUnloaded, + colorSelected, createGroup, messageChanged, messageDeleted, @@ -798,6 +813,50 @@ function resetAllChatColors(): ThunkAction< }; } +function colorSelected({ + conversationId, + conversationColor, + customColorData, +}: ColorSelectedPayloadType): ThunkAction< + void, + RootStateType, + unknown, + ColorSelectedActionType +> { + return async dispatch => { + // We don't want to trigger a model change because we're updating redux + // here manually ourselves. Au revoir Backbone! + const conversation = window.ConversationController.get(conversationId); + if (conversation) { + if (conversationColor) { + conversation.attributes.conversationColor = conversationColor; + if (customColorData) { + conversation.attributes.customColor = customColorData.value; + conversation.attributes.customColorId = customColorData.id; + } else { + delete conversation.attributes.customColor; + delete conversation.attributes.customColorId; + } + } else { + delete conversation.attributes.conversationColor; + delete conversation.attributes.customColor; + delete conversation.attributes.customColorId; + } + + await window.Signal.Data.updateConversation(conversation.attributes); + } + + dispatch({ + type: COLOR_SELECTED, + payload: { + conversationId, + conversationColor, + customColorData, + }, + }); + }; +} + function cantAddContactToGroup( conversationId: string ): CantAddContactToGroupActionType { @@ -2531,6 +2590,36 @@ export function reducer( return nextState; } + if (action.type === COLOR_SELECTED) { + const { conversationLookup } = state; + const { + conversationId, + conversationColor, + customColorData, + } = action.payload; + + const existing = conversationLookup[conversationId]; + if (!existing) { + return state; + } + + const changed = { + ...existing, + conversationColor, + customColor: customColorData?.value, + customColorId: customColorData?.id, + }; + + return { + ...state, + conversationLookup: { + ...conversationLookup, + [conversationId]: changed, + }, + ...updateConversationLookups(changed, existing, state), + }; + } + if (action.type === CUSTOM_COLOR_REMOVED) { const { conversationLookup } = state; const { colorId, defaultConversationColor } = action.payload; diff --git a/ts/state/ducks/items.ts b/ts/state/ducks/items.ts index d0cedc050d..44d235fd05 100644 --- a/ts/state/ducks/items.ts +++ b/ts/state/ducks/items.ts @@ -141,7 +141,8 @@ function getDefaultCustomColorData() { } function addCustomColor( - payload: CustomColorType + customColor: CustomColorType, + nextAction: (uuid: string) => unknown ): ThunkAction { return (dispatch, getState) => { const { customColors = getDefaultCustomColorData() } = getState().items; @@ -155,11 +156,12 @@ function addCustomColor( ...customColors, colors: { ...customColors.colors, - [uuid]: payload, + [uuid]: customColor, }, }; dispatch(putItem('customColors', nextCustomColors)); + nextAction(uuid); }; } diff --git a/ts/state/smart/ChatColorPicker.tsx b/ts/state/smart/ChatColorPicker.tsx index 34ef2338b8..1dd3c7f3c2 100644 --- a/ts/state/smart/ChatColorPicker.tsx +++ b/ts/state/smart/ChatColorPicker.tsx @@ -8,7 +8,6 @@ import { ChatColorPicker, PropsDataType, } from '../../components/ChatColorPicker'; -import { ConversationColorType, CustomColorType } from '../../types/Colors'; import { StateType } from '../reducer'; import { getConversationSelector, @@ -19,15 +18,6 @@ import { getIntl } from '../selectors/user'; export type SmartChatColorPickerProps = { conversationId?: string; - isGlobal?: boolean; - onChatColorReset?: () => unknown; - onSelectColor: ( - color: ConversationColorType, - customColorData?: { - id: string; - value: CustomColorType; - } - ) => unknown; }; const mapStateToProps = ( diff --git a/ts/state/smart/GlobalModalContainer.tsx b/ts/state/smart/GlobalModalContainer.tsx index e1ac364a28..9fe87a8b29 100644 --- a/ts/state/smart/GlobalModalContainer.tsx +++ b/ts/state/smart/GlobalModalContainer.tsx @@ -8,19 +8,9 @@ import { GlobalModalContainer } from '../../components/GlobalModalContainer'; import { StateType } from '../reducer'; import { getIntl } from '../selectors/user'; import { SmartChatColorPicker } from './ChatColorPicker'; -import { ConversationColorType } from '../../types/Colors'; -function renderChatColorPicker({ - setGlobalDefaultConversationColor, -}: { - setGlobalDefaultConversationColor: (color: ConversationColorType) => unknown; -}): JSX.Element { - return ( - - ); +function renderChatColorPicker(): JSX.Element { + return ; } const mapStateToProps = (state: StateType) => { diff --git a/ts/views/conversation_view.ts b/ts/views/conversation_view.ts index 2b8cacc8af..f756aa080d 100644 --- a/ts/views/conversation_view.ts +++ b/ts/views/conversation_view.ts @@ -4,7 +4,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { AttachmentType } from '../types/Attachment'; -import { ConversationColorType, CustomColorType } from '../types/Colors'; import { ConversationModel } from '../models/conversations'; import { GroupV2PendingMemberType } from '../model-types.d'; import { LinkPreviewType } from '../types/message/LinkPreviews'; @@ -3235,28 +3234,6 @@ Whisper.ConversationView = Whisper.View.extend({ className: 'panel', JSX: window.Signal.State.Roots.createChatColorPicker(window.reduxStore, { conversationId: conversation.get('id'), - onSelectColor: ( - color: ConversationColorType, - customColorData?: { - id: string; - value: CustomColorType; - } - ) => { - conversation.set('conversationColor', color); - if (customColorData) { - conversation.set('customColor', customColorData.value); - conversation.set('customColorId', customColorData.id); - } else { - conversation.unset('customColor'); - conversation.unset('customColorId'); - } - window.Signal.Data.updateConversation(conversation.attributes); - }, - onChatColorReset: () => { - conversation.set('conversationColor', undefined); - conversation.unset('customColor'); - window.Signal.Data.updateConversation(conversation.attributes); - }, }), });