Keyboard shortcuts and accessibility

This commit is contained in:
Scott Nonnenberg 2019-11-07 13:36:16 -08:00
parent 8590a047c7
commit 20a892247f
87 changed files with 3652 additions and 711 deletions

View file

@ -130,7 +130,7 @@ type ConversationRemovedActionType = {
id: string;
};
};
type ConversationUnloadedActionType = {
export type ConversationUnloadedActionType = {
type: 'CONVERSATION_UNLOADED';
payload: {
id: string;
@ -140,6 +140,13 @@ export type RemoveAllConversationsActionType = {
type: 'CONVERSATIONS_REMOVE_ALL';
payload: null;
};
export type MessageSelectedActionType = {
type: 'MESSAGE_SELECTED';
payload: {
messageId: string;
conversationId: string;
};
};
export type MessageChangedActionType = {
type: 'MESSAGE_CHANGED';
payload: {
@ -228,7 +235,7 @@ type ShowInboxActionType = {
type: 'SHOW_INBOX';
payload: null;
};
type ShowArchivedConversationsActionType = {
export type ShowArchivedConversationsActionType = {
type: 'SHOW_ARCHIVED_CONVERSATIONS';
payload: null;
};
@ -239,6 +246,7 @@ export type ConversationActionType =
| ConversationRemovedActionType
| ConversationUnloadedActionType
| RemoveAllConversationsActionType
| MessageSelectedActionType
| MessageChangedActionType
| MessageDeletedActionType
| MessagesAddedActionType
@ -264,6 +272,7 @@ export const actions = {
conversationRemoved,
conversationUnloaded,
removeAllConversations,
selectMessage,
messageDeleted,
messageChanged,
messagesAdded,
@ -328,6 +337,16 @@ function removeAllConversations(): RemoveAllConversationsActionType {
};
}
function selectMessage(messageId: string, conversationId: string) {
return {
type: 'MESSAGE_SELECTED',
payload: {
messageId,
conversationId,
},
};
}
function messageChanged(
id: string,
conversationId: string,
@ -632,9 +651,14 @@ export function reducer(
}
const { messageIds } = existingConversation;
const selectedConversation =
state.selectedConversation !== id
? state.selectedConversation
: undefined;
return {
...state,
selectedConversation,
messagesLookup: omit(state.messagesLookup, messageIds),
messagesByConversation: omit(state.messagesByConversation, [id]),
};
@ -642,6 +666,19 @@ export function reducer(
if (action.type === 'CONVERSATIONS_REMOVE_ALL') {
return getEmptyState();
}
if (action.type === 'MESSAGE_SELECTED') {
const { messageId, conversationId } = action.payload;
if (state.selectedConversation !== conversationId) {
return state;
}
return {
...state,
selectedMessage: messageId,
selectedMessageCounter: state.selectedMessageCounter + 1,
};
}
if (action.type === 'MESSAGE_CHANGED') {
const { id, conversationId, data } = action.payload;
const existingConversation = state.messagesByConversation[conversationId];
@ -712,7 +749,9 @@ export function reducer(
[conversationId]: {
isLoadingMessages: false,
scrollToMessageId,
scrollToMessageCounter: 0,
scrollToMessageCounter: existingConversation
? existingConversation.scrollToMessageCounter + 1
: 0,
messageIds,
metrics,
resetCounter,

View file

@ -12,10 +12,12 @@ import { makeLookup } from '../../util/makeLookup';
import {
ConversationType,
ConversationUnloadedActionType,
MessageDeletedActionType,
MessageType,
RemoveAllConversationsActionType,
SelectedConversationChangedActionType,
ShowArchivedConversationsActionType,
} from './conversations';
// State
@ -29,6 +31,7 @@ export type MessageSearchResultLookupType = {
};
export type SearchStateType = {
startSearchCounter: number;
searchConversationId?: string;
searchConversationName?: string;
// We store just ids of conversations, since that data is always cached in memory
@ -81,6 +84,10 @@ type UpdateSearchTermActionType = {
query: string;
};
};
type StartSearchActionType = {
type: 'SEARCH_START';
payload: null;
};
type ClearSearchActionType = {
type: 'SEARCH_CLEAR';
payload: null;
@ -103,18 +110,22 @@ export type SEARCH_TYPES =
| SearchMessagesResultsFulfilledActionType
| SearchDiscussionsResultsFulfilledActionType
| UpdateSearchTermActionType
| StartSearchActionType
| ClearSearchActionType
| ClearConversationSearchActionType
| SearchInConversationActionType
| MessageDeletedActionType
| RemoveAllConversationsActionType
| SelectedConversationChangedActionType;
| SelectedConversationChangedActionType
| ShowArchivedConversationsActionType
| ConversationUnloadedActionType;
// Action Creators
export const actions = {
searchMessages,
searchDiscussions,
startSearch,
clearSearch,
clearConversationSearch,
searchInConversation,
@ -188,7 +199,12 @@ async function doSearchDiscussions(
query,
};
}
function startSearch(): StartSearchActionType {
return {
type: 'SEARCH_START',
payload: null,
};
}
function clearSearch(): ClearSearchActionType {
return {
type: 'SEARCH_CLEAR',
@ -294,6 +310,7 @@ async function queryConversationsAndContacts(
function getEmptyState(): SearchStateType {
return {
startSearchCounter: 0,
query: '',
messageIds: [],
messageLookup: {},
@ -304,11 +321,24 @@ function getEmptyState(): SearchStateType {
};
}
// tslint:disable-next-line max-func-body-length
// tslint:disable-next-line cyclomatic-complexity max-func-body-length
export function reducer(
state: SearchStateType = getEmptyState(),
action: SEARCH_TYPES
): SearchStateType {
if (action.type === 'SHOW_ARCHIVED_CONVERSATIONS') {
return getEmptyState();
}
if (action.type === 'SEARCH_START') {
return {
...state,
searchConversationId: undefined,
searchConversationName: undefined,
startSearchCounter: state.startSearchCounter + 1,
};
}
if (action.type === 'SEARCH_CLEAR') {
return getEmptyState();
}
@ -341,13 +371,17 @@ export function reducer(
const { searchConversationId, searchConversationName } = payload;
if (searchConversationId === state.searchConversationId) {
return state;
return {
...state,
startSearchCounter: state.startSearchCounter + 1,
};
}
return {
...getEmptyState(),
searchConversationId,
searchConversationName,
startSearchCounter: state.startSearchCounter + 1,
};
}
if (action.type === 'CLEAR_CONVERSATION_SEARCH') {
@ -412,6 +446,18 @@ export function reducer(
};
}
if (action.type === 'CONVERSATION_UNLOADED') {
const { payload } = action;
const { id } = payload;
const { searchConversationId } = state;
if (searchConversationId && searchConversationId === id) {
return getEmptyState();
}
return state;
}
if (action.type === 'MESSAGE_DELETED') {
const { messageIds, messageLookup } = state;
if (!messageIds || messageIds.length < 1) {

View file

@ -8,6 +8,7 @@ export type UserStateType = {
stickersPath: string;
tempPath: string;
ourNumber: string;
platform: string;
regionCode: string;
i18n: LocalizerType;
};
@ -49,6 +50,7 @@ function getEmptyState(): UserStateType {
tempPath: 'missing',
ourNumber: 'missing',
regionCode: 'missing',
platform: 'missing',
i18n: () => 'missing',
};
}