= createSelector(
diff --git a/src/react-native-action-sheet.js b/src/react-native-action-sheet.js
new file mode 100644
index 00000000000..16ec503fc19
--- /dev/null
+++ b/src/react-native-action-sheet.js
@@ -0,0 +1,29 @@
+/* @flow strict-local */
+import type { ComponentType, ElementConfig } from 'react';
+import { connectActionSheet as connectActionSheetInner } from '@expo/react-native-action-sheet';
+
+import type { BoundedDiff } from './generics';
+
+/* eslint-disable flowtype/generic-spacing */
+
+export type ShowActionSheetWithOptions = (
+ { options: string[], cancelButtonIndex: number },
+ (number) => void,
+) => void;
+
+/**
+ * Exactly like the `connectActionSheet` in
+ * `react-native-action-sheet` upstream, but more typed.
+ */
+export function connectActionSheet>(
+ WrappedComponent: C,
+): ComponentType<
+ $ReadOnly<
+ BoundedDiff<
+ $Exact>,
+ {| showActionSheetWithOptions: ShowActionSheetWithOptions |},
+ >,
+ >,
+> {
+ return connectActionSheetInner(WrappedComponent);
+}
diff --git a/src/search/SearchMessagesCard.js b/src/search/SearchMessagesCard.js
index d4a8912c886..8380f7aa36f 100644
--- a/src/search/SearchMessagesCard.js
+++ b/src/search/SearchMessagesCard.js
@@ -8,8 +8,6 @@ import { createStyleSheet } from '../styles';
import { LoadingIndicator, SearchEmptyState } from '../common';
import { HOME_NARROW } from '../utils/narrow';
import MessageList from '../webview/MessageList';
-import getHtmlPieceDescriptors from '../message/getHtmlPieceDescriptors';
-import { NULL_ARRAY } from '../nullObjects';
const styles = createStyleSheet({
results: {
@@ -23,8 +21,6 @@ type Props = $ReadOnly<{|
|}>;
export default class SearchMessagesCard extends PureComponent {
- static NOT_FETCHING = { older: false, newer: false };
-
render() {
const { isFetching, messages } = this.props;
@@ -44,18 +40,19 @@ export default class SearchMessagesCard extends PureComponent {
return ;
}
- const htmlPieceDescriptors = getHtmlPieceDescriptors(messages, HOME_NARROW);
+ // TODO: This is kind of a hack.
+ const narrow = HOME_NARROW;
return (
undefined}
/>
);
diff --git a/src/webview/MessageList.js b/src/webview/MessageList.js
index e38e0e485fc..8bd402080c0 100644
--- a/src/webview/MessageList.js
+++ b/src/webview/MessageList.js
@@ -1,10 +1,10 @@
/* @flow strict-local */
-import React, { Component } from 'react';
+import React, { Component, type ComponentType } from 'react';
import { Platform, NativeModules } from 'react-native';
import { WebView } from 'react-native-webview';
import type { WebViewNavigation } from 'react-native-webview';
-import { connectActionSheet } from '@expo/react-native-action-sheet';
+import { connectActionSheet } from '../react-native-action-sheet';
import type {
AlertWordsState,
Auth,
@@ -34,20 +34,18 @@ import {
getAllImageEmojiById,
getCurrentTypingUsers,
getDebug,
- getHtmlPieceDescriptorsForShownMessages,
getFlags,
getFetchingForNarrow,
- getFirstUnreadIdInNarrow,
getMute,
getMutedUsers,
getOwnUser,
getSettings,
getSubscriptions,
- getShownMessagesForNarrow,
getRealm,
} from '../selectors';
import { withGetText } from '../boot/TranslationProvider';
import type { ShowActionSheetWithOptions } from '../message/messageActionSheet';
+import { getHtmlPieceDescriptorsForMessages } from '../message/messageSelectors';
import type { WebViewInboundEvent } from './generateInboundEvents';
import type { WebViewOutboundEvent } from './handleOutboundEvents';
import getHtml from './html/html';
@@ -86,6 +84,14 @@ export type BackgroundData = $ReadOnly<{|
twentyFourHourTime: boolean,
|}>;
+type OuterProps = {|
+ narrow: Narrow,
+ messages: $ReadOnlyArray,
+ initialScrollMessageId: number | null,
+ showMessagePlaceholders: boolean,
+ startEditMessage: (editMessage: EditMessage) => void,
+|};
+
type SelectorProps = {|
// Data independent of the particular narrow or messages we're displaying.
backgroundData: BackgroundData,
@@ -93,18 +99,13 @@ type SelectorProps = {|
// The remaining props contain data specific to the particular narrow or
// particular messages we're displaying. Data that's independent of those
// should go in `BackgroundData`, above.
- initialScrollMessageId: number | null,
fetching: Fetching,
- messages: $ReadOnlyArray,
htmlPieceDescriptorsForShownMessages: HtmlPieceDescriptor[],
typingUsers: $ReadOnlyArray,
|};
-// TODO get a type for `connectActionSheet` so this gets fully type-checked.
export type Props = $ReadOnly<{|
- narrow: Narrow,
- showMessagePlaceholders: boolean,
- startEditMessage: (editMessage: EditMessage) => void,
+ ...OuterProps,
dispatch: Dispatch,
...SelectorProps,
@@ -145,7 +146,7 @@ const assetsUrl =
*/
const webviewAssetsUrl = new URL('webview/', assetsUrl);
-class MessageList extends Component {
+class MessageListInner extends Component {
static contextType = ThemeContext;
context: ThemeData;
@@ -299,52 +300,36 @@ class MessageList extends Component {
}
}
-type OuterProps = {|
- narrow: Narrow,
- showMessagePlaceholders: boolean,
-
- /* Remaining props are derived from `narrow` by default. */
-
- messages?: Message[],
- htmlPieceDescriptorsForShownMessages?: HtmlPieceDescriptor[],
- initialScrollMessageId?: number | null,
-
- /* Passing these two from the parent is kind of a hack; search uses it
- to hard-code some behavior. */
- fetching?: Fetching,
- typingUsers?: UserOrBot[],
-|};
-
-export default connect((state, props: OuterProps) => {
- // TODO Ideally this ought to be a caching selector that doesn't change
- // when the inputs don't. Doesn't matter in a practical way here, because
- // we have a `shouldComponentUpdate` that doesn't look at this prop... but
- // it'd be better to set an example of the right general pattern.
- const backgroundData: BackgroundData = {
- alertWords: state.alertWords,
- allImageEmojiById: getAllImageEmojiById(state),
- auth: getAuth(state),
- debug: getDebug(state),
- flags: getFlags(state),
- mute: getMute(state),
- mutedUsers: getMutedUsers(state),
- ownUser: getOwnUser(state),
- subscriptions: getSubscriptions(state),
- theme: getSettings(state).theme,
- twentyFourHourTime: getRealm(state).twentyFourHourTime,
- };
-
- return {
- backgroundData,
- initialScrollMessageId:
- props.initialScrollMessageId !== undefined
- ? props.initialScrollMessageId
- : getFirstUnreadIdInNarrow(state, props.narrow),
- fetching: props.fetching || getFetchingForNarrow(state, props.narrow),
- messages: props.messages || getShownMessagesForNarrow(state, props.narrow),
- htmlPieceDescriptorsForShownMessages:
- props.htmlPieceDescriptorsForShownMessages
- || getHtmlPieceDescriptorsForShownMessages(state, props.narrow),
- typingUsers: props.typingUsers || getCurrentTypingUsers(state, props.narrow),
- };
-})(connectActionSheet(withGetText(MessageList)));
+const MessageList: ComponentType = connect(
+ (state, props: OuterProps) => {
+ // TODO Ideally this ought to be a caching selector that doesn't change
+ // when the inputs don't. Doesn't matter in a practical way here, because
+ // we have a `shouldComponentUpdate` that doesn't look at this prop... but
+ // it'd be better to set an example of the right general pattern.
+ const backgroundData: BackgroundData = {
+ alertWords: state.alertWords,
+ allImageEmojiById: getAllImageEmojiById(state),
+ auth: getAuth(state),
+ debug: getDebug(state),
+ flags: getFlags(state),
+ mute: getMute(state),
+ mutedUsers: getMutedUsers(state),
+ ownUser: getOwnUser(state),
+ subscriptions: getSubscriptions(state),
+ theme: getSettings(state).theme,
+ twentyFourHourTime: getRealm(state).twentyFourHourTime,
+ };
+
+ return {
+ backgroundData,
+ fetching: getFetchingForNarrow(state, props.narrow),
+ htmlPieceDescriptorsForShownMessages: getHtmlPieceDescriptorsForMessages(
+ props.messages,
+ props.narrow,
+ ),
+ typingUsers: getCurrentTypingUsers(state, props.narrow),
+ };
+ },
+)(connectActionSheet(withGetText(MessageListInner)));
+
+export default MessageList;