Fixes global chat color setting

This commit is contained in:
Josh Perez 2021-06-02 17:05:09 -04:00 committed by GitHub
parent a6ce00ff37
commit bd46e3afd6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 250 additions and 122 deletions

View File

@ -5454,10 +5454,18 @@
"message": "Reset chat color", "message": "Reset chat color",
"description": "Button label for resetting chat colors" "description": "Button label for resetting chat colors"
}, },
"ChatColorPicker__resetDefault": {
"message": "Reset Chat Colors",
"description": "Confirmation dialog title for resetting all chat colors or only the global default one"
},
"ChatColorPicker__resetAll": { "ChatColorPicker__resetAll": {
"message": "Reset all chat colors", "message": "Reset all chat colors",
"description": "Button label for resetting all chat colors" "description": "Button label for resetting all chat colors"
}, },
"ChatColorPicker__confirm-reset-default": {
"message": "Reset default",
"description": "Button label for resetting only global chat color"
},
"ChatColorPicker__confirm-reset": { "ChatColorPicker__confirm-reset": {
"message": "Reset", "message": "Reset",
"description": "Confirm button label for resetting chat colors" "description": "Confirm button label for resetting chat colors"

View File

@ -412,6 +412,12 @@ export async function startApp(): Promise<void> {
} }
first = false; first = false;
if (!window.storage.get('defaultConversationColor')) {
window.storage.put('defaultConversationColor', {
color: 'ultramarine',
});
}
cleanupSessionResets(); cleanupSessionResets();
const retryPlaceholders = new window.Signal.Util.RetryPlaceholders(); const retryPlaceholders = new window.Signal.Util.RetryPlaceholders();
window.Signal.Services.retryPlaceholders = retryPlaceholders; window.Signal.Services.retryPlaceholders = retryPlaceholders;

View File

@ -32,6 +32,7 @@ const createProps = (): PropsType => ({
removeCustomColor: action('removeCustomColor'), removeCustomColor: action('removeCustomColor'),
removeCustomColorOnConversations: action('removeCustomColorOnConversations'), removeCustomColorOnConversations: action('removeCustomColorOnConversations'),
resetAllChatColors: action('resetAllChatColors'), resetAllChatColors: action('resetAllChatColors'),
resetDefaultChatColor: action('resetDefaultChatColor'),
selectedColor: select('selectedColor', ConversationColors, 'basil' as const), selectedColor: select('selectedColor', ConversationColors, 'basil' as const),
selectedCustomColor: {}, selectedCustomColor: {},
}); });

View File

