2022-02-14 17:57:11 +00:00
|
|
|
// Copyright 2021-2022 Signal Messenger, LLC
|
2021-02-23 20:34:28 +00:00
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
2021-10-26 19:15:33 +00:00
|
|
|
import type { ReactChild } from 'react';
|
|
|
|
import React from 'react';
|
2021-02-23 20:34:28 +00:00
|
|
|
import { last } from 'lodash';
|
|
|
|
|
2021-10-26 19:15:33 +00:00
|
|
|
import type { ToFindType } from './LeftPaneHelper';
|
|
|
|
import { LeftPaneHelper } from './LeftPaneHelper';
|
2021-02-23 20:34:28 +00:00
|
|
|
import { getConversationInDirection } from './getConversationInDirection';
|
2021-10-26 19:15:33 +00:00
|
|
|
import type { Row } from '../ConversationList';
|
|
|
|
import { RowType } from '../ConversationList';
|
|
|
|
import type { PropsData as ConversationListItemPropsType } from '../conversationList/ConversationListItem';
|
|
|
|
import type { LocalizerType } from '../../types/Util';
|
2021-11-01 18:43:02 +00:00
|
|
|
import type { ConversationType } from '../../state/ducks/conversations';
|
2022-02-14 17:57:11 +00:00
|
|
|
import { LeftPaneSearchInput } from '../LeftPaneSearchInput';
|
2021-11-01 18:43:02 +00:00
|
|
|
import type { LeftPaneSearchPropsType } from './LeftPaneSearchHelper';
|
|
|
|
import { LeftPaneSearchHelper } from './LeftPaneSearchHelper';
|
2022-03-31 05:58:28 +00:00
|
|
|
import * as KeyboardLayout from '../../services/keyboardLayout';
|
2021-02-23 20:34:28 +00:00
|
|
|
|
2021-11-01 18:43:02 +00:00
|
|
|
type LeftPaneArchiveBasePropsType = {
|
2021-02-23 20:34:28 +00:00
|
|
|
archivedConversations: ReadonlyArray<ConversationListItemPropsType>;
|
2021-11-01 18:43:02 +00:00
|
|
|
searchConversation: undefined | ConversationType;
|
|
|
|
searchTerm: string;
|
2022-02-02 15:30:39 +00:00
|
|
|
startSearchCounter: number;
|
2021-02-23 20:34:28 +00:00
|
|
|
};
|
|
|
|
|
2021-11-01 18:43:02 +00:00
|
|
|
export type LeftPaneArchivePropsType =
|
|
|
|
| LeftPaneArchiveBasePropsType
|
|
|
|
| (LeftPaneArchiveBasePropsType & LeftPaneSearchPropsType);
|
|
|
|
|
2021-04-26 16:38:50 +00:00
|
|
|
export class LeftPaneArchiveHelper extends LeftPaneHelper<LeftPaneArchivePropsType> {
|
|
|
|
private readonly archivedConversations: ReadonlyArray<ConversationListItemPropsType>;
|
2021-02-23 20:34:28 +00:00
|
|
|
|
2021-11-01 18:43:02 +00:00
|
|
|
private readonly searchConversation: undefined | ConversationType;
|
|
|
|
|
|
|
|
private readonly searchTerm: string;
|
|
|
|
|
|
|
|
private readonly searchHelper: undefined | LeftPaneSearchHelper;
|
|
|
|
|
2022-02-02 15:30:39 +00:00
|
|
|
private readonly startSearchCounter: number;
|
|
|
|
|
2021-11-01 18:43:02 +00:00
|
|
|
constructor(props: Readonly<LeftPaneArchivePropsType>) {
|
2021-02-23 20:34:28 +00:00
|
|
|
super();
|
|
|
|
|
2021-11-01 18:43:02 +00:00
|
|
|
this.archivedConversations = props.archivedConversations;
|
|
|
|
this.searchConversation = props.searchConversation;
|
|
|
|
this.searchTerm = props.searchTerm;
|
2022-02-02 15:30:39 +00:00
|
|
|
this.startSearchCounter = props.startSearchCounter;
|
2021-11-01 18:43:02 +00:00
|
|
|
|
|
|
|
if ('conversationResults' in props) {
|
|
|
|
this.searchHelper = new LeftPaneSearchHelper(props);
|
|
|
|
}
|
2021-02-23 20:34:28 +00:00
|
|
|
}
|
|
|
|
|
2021-11-12 23:44:20 +00:00
|
|
|
override getHeaderContents({
|
2021-02-23 20:34:28 +00:00
|
|
|
i18n,
|
|
|
|
showInbox,
|
|
|
|
}: Readonly<{
|
|
|
|
i18n: LocalizerType;
|
|
|
|
showInbox: () => void;
|
|
|
|
}>): ReactChild {
|
|
|
|
return (
|
|
|
|
<div className="module-left-pane__header__contents">
|
|
|
|
<button
|
2021-04-02 21:43:39 +00:00
|
|
|
onClick={this.getBackAction({ showInbox })}
|
2021-02-23 20:34:28 +00:00
|
|
|
className="module-left-pane__header__contents__back-button"
|
|
|
|
title={i18n('backToInbox')}
|
|
|
|
aria-label={i18n('backToInbox')}
|
|
|
|
type="button"
|
|
|
|
/>
|
|
|
|
<div className="module-left-pane__header__contents__text">
|
2022-01-27 22:12:26 +00:00
|
|
|
{i18n('archivedConversations')}
|
2021-02-23 20:34:28 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-01-27 22:12:26 +00:00
|
|
|
override getSearchInput({
|
2022-02-02 15:30:39 +00:00
|
|
|
clearConversationSearch,
|
2022-01-27 22:12:26 +00:00
|
|
|
clearSearch,
|
|
|
|
i18n,
|
|
|
|
updateSearchTerm,
|
|
|
|
}: Readonly<{
|
|
|
|
clearConversationSearch: () => unknown;
|
|
|
|
clearSearch: () => unknown;
|
|
|
|
i18n: LocalizerType;
|
|
|
|
updateSearchTerm: (searchTerm: string) => unknown;
|
|
|
|
}>): ReactChild | null {
|
|
|
|
if (!this.searchConversation) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
2022-02-14 17:57:11 +00:00
|
|
|
<LeftPaneSearchInput
|
2022-02-02 15:30:39 +00:00
|
|
|
clearConversationSearch={clearConversationSearch}
|
|
|
|
clearSearch={clearSearch}
|
2022-01-27 22:12:26 +00:00
|
|
|
i18n={i18n}
|
|
|
|
searchConversation={this.searchConversation}
|
2022-02-02 15:30:39 +00:00
|
|
|
searchTerm={this.searchTerm}
|
|
|
|
startSearchCounter={this.startSearchCounter}
|
|
|
|
updateSearchTerm={updateSearchTerm}
|
2022-01-27 22:12:26 +00:00
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-11-12 23:44:20 +00:00
|
|
|
override getBackAction({ showInbox }: { showInbox: () => void }): () => void {
|
2021-04-02 21:43:39 +00:00
|
|
|
return showInbox;
|
|
|
|
}
|
|
|
|
|
2021-11-12 23:44:20 +00:00
|
|
|
override getPreRowsNode({
|
2021-11-01 18:43:02 +00:00
|
|
|
i18n,
|
|
|
|
}: Readonly<{ i18n: LocalizerType }>): ReactChild | null {
|
|
|
|
if (this.searchHelper) {
|
|
|
|
return this.searchHelper.getPreRowsNode({ i18n });
|
|
|
|
}
|
|
|
|
|
2021-02-23 20:34:28 +00:00
|
|
|
return (
|
|
|
|
<div className="module-left-pane__archive-helper-text">
|
2022-01-06 21:06:33 +00:00
|
|
|
{this.getRowCount() > 0
|
|
|
|
? i18n('archiveHelperText')
|
|
|
|
: i18n('noArchivedConversations')}
|
2021-02-23 20:34:28 +00:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
getRowCount(): number {
|
2021-11-01 18:43:02 +00:00
|
|
|
return (
|
|
|
|
this.searchHelper?.getRowCount() ?? this.archivedConversations.length
|
|
|
|
);
|
2021-02-23 20:34:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
getRow(rowIndex: number): undefined | Row {
|
2021-11-01 18:43:02 +00:00
|
|
|
if (this.searchHelper) {
|
|
|
|
return this.searchHelper.getRow(rowIndex);
|
|
|
|
}
|
|
|
|
|
2021-02-23 20:34:28 +00:00
|
|
|
const conversation = this.archivedConversations[rowIndex];
|
|
|
|
return conversation
|
|
|
|
? {
|
|
|
|
type: RowType.Conversation,
|
|
|
|
conversation,
|
|
|
|
}
|
|
|
|
: undefined;
|
|
|
|
}
|
|
|
|
|
2021-11-12 23:44:20 +00:00
|
|
|
override getRowIndexToScrollTo(
|
2021-02-23 20:34:28 +00:00
|
|
|
selectedConversationId: undefined | string
|
|
|
|
): undefined | number {
|
2021-11-01 18:43:02 +00:00
|
|
|
if (this.searchHelper) {
|
|
|
|
return this.searchHelper.getRowIndexToScrollTo(selectedConversationId);
|
|
|
|
}
|
|
|
|
|
2021-02-23 20:34:28 +00:00
|
|
|
if (!selectedConversationId) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
const result = this.archivedConversations.findIndex(
|
|
|
|
conversation => conversation.id === selectedConversationId
|
|
|
|
);
|
|
|
|
return result === -1 ? undefined : result;
|
|
|
|
}
|
|
|
|
|
|
|
|
getConversationAndMessageAtIndex(
|
|
|
|
conversationIndex: number
|
|
|
|
): undefined | { conversationId: string } {
|
2021-11-01 18:43:02 +00:00
|
|
|
const { archivedConversations, searchHelper } = this;
|
|
|
|
|
|
|
|
if (searchHelper) {
|
|
|
|
return searchHelper.getConversationAndMessageAtIndex(conversationIndex);
|
|
|
|
}
|
|
|
|
|
2021-02-23 20:34:28 +00:00
|
|
|
const conversation =
|
|
|
|
archivedConversations[conversationIndex] || last(archivedConversations);
|
|
|
|
return conversation ? { conversationId: conversation.id } : undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
getConversationAndMessageInDirection(
|
|
|
|
toFind: Readonly<ToFindType>,
|
|
|
|
selectedConversationId: undefined | string,
|
2021-11-01 18:43:02 +00:00
|
|
|
selectedMessageId: unknown
|
2021-02-23 20:34:28 +00:00
|
|
|
): undefined | { conversationId: string } {
|
2021-11-01 18:43:02 +00:00
|
|
|
if (this.searchHelper) {
|
|
|
|
return this.searchHelper.getConversationAndMessageInDirection(
|
|
|
|
toFind,
|
|
|
|
selectedConversationId,
|
|
|
|
selectedMessageId
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-02-23 20:34:28 +00:00
|
|
|
return getConversationInDirection(
|
|
|
|
this.archivedConversations,
|
|
|
|
toFind,
|
|
|
|
selectedConversationId
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-11-01 18:43:02 +00:00
|
|
|
shouldRecomputeRowHeights(old: Readonly<LeftPaneArchivePropsType>): boolean {
|
|
|
|
const hasSearchingChanged =
|
|
|
|
'conversationResults' in old !== Boolean(this.searchHelper);
|
|
|
|
if (hasSearchingChanged) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ('conversationResults' in old && this.searchHelper) {
|
|
|
|
return this.searchHelper.shouldRecomputeRowHeights(old);
|
|
|
|
}
|
|
|
|
|
2021-02-23 20:34:28 +00:00
|
|
|
return false;
|
|
|
|
}
|
2021-11-01 18:43:02 +00:00
|
|
|
|
2021-11-12 23:44:20 +00:00
|
|
|
override onKeyDown(
|
2021-11-01 18:43:02 +00:00
|
|
|
event: KeyboardEvent,
|
|
|
|
{
|
|
|
|
searchInConversation,
|
|
|
|
selectedConversationId,
|
|
|
|
}: Readonly<{
|
|
|
|
searchInConversation: (conversationId: string) => unknown;
|
|
|
|
selectedConversationId: undefined | string;
|
|
|
|
}>
|
|
|
|
): void {
|
|
|
|
if (!selectedConversationId) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-31 05:58:28 +00:00
|
|
|
const { ctrlKey, metaKey, shiftKey } = event;
|
2021-11-01 18:43:02 +00:00
|
|
|
const commandKey = window.platform === 'darwin' && metaKey;
|
|
|
|
const controlKey = window.platform !== 'darwin' && ctrlKey;
|
|
|
|
const commandOrCtrl = commandKey || controlKey;
|
|
|
|
const commandAndCtrl = commandKey && ctrlKey;
|
2022-03-31 05:58:28 +00:00
|
|
|
const key = KeyboardLayout.lookup(event);
|
2021-11-01 18:43:02 +00:00
|
|
|
|
|
|
|
if (
|
|
|
|
commandOrCtrl &&
|
|
|
|
!commandAndCtrl &&
|
|
|
|
shiftKey &&
|
2022-03-31 05:58:28 +00:00
|
|
|
(key === 'f' || key === 'F') &&
|
2021-11-01 18:43:02 +00:00
|
|
|
this.archivedConversations.some(({ id }) => id === selectedConversationId)
|
|
|
|
) {
|
|
|
|
searchInConversation(selectedConversationId);
|
|
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
}
|
|
|
|
}
|
2021-02-23 20:34:28 +00:00
|
|
|
}
|