@ -27,7 +27,7 @@ export type PropsDataType = {
customColors?: Record<string, CustomColorType>; customColors?: Record<string, CustomColorType>;
getConversationsWithCustomColor: (colorId: string) => Array<ConversationType>; getConversationsWithCustomColor: (colorId: string) => Array<ConversationType>;
i18n: LocalizerType; i18n: LocalizerType;
isInModal?: boolean; isGlobal?: boolean;
onChatColorReset?: () => unknown; onChatColorReset?: () => unknown;
onSelectColor: ( onSelectColor: (
color: ConversationColorType, color: ConversationColorType,
@ -46,6 +46,7 @@ type PropsActionType = {
removeCustomColor: (colorId: string) => unknown; removeCustomColor: (colorId: string) => unknown;
removeCustomColorOnConversations: (colorId: string) => unknown; removeCustomColorOnConversations: (colorId: string) => unknown;
resetAllChatColors: () => unknown; resetAllChatColors: () => unknown;
resetDefaultChatColor: () => unknown;
}; };
export type PropsType = PropsDataType & PropsActionType; export type PropsType = PropsDataType & PropsActionType;
@ -56,16 +57,18 @@ export const ChatColorPicker = ({
editCustomColor, editCustomColor,
getConversationsWithCustomColor, getConversationsWithCustomColor,
i18n, i18n,
isInModal = false, isGlobal = false,
onChatColorReset, onChatColorReset,
onSelectColor, onSelectColor,
removeCustomColor, removeCustomColor,
removeCustomColorOnConversations, removeCustomColorOnConversations,
resetAllChatColors, resetAllChatColors,
resetDefaultChatColor,
selectedColor = ConversationColors[0], selectedColor = ConversationColors[0],
selectedCustomColor, selectedCustomColor,
}: PropsType): JSX.Element => { }: PropsType): JSX.Element => {
const [confirmResetAll, setConfirmResetAll] = useState(false); const [confirmResetAll, setConfirmResetAll] = useState(false);
const [confirmResetWhat, setConfirmResetWhat] = useState(false);
const [customColorToEdit, setCustomColorToEdit] = useState< const [customColorToEdit, setCustomColorToEdit] = useState<
CustomColorDataType | undefined CustomColorDataType | undefined
>(undefined); >(undefined);
@ -74,7 +77,7 @@ export const ChatColorPicker = ({
<CustomColorEditorWrapper <CustomColorEditorWrapper
customColorToEdit={customColorToEdit} customColorToEdit={customColorToEdit}
i18n={i18n} i18n={i18n}
isInModal={isInModal} isGlobal={isGlobal}
onClose={() => setCustomColorToEdit(undefined)} onClose={() => setCustomColorToEdit(undefined)}
onSave={(color: CustomColorType) => { onSave={(color: CustomColorType) => {
if (customColorToEdit?.id) { if (customColorToEdit?.id) {
@ -90,13 +93,39 @@ export const ChatColorPicker = ({
/> />
); );
if (isInModal && customColorToEdit) { if (isGlobal && customColorToEdit) {
return renderCustomColorEditorWrapper(); return renderCustomColorEditorWrapper();
} }
return ( return (
<div className="ChatColorPicker__container"> <div className="ChatColorPicker__container">
{customColorToEdit ? renderCustomColorEditorWrapper() : null} {customColorToEdit ? renderCustomColorEditorWrapper() : null}
{confirmResetWhat ? (
<ConfirmationDialog
actions={[
{
action: resetDefaultChatColor,
style: 'affirmative',
text: i18n('ChatColorPicker__confirm-reset-default'),
},
{
action: () => {
resetDefaultChatColor();
resetAllChatColors();
},
style: 'affirmative',
text: i18n('ChatColorPicker__resetAll'),
},
]}
i18n={i18n}
onClose={() => {
setConfirmResetWhat(false);
}}
title={i18n('ChatColorPicker__resetDefault')}
>
{i18n('ChatColorPicker__confirm-reset-message')}
</ConfirmationDialog>
) : null}
{confirmResetAll ? ( {confirmResetAll ? (
<ConfirmationDialog <ConfirmationDialog
actions={[ actions={[
@ -198,7 +227,11 @@ export const ChatColorPicker = ({
<PanelRow <PanelRow
label={i18n('ChatColorPicker__resetAll')} label={i18n('ChatColorPicker__resetAll')}
onClick={() => { onClick={() => {
setConfirmResetAll(true); if (isGlobal) {
setConfirmResetWhat(true);
} else {
setConfirmResetAll(true);
}
}} }}
/> />
</div> </div>
@ -349,7 +382,7 @@ const CustomColorBubble = ({
type CustomColorEditorWrapperPropsType = { type CustomColorEditorWrapperPropsType = {
customColorToEdit?: CustomColorDataType; customColorToEdit?: CustomColorDataType;
i18n: LocalizerType; i18n: LocalizerType;
isInModal: boolean; isGlobal: boolean;
onClose: () => unknown; onClose: () => unknown;
onSave: (color: CustomColorType) => unknown; onSave: (color: CustomColorType) => unknown;
}; };
@ -357,7 +390,7 @@ type CustomColorEditorWrapperPropsType = {
const CustomColorEditorWrapper = ({ const CustomColorEditorWrapper = ({
customColorToEdit, customColorToEdit,
i18n, i18n,
isInModal, isGlobal,
onClose, onClose,
onSave, onSave,
}: CustomColorEditorWrapperPropsType): JSX.Element => { }: CustomColorEditorWrapperPropsType): JSX.Element => {
@ -370,7 +403,7 @@ const CustomColorEditorWrapper = ({
/> />
); );
if (!isInModal) { if (!isGlobal) {
return ( return (
<Modal <Modal
hasXButton hasXButton

View File

@ -10,9 +10,11 @@ type PropsType = {
i18n: LocalizerType; i18n: LocalizerType;
isChatColorEditorVisible: boolean; isChatColorEditorVisible: boolean;
renderChatColorPicker: (actions: { renderChatColorPicker: (actions: {
setAllConversationColors: (color: ConversationColorType) => unknown; setGlobalDefaultConversationColor: (
color: ConversationColorType
) => unknown;
}) => JSX.Element; }) => JSX.Element;
setAllConversationColors: (color: ConversationColorType) => unknown; setGlobalDefaultConversationColor: (color: ConversationColorType) => unknown;
toggleChatColorEditor: () => unknown; toggleChatColorEditor: () => unknown;
}; };
@ -20,7 +22,7 @@ export const GlobalModalContainer = ({
i18n, i18n,
isChatColorEditorVisible, isChatColorEditorVisible,
renderChatColorPicker, renderChatColorPicker,
setAllConversationColors, setGlobalDefaultConversationColor,
toggleChatColorEditor, toggleChatColorEditor,
}: PropsType): JSX.Element | null => { }: PropsType): JSX.Element | null => {
if (isChatColorEditorVisible) { if (isChatColorEditorVisible) {
@ -34,7 +36,7 @@ export const GlobalModalContainer = ({
title={i18n('ChatColorPicker__global-chat-color')} title={i18n('ChatColorPicker__global-chat-color')}
> >
{renderChatColorPicker({ {renderChatColorPicker({
setAllConversationColors, setGlobalDefaultConversationColor,
})} })}
</Modal> </Modal>
); );

View File

@ -24,6 +24,7 @@ import {
AvatarColorType, AvatarColorType,
AvatarColors, AvatarColors,
ConversationColorType, ConversationColorType,
CustomColorType,
} from '../types/Colors'; } from '../types/Colors';
import { MessageModel } from './messages'; import { MessageModel } from './messages';
import { isMuted } from '../util/isMuted'; import { isMuted } from '../util/isMuted';
@ -1446,6 +1447,8 @@ export class ConversationModel extends window.Backbone
.filter((member): member is ConversationType => member !== null) .filter((member): member is ConversationType => member !== null)
: undefined; : undefined;
const { customColor, customColorId } = this.getCustomColorData();
// TODO: DESKTOP-720 // TODO: DESKTOP-720
/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-non-null-assertion */
const result: ConversationType = { const result: ConversationType = {
@ -1469,8 +1472,8 @@ export class ConversationModel extends window.Backbone
unblurredAvatarPath: this.getAbsoluteUnblurredAvatarPath(), unblurredAvatarPath: this.getAbsoluteUnblurredAvatarPath(),
color, color,
conversationColor: this.getConversationColor(), conversationColor: this.getConversationColor(),
customColor: this.get('customColor'), customColor,
customColorId: this.get('customColorId'), customColorId,
discoveredUnregisteredAt: this.get('discoveredUnregisteredAt'), discoveredUnregisteredAt: this.get('discoveredUnregisteredAt'),
draftBodyRanges, draftBodyRanges,
draftPreview, draftPreview,
@ -4871,8 +4874,33 @@ export class ConversationModel extends window.Backbone
} }
getConversationColor(): ConversationColorType { getConversationColor(): ConversationColorType {
return (this.get('conversationColor') || const defaultConversationColor = window.storage.get(
'ultramarine') as ConversationColorType; 'defaultConversationColor'
);
if (defaultConversationColor.customColorData) {
return 'custom';
}
return this.get('conversationColor') || defaultConversationColor.color;
}
getCustomColorData(): {
customColor?: CustomColorType;
customColorId?: string;
} {
const defaultConversationColor = window.storage.get(
'defaultConversationColor'
);
return {
customColor:
this.get('customColor') ||
defaultConversationColor.customColorData?.value,
customColorId:
this.get('customColorId') ||
defaultConversationColor.customColorData?.id,
};
} }
private getAvatarPath(): undefined | string { private getAvatarPath(): undefined | string {

View File

@ -1002,7 +1002,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
textPending: this.get('bodyPending'), textPending: this.get('bodyPending'),
id: this.id, id: this.id,
conversationColor: this.getConversationColor(), conversationColor: this.getConversationColor(),
customColor: conversation?.get('customColor'), customColor: conversation?.getCustomColorData()?.customColor,
conversationId: this.get('conversationId'), conversationId: this.get('conversationId'),
isSticker: Boolean(sticker), isSticker: Boolean(sticker),
direction: this.isIncoming() ? 'incoming' : 'outgoing', direction: this.isIncoming() ? 'incoming' : 'outgoing',

View File

@ -0,0 +1,21 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
export function reloadSelectedConversation(): void {
const { conversations } = window.reduxStore.getState();
const { selectedConversationId } = conversations;
if (!selectedConversationId) {
return;
}
const conversation = window.ConversationController.get(
selectedConversationId
);
if (!conversation) {
return;
}
conversation.cachedProps = undefined;
window.reduxActions.conversations.conversationChanged(
conversation.id,
conversation.format()
);
}

View File

@ -379,7 +379,16 @@ type ColorsChangedActionType = {
}; };
type CustomColorRemovedActionType = { type CustomColorRemovedActionType = {
type: typeof CUSTOM_COLOR_REMOVED; type: typeof CUSTOM_COLOR_REMOVED;
payload: string; payload: {
colorId: string;
defaultConversationColor: {
color: ConversationColorType;
customColorData?: {
id: string;
value: CustomColorType;
};
};
};
}; };
type SetPreJoinConversationActionType = { type SetPreJoinConversationActionType = {
type: 'SET_PRE_JOIN_CONVERSATION'; type: 'SET_PRE_JOIN_CONVERSATION';
@ -697,7 +706,6 @@ export const actions = {
reviewMessageRequestNameCollision, reviewMessageRequestNameCollision,
scrollToMessage, scrollToMessage,
selectMessage, selectMessage,
setAllConversationColors,
setComposeGroupAvatar, setComposeGroupAvatar,
setComposeGroupName, setComposeGroupName,
setComposeSearchTerm, setComposeSearchTerm,
@ -741,9 +749,16 @@ function removeCustomColorOnConversations(
await window.Signal.Data.updateConversations(conversationsToUpdate); await window.Signal.Data.updateConversations(conversationsToUpdate);
} }
const defaultConversationColor = window.storage.get(
'defaultConversationColor'
);
dispatch({ dispatch({
type: CUSTOM_COLOR_REMOVED, type: CUSTOM_COLOR_REMOVED,
payload: colorId, payload: {
colorId,
defaultConversationColor,
},
}); });
}; };
} }
@ -769,44 +784,15 @@ function resetAllChatColors(): ThunkAction<
delete conversation.attributes.customColorId; delete conversation.attributes.customColorId;
}); });
dispatch({ const defaultConversationColor = window.storage.get(
type: COLORS_CHANGED, 'defaultConversationColor'
payload: {
conversationColor: undefined,
customColorData: undefined,
},
});
};
}
function setAllConversationColors(
conversationColor: ConversationColorType,
customColorData?: {
id: string;
value: CustomColorType;
}
): ThunkAction<void, RootStateType, unknown, ColorsChangedActionType> {
return async dispatch => {
await window.Signal.Data.updateAllConversationColors(
conversationColor,
customColorData
); );
// We don't want to trigger a model change because we're updating redux
// here manually ourselves. Au revoir Backbone!
window.getConversations().forEach(conversation => {
Object.assign(conversation.attributes, {
conversationColor,
customColor: customColorData?.value,
customColorId: customColorData?.id,
});
});
dispatch({ dispatch({
type: COLORS_CHANGED, type: COLORS_CHANGED,
payload: { payload: {
conversationColor, conversationColor: defaultConversationColor.color,
customColorData, customColorData: defaultConversationColor.customColorData,
}, },
}); });
}; };
@ -2547,7 +2533,7 @@ export function reducer(
if (action.type === CUSTOM_COLOR_REMOVED) { if (action.type === CUSTOM_COLOR_REMOVED) {
const { conversationLookup } = state; const { conversationLookup } = state;
const colorId = action.payload; const { colorId, defaultConversationColor } = action.payload;
const nextState = { const nextState = {
...state, ...state,
@ -2560,11 +2546,12 @@ export function reducer(
return; return;
} }
const changed = omit(existing, [ const changed = {
'conversationColor', ...existing,
'customColor', conversationColor: defaultConversationColor.color,
'customColorId', customColor: defaultConversationColor.customColorData?.value,
]); customColorId: defaultConversationColor.customColorData?.id,
};
Object.assign( Object.assign(
nextState, nextState,

View File

@ -7,7 +7,12 @@ import { ThunkAction } from 'redux-thunk';
import { StateType as RootStateType } from '../reducer'; import { StateType as RootStateType } from '../reducer';
import * as storageShim from '../../shims/storage'; import * as storageShim from '../../shims/storage';
import { useBoundActions } from '../../util/hooks'; import { useBoundActions } from '../../util/hooks';
import { CustomColorType } from '../../types/Colors'; import {
ConversationColors,
ConversationColorType,
CustomColorType,
} from '../../types/Colors';
import { reloadSelectedConversation } from '../../shims/reloadSelectedConversation';
// State // State
@ -15,6 +20,16 @@ export type ItemsStateType = {
readonly universalExpireTimer?: number; readonly universalExpireTimer?: number;
readonly [key: string]: unknown; readonly [key: string]: unknown;
// This property should always be set and this is ensured in background.ts
readonly defaultConversationColor?: {
color: ConversationColorType;
customColorData?: {
id: string;
value: CustomColorType;
};
};
readonly customColors?: { readonly customColors?: {
readonly colors: Record<string, CustomColorType>; readonly colors: Record<string, CustomColorType>;
readonly version: number; readonly version: number;
@ -63,6 +78,8 @@ export const actions = {
addCustomColor, addCustomColor,
editCustomColor, editCustomColor,
removeCustomColor, removeCustomColor,
resetDefaultChatColor,
setGlobalDefaultConversationColor,
onSetSkinTone, onSetSkinTone,
putItem, putItem,
putItemExternal, putItemExternal,
@ -184,10 +201,48 @@ function removeCustomColor(
}; };
} }
function resetDefaultChatColor(): ThunkAction<
void,
RootStateType,
unknown,
ItemPutAction
> {
return dispatch => {
dispatch(
putItem('defaultConversationColor', {
color: ConversationColors[0],
})
);
reloadSelectedConversation();
};
}
function setGlobalDefaultConversationColor(
color: ConversationColorType,
customColorData?: {
id: string;
value: CustomColorType;
}
): ThunkAction<void, RootStateType, unknown, ItemPutAction> {
return dispatch => {
dispatch(
putItem('defaultConversationColor', {
color,
customColorData,
})
);
reloadSelectedConversation();
};
}
// Reducer // Reducer
function getEmptyState(): ItemsStateType { function getEmptyState(): ItemsStateType {
return {}; return {
defaultConversationColor: {
color: ConversationColors[0],
},
};
} }
export function reducer( export function reducer(

View File

@ -7,6 +7,11 @@ import { ITEM_NAME as UNIVERSAL_EXPIRE_TIMER_ITEM } from '../../util/universalEx
import { StateType } from '../reducer'; import { StateType } from '../reducer';
import { ItemsStateType } from '../ducks/items'; import { ItemsStateType } from '../ducks/items';
import {
ConversationColors,
ConversationColorType,
CustomColorType,
} from '../../types/Colors';
export const getItems = (state: StateType): ItemsStateType => state.items; export const getItems = (state: StateType): ItemsStateType => state.items;
@ -25,3 +30,16 @@ export const getUniversalExpireTimer = createSelector(
getItems, getItems,
(state: ItemsStateType): number => state[UNIVERSAL_EXPIRE_TIMER_ITEM] || 0 (state: ItemsStateType): number => state[UNIVERSAL_EXPIRE_TIMER_ITEM] || 0
); );
export const getDefaultConversationColor = createSelector(
getItems,
(
state: ItemsStateType
): {
color: ConversationColorType;
customColorData?: {
id: string;
value: CustomColorType;
};
} => state.defaultConversationColor ?? { color: ConversationColors[0] }
);

View File

@ -13,13 +13,13 @@ import { StateType } from '../reducer';
import { import {
getConversationSelector, getConversationSelector,
getConversationsWithCustomColorSelector, getConversationsWithCustomColorSelector,
getMe,
} from '../selectors/conversations'; } from '../selectors/conversations';
import { getDefaultConversationColor } from '../selectors/items';
import { getIntl } from '../selectors/user'; import { getIntl } from '../selectors/user';
export type SmartChatColorPickerProps = { export type SmartChatColorPickerProps = {
conversationId?: string; conversationId?: string;
isInModal?: boolean; isGlobal?: boolean;
onChatColorReset?: () => unknown; onChatColorReset?: () => unknown;
onSelectColor: ( onSelectColor: (
color: ConversationColorType, color: ConversationColorType,
@ -34,9 +34,14 @@ const mapStateToProps = (
state: StateType, state: StateType,
props: SmartChatColorPickerProps props: SmartChatColorPickerProps
): PropsDataType => { ): PropsDataType => {
const conversation = props.conversationId const defaultConversationColor = getDefaultConversationColor(state);
const colorValues = props.conversationId
? getConversationSelector(state)(props.conversationId) ? getConversationSelector(state)(props.conversationId)
: getMe(state); : {
conversationColor: defaultConversationColor.color,
customColorId: defaultConversationColor.customColorData?.id,
customColor: defaultConversationColor.customColorData?.value,
};
const { customColors } = state.items; const { customColors } = state.items;
@ -47,10 +52,10 @@ const mapStateToProps = (
state state
), ),
i18n: getIntl(state), i18n: getIntl(state),
selectedColor: conversation.conversationColor, selectedColor: colorValues.conversationColor,
selectedCustomColor: { selectedCustomColor: {
id: conversation.customColorId, id: colorValues.customColorId,
value: conversation.customColor, value: colorValues.customColor,
}, },
}; };
}; };

View File

@ -11,12 +11,15 @@ import { SmartChatColorPicker } from './ChatColorPicker';
import { ConversationColorType } from '../../types/Colors'; import { ConversationColorType } from '../../types/Colors';
function renderChatColorPicker({ function renderChatColorPicker({
setAllConversationColors, setGlobalDefaultConversationColor,
}: { }: {
setAllConversationColors: (color: ConversationColorType) => unknown; setGlobalDefaultConversationColor: (color: ConversationColorType) => unknown;
}): JSX.Element { }): JSX.Element {
return ( return (
<SmartChatColorPicker isInModal onSelectColor={setAllConversationColors} /> <SmartChatColorPicker
isGlobal
onSelectColor={setGlobalDefaultConversationColor}
/>
); );
} }

View File

@ -41,7 +41,6 @@ const {
openConversationInternal, openConversationInternal,
repairNewestMessage, repairNewestMessage,
repairOldestMessage, repairOldestMessage,
setAllConversationColors,
setComposeGroupAvatar, setComposeGroupAvatar,
setComposeGroupName, setComposeGroupName,
setComposeSearchTerm, setComposeSearchTerm,
@ -2041,49 +2040,10 @@ describe('both/state/ducks/conversations', () => {
}, },
}); });
it('setAllConversationColors', async () => {
const dispatch = sinon.spy();
await setAllConversationColors('crimson')(dispatch, getState, null);
const [action] = dispatch.getCall(0).args;
const nextState = reducer(getState().conversations, action);
sinon.assert.calledOnce(dispatch);
assert.equal(
nextState.conversationLookup.abc.conversationColor,
'crimson'
);
assert.equal(
nextState.conversationLookup.def.conversationColor,
'crimson'
);
assert.equal(
nextState.conversationLookup.ghi.conversationColor,
'crimson'
);
assert.equal(
nextState.conversationLookup.jkl.conversationColor,
'crimson'
);
assert.equal(
nextState.conversationsByUuid.abc.conversationColor,
'crimson'
);
assert.equal(
nextState.conversationsByUuid.def.conversationColor,
'crimson'
);
assert.equal(
nextState.conversationsByE164.ghi.conversationColor,
'crimson'
);
assert.equal(
nextState.conversationsByGroupId.jkl.conversationColor,
'crimson'
);
});
it('resetAllChatColors', async () => { it('resetAllChatColors', async () => {
window.storage.put('defaultConversationColor', {
color: 'crimson',
});
const dispatch = sinon.spy(); const dispatch = sinon.spy();
await resetAllChatColors()(dispatch, getState, null); await resetAllChatColors()(dispatch, getState, null);
@ -2091,38 +2051,39 @@ describe('both/state/ducks/conversations', () => {
const nextState = reducer(getState().conversations, action); const nextState = reducer(getState().conversations, action);
sinon.assert.calledOnce(dispatch); sinon.assert.calledOnce(dispatch);
assert.isUndefined( assert.equal(
nextState.conversationLookup.abc.conversationColor, nextState.conversationLookup.abc.conversationColor,
'crimson' 'crimson'
); );
assert.isUndefined( assert.equal(
nextState.conversationLookup.def.conversationColor, nextState.conversationLookup.def.conversationColor,
'crimson' 'crimson'
); );
assert.isUndefined( assert.equal(
nextState.conversationLookup.ghi.conversationColor, nextState.conversationLookup.ghi.conversationColor,
'crimson' 'crimson'
); );
assert.isUndefined( assert.equal(
nextState.conversationLookup.jkl.conversationColor, nextState.conversationLookup.jkl.conversationColor,
'crimson' 'crimson'
); );
assert.isUndefined( assert.equal(
nextState.conversationsByUuid.abc.conversationColor, nextState.conversationsByUuid.abc.conversationColor,
'crimson' 'crimson'
); );
assert.isUndefined( assert.equal(
nextState.conversationsByUuid.def.conversationColor, nextState.conversationsByUuid.def.conversationColor,
'crimson' 'crimson'
); );
assert.isUndefined( assert.equal(
nextState.conversationsByE164.ghi.conversationColor, nextState.conversationsByE164.ghi.conversationColor,
'crimson' 'crimson'
); );
assert.isUndefined( assert.equal(
nextState.conversationsByGroupId.jkl.conversationColor, nextState.conversationsByGroupId.jkl.conversationColor,
'crimson' 'crimson'
); );
window.storage.remove('defaultConversationColor');
}); });
}); });
}); });