Page MenuHomePhabricator

D10015.diff
No OneTemporary

D10015.diff

diff --git a/native/account/logged-out-modal.react.js b/native/account/logged-out-modal.react.js
--- a/native/account/logged-out-modal.react.js
+++ b/native/account/logged-out-modal.react.js
@@ -270,7 +270,7 @@
activeAlert = false;
contentHeight: Value;
- keyboardHeightValue = new Value(0);
+ keyboardHeightValue: Value = new Value(0);
modeValue: Value;
buttonOpacity: Value;
@@ -448,7 +448,7 @@
this.props.dispatch({ type: resetUserStateActionType });
}
- hardwareBack = () => {
+ hardwareBack: () => boolean = () => {
if (this.nextMode !== 'prompt') {
this.goBackToPrompt();
return true;
@@ -456,7 +456,7 @@
return false;
};
- panelPaddingTop() {
+ panelPaddingTop(): Node {
const headerHeight = Platform.OS === 'ios' ? 62.33 : 58.54;
const promptButtonsSize = Platform.OS === 'ios' ? 40 : 61;
const logInContainerSize = 140;
@@ -525,7 +525,7 @@
]);
}
- panelOpacity() {
+ panelOpacity(): Node {
const targetPanelOpacity = isPastPrompt(this.modeValue);
const panelOpacity = new Value(-1);
@@ -593,7 +593,7 @@
Keyboard.dismiss();
};
- render() {
+ render(): React.Node {
const { styles } = this.props;
const siweButton = (
diff --git a/native/account/register-panel.react.js b/native/account/register-panel.react.js
--- a/native/account/register-panel.react.js
+++ b/native/account/register-panel.react.js
@@ -84,7 +84,7 @@
confirmPasswordInput: ?TextInput;
passwordBeingAutoFilled = false;
- render() {
+ render(): React.Node {
let confirmPasswordTextInputExtraProps;
if (
Platform.OS !== 'ios' ||
@@ -346,7 +346,7 @@
);
};
- async registerAction(extraInfo: LogInExtraInfo) {
+ async registerAction(extraInfo: LogInExtraInfo): Promise<RegisterResult> {
try {
const result = await this.props.register({
...extraInfo,
diff --git a/native/account/registration/emoji-avatar-selection.react.js b/native/account/registration/emoji-avatar-selection.react.js
--- a/native/account/registration/emoji-avatar-selection.react.js
+++ b/native/account/registration/emoji-avatar-selection.react.js
@@ -6,6 +6,7 @@
import { EditUserAvatarContext } from 'lib/components/edit-user-avatar-provider.react.js';
import { getDefaultAvatar } from 'lib/shared/avatar-utils.js';
+import type { UpdateUserAvatarRequest } from 'lib/types/avatar-types';
import RegistrationContainer from './registration-container.react.js';
import RegistrationContentContainer from './registration-content-container.react.js';
@@ -38,7 +39,7 @@
const { goBack } = props.navigation;
const onSuccess = React.useCallback(
- avatarRequest => {
+ (avatarRequest: UpdateUserAvatarRequest) => {
goBack();
return nativeSetUserAvatar(avatarRequest);
},
diff --git a/native/account/siwe-hooks.js b/native/account/siwe-hooks.js
--- a/native/account/siwe-hooks.js
+++ b/native/account/siwe-hooks.js
@@ -4,7 +4,10 @@
import { siweAuth, siweAuthActionTypes } from 'lib/actions/siwe-actions.js';
import { useInitialNotificationsEncryptedMessage } from 'lib/shared/crypto-utils.js';
-import type { LogInStartingPayload } from 'lib/types/account-types.js';
+import type {
+ LogInStartingPayload,
+ LogInExtraInfo,
+} from 'lib/types/account-types.js';
import {
useServerCall,
useDispatchActionPromise,
@@ -32,7 +35,12 @@
const siweAuthCall = useServerCall(siweAuth);
const callSIWE = React.useCallback(
- async (message, signature, extraInfo, callServerEndpointOptions) => {
+ async (
+ message: string,
+ signature: string,
+ extraInfo: LogInExtraInfo,
+ callServerEndpointOptions: ?CallServerEndpointOptions,
+ ) => {
try {
return await siweAuthCall(
{
diff --git a/native/account/siwe-panel.react.js b/native/account/siwe-panel.react.js
--- a/native/account/siwe-panel.react.js
+++ b/native/account/siwe-panel.react.js
@@ -32,6 +32,14 @@
const siweAuthLoadingStatusSelector =
createLoadingStatusSelector(siweAuthActionTypes);
+type WebViewMessageEvent = {
+ +nativeEvent: {
+ +data: string,
+ ...
+ },
+ ...
+};
+
type Props = {
+onClosed: () => mixed,
+onClosing: () => mixed,
@@ -119,7 +127,7 @@
const closeBottomSheet = bottomSheetRef.current?.close;
const { closing, onSuccessfulWalletSignature } = props;
const handleMessage = React.useCallback(
- async event => {
+ async (event: WebViewMessageEvent) => {
const data: SIWEWebViewMessage = JSON.parse(event.nativeEvent.data);
if (data.type === 'siwe_success') {
const { address, message, signature } = data;
diff --git a/native/avatars/emoji-avatar-creation.react.js b/native/avatars/emoji-avatar-creation.react.js
--- a/native/avatars/emoji-avatar-creation.react.js
+++ b/native/avatars/emoji-avatar-creation.react.js
@@ -11,12 +11,13 @@
import type {
UpdateUserAvatarRequest,
ClientEmojiAvatar,
-} from 'lib/types/avatar-types';
+} from 'lib/types/avatar-types.js';
import Avatar from './avatar.react.js';
import Button from '../components/button.react.js';
import ColorRows from '../components/color-rows.react.js';
import EmojiKeyboard from '../components/emoji-keyboard.react.js';
+import type { EmojiSelection } from '../components/emoji-keyboard.react.js';
import { useStyles } from '../themes/colors.js';
type Props = {
@@ -60,7 +61,7 @@
setPendingColor(resetEmojiAvatar.color);
}, [savedEmojiAvatarFunc]);
- const onEmojiSelected = React.useCallback(emoji => {
+ const onEmojiSelected = React.useCallback((emoji: EmojiSelection) => {
setPendingEmoji(emoji.emoji);
}, []);
diff --git a/native/calendar/calendar.react.js b/native/calendar/calendar.react.js
--- a/native/calendar/calendar.react.js
+++ b/native/calendar/calendar.react.js
@@ -215,7 +215,7 @@
topLoaderWaitingToLeaveView = true;
bottomLoaderWaitingToLeaveView = true;
// We keep refs to the entries so CalendarInputBar can save them
- entryRefs = new Map();
+ entryRefs: Map<string, ?InternalEntry> = new Map();
constructor(props: Props) {
super(props);
@@ -389,7 +389,12 @@
static datesFromListData(
lastLDWH: $ReadOnlyArray<CalendarItemWithHeight>,
newLDWH: $ReadOnlyArray<CalendarItemWithHeight>,
- ) {
+ ): {
+ +lastStartDate: Date,
+ +newStartDate: Date,
+ +lastEndDate: Date,
+ +newEndDate: Date,
+ } {
const lastSecondItem = lastLDWH[1];
const newSecondItem = newLDWH[1];
invariant(
@@ -472,7 +477,7 @@
// ESLint doesn't recognize that invariant always throws
// eslint-disable-next-line consistent-return
- renderItem = (row: { item: CalendarItemWithHeight, ... }) => {
+ renderItem = (row: { +item: CalendarItemWithHeight, ... }): React.Node => {
const item = row.item;
if (item.itemType === 'loader') {
return <ListLoadingIndicator />;
@@ -500,7 +505,7 @@
invariant(false, 'renderItem conditions should be exhaustive');
};
- renderSectionHeader = (item: SectionHeaderItem) => {
+ renderSectionHeader = (item: SectionHeaderItem): React.Node => {
let date = prettyDate(item.dateString);
if (dateString(new Date()) === item.dateString) {
date += ' (today)';
@@ -519,7 +524,7 @@
);
};
- renderSectionFooter = (item: SectionFooterItem) => {
+ renderSectionFooter = (item: SectionFooterItem): React.Node => {
return (
<SectionFooter
dateString={item.dateString}
@@ -536,9 +541,11 @@
});
};
- // ESLint doesn't recognize that invariant always throws
- // eslint-disable-next-line consistent-return
- static keyExtractor = (item: CalendarItemWithHeight | CalendarItem) => {
+ static keyExtractor = (
+ item: CalendarItemWithHeight | CalendarItem,
+ // ESLint doesn't recognize that invariant always throws
+ // eslint-disable-next-line consistent-return
+ ): string => {
if (item.itemType === 'loader') {
return item.key;
} else if (item.itemType === 'header') {
@@ -554,7 +561,7 @@
static getItemLayout = (
data: ?$ReadOnlyArray<CalendarItemWithHeight>,
index: number,
- ) => {
+ ): { length: number, offset: number, index: number } => {
if (!data) {
return { length: 0, offset: 0, index };
}
@@ -566,7 +573,7 @@
// ESLint doesn't recognize that invariant always throws
// eslint-disable-next-line consistent-return
- static itemHeight = (item: CalendarItemWithHeight) => {
+ static itemHeight = (item: CalendarItemWithHeight): number => {
if (item.itemType === 'loader') {
return 56;
} else if (item.itemType === 'header') {
@@ -580,11 +587,13 @@
invariant(false, 'itemHeight conditions should be exhaustive');
};
- static heightOfItems = (data: $ReadOnlyArray<CalendarItemWithHeight>) => {
+ static heightOfItems = (
+ data: $ReadOnlyArray<CalendarItemWithHeight>,
+ ): number => {
return _sum(data.map(Calendar.itemHeight));
};
- render() {
+ render(): React.Node {
const { listDataWithHeights } = this.state;
let flatList = null;
if (listDataWithHeights) {
@@ -648,12 +657,12 @@
);
}
- flatListHeight() {
+ flatListHeight(): number {
const { safeAreaHeight, tabBarHeight } = this.props.dimensions;
return safeAreaHeight - tabBarHeight;
}
- initialScrollIndex(data: $ReadOnlyArray<CalendarItemWithHeight>) {
+ initialScrollIndex(data: $ReadOnlyArray<CalendarItemWithHeight>): number {
const todayIndex = _findIndex(['dateString', dateString(new Date())])(data);
const heightOfTodayHeader = Calendar.itemHeight(data[todayIndex]);
@@ -811,14 +820,14 @@
this.flatList.scrollToOffset({ offset, animated: true });
}
- heightMeasurerKey = (item: CalendarItem) => {
+ heightMeasurerKey = (item: CalendarItem): ?string => {
if (item.itemType !== 'entryInfo') {
return null;
}
return item.entryInfo.text;
};
- heightMeasurerDummy = (item: CalendarItem) => {
+ heightMeasurerDummy = (item: CalendarItem): React.MixedElement => {
invariant(
item.itemType === 'entryInfo',
'NodeHeightMeasurer asked for dummy for non-entryInfo item',
@@ -826,7 +835,10 @@
return dummyNodeForEntryHeightMeasurement(item.entryInfo.text);
};
- heightMeasurerMergeItem = (item: CalendarItem, height: ?number) => {
+ heightMeasurerMergeItem = (
+ item: CalendarItem,
+ height: ?number,
+ ): CalendarItemWithHeight => {
if (item.itemType !== 'entryInfo') {
return item;
}
@@ -994,7 +1006,7 @@
);
}
- loadMoreAbove = _throttle(() => {
+ loadMoreAbove: () => void = _throttle(() => {
if (
this.topLoadingFromScroll &&
this.topLoaderWaitingToLeaveView &&
@@ -1004,7 +1016,7 @@
}
}, 1000);
- loadMoreBelow = _throttle(() => {
+ loadMoreBelow: () => void = _throttle(() => {
if (
this.bottomLoadingFromScroll &&
this.bottomLoaderWaitingToLeaveView &&
diff --git a/native/calendar/section-footer.react.js b/native/calendar/section-footer.react.js
--- a/native/calendar/section-footer.react.js
+++ b/native/calendar/section-footer.react.js
@@ -48,7 +48,7 @@
+styles: typeof unboundStyles,
};
class SectionFooter extends React.PureComponent<Props> {
- render() {
+ render(): React.Node {
return (
<TouchableWithoutFeedback onPress={this.props.onPressWhitespace}>
<View style={this.props.styles.sectionFooter}>
diff --git a/native/chat/chat-input-bar.react.js b/native/chat/chat-input-bar.react.js
--- a/native/chat/chat-input-bar.react.js
+++ b/native/chat/chat-input-bar.react.js
@@ -1,6 +1,7 @@
// @flow
import Icon from '@expo/vector-icons/Ionicons.js';
+import type { GenericNavigationAction } from '@react-navigation/core';
import invariant from 'invariant';
import _throttle from 'lodash/throttle.js';
import * as React from 'react';
@@ -455,17 +456,17 @@
this.sendButtonContainerStyle = { width: sendButtonContainerWidth };
}
- static mediaGalleryOpen(props: Props) {
+ static mediaGalleryOpen(props: Props): boolean {
const { keyboardState } = props;
return !!(keyboardState && keyboardState.mediaGalleryOpen);
}
- static systemKeyboardShowing(props: Props) {
+ static systemKeyboardShowing(props: Props): boolean {
const { keyboardState } = props;
return !!(keyboardState && keyboardState.systemKeyboardShowing);
}
- get systemKeyboardShowing() {
+ get systemKeyboardShowing(): boolean {
return ChatInputBar.systemKeyboardShowing(this.props);
}
@@ -629,7 +630,7 @@
return checkIfDefaultMembersAreVoiced(this.props.threadInfo);
}
- render() {
+ render(): React.Node {
const isMember = viewerIsMember(this.props.threadInfo);
const canJoin = threadHasPermission(
this.props.threadInfo,
@@ -805,7 +806,7 @@
);
}
- renderInput() {
+ renderInput(): React.Node {
const expandoButton = (
<TouchableOpacity
onPress={this.expandButtons}
@@ -929,7 +930,7 @@
this.setState({ selectionState: data });
};
- saveDraft = _throttle(text => {
+ saveDraft: (text: string) => void = _throttle(text => {
this.props.dispatch({
type: updateDraftActionType,
payload: {
@@ -1021,14 +1022,14 @@
);
};
- isEditMode = () => {
+ isEditMode = (): boolean => {
const editState = this.props.messageEditingContext?.editState;
const isThisThread =
editState?.editedMessage?.threadID === this.props.threadInfo.id;
- return editState && editState.editedMessage !== null && isThisThread;
+ return editState?.editedMessage !== null && isThisThread;
};
- isMessageEdited = newText => {
+ isMessageEdited = (newText?: string): boolean => {
let text = newText ?? this.state.text;
text = trimMessage(text);
const originalText = this.props.editedMessageInfo?.text;
@@ -1097,7 +1098,7 @@
}
};
- getEditedMessage = () => {
+ getEditedMessage = (): ?MessageInfo => {
const editState = this.props.messageEditingContext?.editState;
return editState?.editedMessage;
};
@@ -1144,7 +1145,11 @@
);
};
- onNavigationBeforeRemove = e => {
+ onNavigationBeforeRemove = (e: {
+ +data: { +action: GenericNavigationAction },
+ +preventDefault: () => void,
+ ...
+ }) => {
if (!this.isEditMode()) {
return;
}
@@ -1173,7 +1178,7 @@
this.props.dispatchActionPromise(joinThreadActionTypes, this.joinAction());
};
- async joinAction() {
+ async joinAction(): Promise<ThreadJoinPayload> {
const query = this.props.calendarQuery();
return await this.props.joinThread({
threadID: this.props.threadInfo.id,
diff --git a/native/chat/chat-list.react.js b/native/chat/chat-list.react.js
--- a/native/chat/chat-list.react.js
+++ b/native/chat/chat-list.react.js
@@ -70,7 +70,7 @@
flatList: ?FlatListElementRef;
scrollPos = 0;
- newMessagesPillProgress = new Animated.Value(0);
+ newMessagesPillProgress: Animated.Value = new Animated.Value(0);
newMessagesPillStyle: ViewStyle;
constructor(props: Props) {
@@ -125,7 +125,7 @@
}
};
- get scrolledToBottom() {
+ get scrolledToBottom(): boolean {
return this.scrollPos <= 0;
}
@@ -218,7 +218,7 @@
}
}
- render() {
+ render(): React.Node {
const { navigation, viewerID, ...rest } = this.props;
const { newMessageCount } = this.state;
return (
@@ -250,7 +250,7 @@
static getItemLayout = (
data: ?$ReadOnlyArray<ChatMessageItemWithHeight>,
index: number,
- ) => {
+ ): { length: number, offset: number, index: number } => {
if (!data) {
return { length: 0, offset: 0, index };
}
diff --git a/native/chat/chat.react.js b/native/chat/chat.react.js
--- a/native/chat/chat.react.js
+++ b/native/chat/chat.react.js
@@ -13,6 +13,8 @@
ParamListBase,
StackRouterOptions,
MaterialTopTabNavigationHelpers,
+ HeaderTitleInputProps,
+ StackHeaderLeftButtonProps,
} from '@react-navigation/core';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
import {
@@ -72,6 +74,7 @@
type ChatTopTabsParamList,
MessageSearchRouteName,
ChangeRolesScreenRouteName,
+ type NavigationRoute,
} from '../navigation/route-names.js';
import type { TabNavigationProp } from '../navigation/tab-navigator.react.js';
import ChangeRolesHeaderLeftButton from '../roles/change-roles-header-left-button.react.js';
@@ -107,14 +110,14 @@
const homeChatThreadListOptions = {
title: 'Focused',
// eslint-disable-next-line react/display-name
- tabBarIcon: ({ color }) => (
+ tabBarIcon: ({ color }: { +color: string, ... }) => (
<SWMansionIcon name="home-1" size={22} style={{ color }} />
),
};
const backgroundChatThreadListOptions = {
title: 'Background',
// eslint-disable-next-line react/display-name
- tabBarIcon: ({ color }) => (
+ tabBarIcon: ({ color }: { +color: string, ... }) => (
<SWMansionIcon name="bell-disabled" size={22} style={{ color }} />
),
};
@@ -234,7 +237,13 @@
const headerRightStyle = { flexDirection: 'row' };
-const messageListOptions = ({ navigation, route }) => {
+const messageListOptions = ({
+ navigation,
+ route,
+}: {
+ +navigation: ChatNavigationProp<'MessageList'>,
+ +route: NavigationRoute<'MessageList'>,
+}) => {
const isSearchEmpty =
!!route.params.searching && route.params.threadInfo.members.length === 1;
@@ -244,7 +253,7 @@
return {
// This is a render prop, not a component
// eslint-disable-next-line react/display-name
- headerTitle: props => (
+ headerTitle: (props: HeaderTitleInputProps) => (
<MessageListHeaderTitle
threadInfo={route.params.threadInfo}
navigate={navigation.navigate}
@@ -279,9 +288,14 @@
headerTitle: 'Compose chat',
headerBackTitleVisible: false,
};
-const threadSettingsOptions = ({ route }) => ({
+const threadSettingsOptions = ({
+ route,
+}: {
+ +route: NavigationRoute<'ThreadSettings'>,
+ ...
+}) => ({
// eslint-disable-next-line react/display-name
- headerTitle: props => (
+ headerTitle: (props: HeaderTitleInputProps) => (
<ThreadSettingsHeaderTitle
threadInfo={route.params.threadInfo}
{...props}
@@ -313,9 +327,14 @@
headerTitle: 'Pinned Messages',
headerBackTitleVisible: false,
};
-const changeRolesScreenOptions = ({ route }) => ({
+const changeRolesScreenOptions = ({
+ route,
+}: {
+ +route: NavigationRoute<'ChangeRolesScreen'>,
+ ...
+}) => ({
// eslint-disable-next-line react/display-name
- headerLeft: headerLeftProps => (
+ headerLeft: (headerLeftProps: StackHeaderLeftButtonProps) => (
<ChangeRolesHeaderLeftButton {...headerLeftProps} route={route} />
),
headerTitle: 'Change Role',
@@ -349,7 +368,7 @@
}
const headerLeftButton = React.useCallback(
- headerProps => {
+ (headerProps: StackHeaderLeftButtonProps) => {
if (headerProps.canGoBack) {
return <HeaderBackButton {...headerProps} />;
}
@@ -379,7 +398,12 @@
);
const chatThreadListOptions = React.useCallback(
- ({ navigation }) => ({
+ ({
+ navigation,
+ }: {
+ +navigation: ChatNavigationProp<'ChatThreadList'>,
+ ...
+ }) => ({
headerTitle: 'Inbox',
headerRight:
Platform.OS === 'ios'
diff --git a/native/chat/failed-send.react.js b/native/chat/failed-send.react.js
--- a/native/chat/failed-send.react.js
+++ b/native/chat/failed-send.react.js
@@ -86,7 +86,7 @@
}
}
- render() {
+ render(): React.Node {
if (!this.props.rawMessageInfo) {
return null;
}
diff --git a/native/chat/message-list-container.react.js b/native/chat/message-list-container.react.js
--- a/native/chat/message-list-container.react.js
+++ b/native/chat/message-list-container.react.js
@@ -107,7 +107,7 @@
};
pendingListDataWithHeights: ?$ReadOnlyArray<ChatMessageItemWithHeight>;
- get frozen() {
+ get frozen(): boolean {
const { overlayContext } = this.props;
invariant(
overlayContext,
@@ -155,7 +155,7 @@
}
}
- render() {
+ render(): React.Node {
const { threadInfo, styles } = this.props;
const { listDataWithHeights } = this.state;
const { searching } = this.props.route.params;
diff --git a/native/chat/message-list-header-title.react.js b/native/chat/message-list-header-title.react.js
--- a/native/chat/message-list-header-title.react.js
+++ b/native/chat/message-list-header-title.react.js
@@ -43,7 +43,7 @@
+title: string,
};
class MessageListHeaderTitle extends React.PureComponent<Props> {
- render() {
+ render(): React.Node {
const {
threadInfo,
navigate,
diff --git a/native/chat/message-list.react.js b/native/chat/message-list.react.js
--- a/native/chat/message-list.react.js
+++ b/native/chat/message-list.react.js
@@ -113,40 +113,41 @@
};
flatListContainer: ?React.ElementRef<typeof View>;
- flatListExtraDataSelector = createSelector(
- (propsAndState: PropsAndState) => propsAndState.messageListVerticalBounds,
- (propsAndState: PropsAndState) => propsAndState.focusedMessageKey,
- (propsAndState: PropsAndState) => propsAndState.navigation,
- (propsAndState: PropsAndState) => propsAndState.route,
- (
- messageListVerticalBounds: ?VerticalBounds,
- focusedMessageKey: ?string,
- navigation: ChatNavigationProp<'MessageList'>,
- route: NavigationRoute<'MessageList'>,
- ) => ({
- messageListVerticalBounds,
- focusedMessageKey,
- navigation,
- route,
- }),
- );
+ flatListExtraDataSelector: PropsAndState => FlatListExtraData =
+ createSelector(
+ (propsAndState: PropsAndState) => propsAndState.messageListVerticalBounds,
+ (propsAndState: PropsAndState) => propsAndState.focusedMessageKey,
+ (propsAndState: PropsAndState) => propsAndState.navigation,
+ (propsAndState: PropsAndState) => propsAndState.route,
+ (
+ messageListVerticalBounds: ?VerticalBounds,
+ focusedMessageKey: ?string,
+ navigation: ChatNavigationProp<'MessageList'>,
+ route: NavigationRoute<'MessageList'>,
+ ) => ({
+ messageListVerticalBounds,
+ focusedMessageKey,
+ navigation,
+ route,
+ }),
+ );
get flatListExtraData(): FlatListExtraData {
return this.flatListExtraDataSelector({ ...this.props, ...this.state });
}
- static getOverlayContext(props: Props) {
+ static getOverlayContext(props: Props): OverlayContextType {
const { overlayContext } = props;
invariant(overlayContext, 'MessageList should have OverlayContext');
return overlayContext;
}
- static scrollDisabled(props: Props) {
+ static scrollDisabled(props: Props): boolean {
const overlayContext = MessageList.getOverlayContext(props);
return overlayContext.scrollBlockingModalStatus !== 'closed';
}
- static modalOpen(props: Props) {
+ static modalOpen(props: Props): boolean {
const overlayContext = MessageList.getOverlayContext(props);
return overlayContext.scrollBlockingModalStatus === 'open';
}
@@ -174,7 +175,7 @@
keyboardState && keyboardState.dismissKeyboard();
};
- renderItem = (row: { item: ChatMessageItemWithHeight, ... }) => {
+ renderItem = (row: { item: ChatMessageItemWithHeight, ... }): React.Node => {
if (row.item.itemType === 'loader') {
return (
<TouchableWithoutFeedback onPress={this.dismissKeyboard}>
@@ -211,9 +212,11 @@
};
// Actually header, it's just that our FlatList is inverted
- ListFooterComponent = () => <View style={this.props.styles.header} />;
+ ListFooterComponent = (): React.Node => (
+ <View style={this.props.styles.header} />
+ );
- render() {
+ render(): React.Node {
const { messageListData, startReached } = this.props;
const footer = startReached ? this.ListFooterComponent : undefined;
let relationshipPrompt = null;
diff --git a/native/chat/message-reactions-modal.react.js b/native/chat/message-reactions-modal.react.js
--- a/native/chat/message-reactions-modal.react.js
+++ b/native/chat/message-reactions-modal.react.js
@@ -12,7 +12,10 @@
import { SafeAreaView } from 'react-native-safe-area-context';
import type { ReactionInfo } from 'lib/selectors/chat-selectors.js';
-import { useMessageReactionsList } from 'lib/shared/reaction-utils.js';
+import {
+ useMessageReactionsList,
+ type MessageReactionListInfo,
+} from 'lib/shared/reaction-utils.js';
import UserAvatar from '../avatars/user-avatar.react.js';
import Modal from '../components/modal.react.js';
@@ -70,7 +73,7 @@
);
const renderItem = React.useCallback(
- ({ item }) => (
+ ({ item }: { +item: MessageReactionListInfo, ... }) => (
<TouchableOpacity
onPress={() => onPressUser(item.id)}
key={item.id}
diff --git a/native/chat/multimedia-message-multimedia.react.js b/native/chat/multimedia-message-multimedia.react.js
--- a/native/chat/multimedia-message-multimedia.react.js
+++ b/native/chat/multimedia-message-multimedia.react.js
@@ -74,7 +74,7 @@
};
}
- static getOverlayContext(props: Props) {
+ static getOverlayContext(props: Props): OverlayContextType {
const { overlayContext } = props;
invariant(
overlayContext,
@@ -83,7 +83,7 @@
return overlayContext;
}
- static getModalOverlayPosition(props: Props) {
+ static getModalOverlayPosition(props: Props): ?Animated.Value {
const overlayContext = MultimediaMessageMultimedia.getOverlayContext(props);
const { visibleOverlays } = overlayContext;
for (const overlay of visibleOverlays) {
@@ -98,7 +98,7 @@
return undefined;
}
- getOpacity() {
+ getOpacity(): number | Animated.Node {
const overlayPosition = MultimediaMessageMultimedia.getModalOverlayPosition(
this.props,
);
@@ -136,7 +136,7 @@
}
}
- render() {
+ render(): React.Node {
const { opacity } = this.state;
const animatedWrapperStyle: AnimatedStyleObj = { opacity };
const wrapperStyles = [
@@ -202,7 +202,7 @@
});
};
- dismissKeyboardIfShowing = () => {
+ dismissKeyboardIfShowing = (): boolean => {
const { keyboardState } = this.props;
return !!(keyboardState && keyboardState.dismissKeyboardIfShowing());
};
diff --git a/native/chat/multimedia-message-tooltip-button.react.js b/native/chat/multimedia-message-tooltip-button.react.js
--- a/native/chat/multimedia-message-tooltip-button.react.js
+++ b/native/chat/multimedia-message-tooltip-button.react.js
@@ -18,6 +18,7 @@
import SidebarInputBarHeightMeasurer from './sidebar-input-bar-height-measurer.react.js';
import { useAnimatedMessageTooltipButton } from './utils.js';
import EmojiKeyboard from '../components/emoji-keyboard.react.js';
+import type { EmojiSelection } from '../components/emoji-keyboard.react.js';
import type { AppNavigationProp } from '../navigation/app-navigator.react.js';
import { useSelector } from '../redux/redux-utils.js';
import { useTooltipActions } from '../tooltip/tooltip-hooks.js';
@@ -147,7 +148,7 @@
const { dismissTooltip } = useTooltipActions(navigation, tooltipRouteKey);
const onEmojiSelected = React.useCallback(
- emoji => {
+ (emoji: EmojiSelection) => {
sendReaction(emoji.emoji);
dismissTooltip();
},
diff --git a/native/chat/multimedia-message-tooltip-modal.react.js b/native/chat/multimedia-message-tooltip-modal.react.js
--- a/native/chat/multimedia-message-tooltip-modal.react.js
+++ b/native/chat/multimedia-message-tooltip-modal.react.js
@@ -16,6 +16,7 @@
} from '../tooltip/tooltip.react.js';
import type { ChatMultimediaMessageInfoItem } from '../types/chat-types.js';
import type { VerticalBounds } from '../types/layout-types.js';
+import type { TextStyle } from '../types/styles.js';
import { useNavigateToPinModal } from '../utils/toggle-pin-utils.js';
export type MultimediaMessageTooltipModalParams = TooltipParams<{
@@ -33,17 +34,21 @@
const onPressTogglePin = useNavigateToPinModal(overlayContext, route);
const renderPinIcon = React.useCallback(
- style => <CommIcon name="pin-outline" style={style} size={16} />,
+ (style: TextStyle) => (
+ <CommIcon name="pin-outline" style={style} size={16} />
+ ),
[],
);
const renderUnpinIcon = React.useCallback(
- style => <CommIcon name="unpin-outline" style={style} size={16} />,
+ (style: TextStyle) => (
+ <CommIcon name="unpin-outline" style={style} size={16} />
+ ),
[],
);
const onPressSidebar = useAnimatedNavigateToSidebar(route.params.item);
const renderSidebarIcon = React.useCallback(
- style => (
+ (style: TextStyle) => (
<SWMansionIcon name="message-circle-lines" style={style} size={16} />
),
[],
@@ -51,7 +56,9 @@
const onPressReport = useOnPressReport(route);
const renderReportIcon = React.useCallback(
- style => <SWMansionIcon name="warning-circle" style={style} size={16} />,
+ (style: TextStyle) => (
+ <SWMansionIcon name="warning-circle" style={style} size={16} />
+ ),
[],
);
diff --git a/native/chat/multimedia-message.react.js b/native/chat/multimedia-message.react.js
--- a/native/chat/multimedia-message.react.js
+++ b/native/chat/multimedia-message.react.js
@@ -86,7 +86,7 @@
});
};
- visibleEntryIDs() {
+ visibleEntryIDs(): $ReadOnlyArray<string> {
const result = [];
if (this.props.canTogglePins) {
@@ -182,14 +182,14 @@
});
};
- canNavigateToSidebar() {
+ canNavigateToSidebar(): boolean {
return (
- this.props.item.threadCreatedFromMessage ||
+ !!this.props.item.threadCreatedFromMessage ||
this.props.canCreateSidebarFromMessage
);
}
- render() {
+ render(): React.Node {
const {
item,
focused,
diff --git a/native/chat/robotext-message-tooltip-button.react.js b/native/chat/robotext-message-tooltip-button.react.js
--- a/native/chat/robotext-message-tooltip-button.react.js
+++ b/native/chat/robotext-message-tooltip-button.react.js
@@ -17,6 +17,7 @@
import { Timestamp } from './timestamp.react.js';
import { useAnimatedMessageTooltipButton } from './utils.js';
import EmojiKeyboard from '../components/emoji-keyboard.react.js';
+import type { EmojiSelection } from '../components/emoji-keyboard.react.js';
import type { AppNavigationProp } from '../navigation/app-navigator.react.js';
import { useSelector } from '../redux/redux-utils.js';
import { useTooltipActions } from '../tooltip/tooltip-hooks.js';
@@ -130,7 +131,7 @@
const { dismissTooltip } = useTooltipActions(navigation, tooltipRouteKey);
const onEmojiSelected = React.useCallback(
- emoji => {
+ (emoji: EmojiSelection) => {
sendReaction(emoji.emoji);
dismissTooltip();
},
diff --git a/native/chat/robotext-message-tooltip-modal.react.js b/native/chat/robotext-message-tooltip-modal.react.js
--- a/native/chat/robotext-message-tooltip-modal.react.js
+++ b/native/chat/robotext-message-tooltip-modal.react.js
@@ -12,6 +12,7 @@
type TooltipMenuProps,
} from '../tooltip/tooltip.react.js';
import type { ChatRobotextMessageInfoItemWithHeight } from '../types/chat-types.js';
+import type { TextStyle } from '../types/styles.js';
export type RobotextMessageTooltipModalParams = TooltipParams<{
+item: ChatRobotextMessageInfoItemWithHeight,
@@ -24,7 +25,7 @@
const onPress = useAnimatedNavigateToSidebar(route.params.item);
const renderIcon = React.useCallback(
- style => (
+ (style: TextStyle) => (
<SWMansionIcon name="message-circle-lines" style={style} size={16} />
),
[],
diff --git a/native/chat/robotext-message.react.js b/native/chat/robotext-message.react.js
--- a/native/chat/robotext-message.react.js
+++ b/native/chat/robotext-message.react.js
@@ -106,7 +106,14 @@
}, [item.threadCreatedFromMessage, canCreateSidebarFromMessage]);
const openRobotextTooltipModal = React.useCallback(
- (x, y, width, height, pageX, pageY) => {
+ (
+ x: number,
+ y: number,
+ width: number,
+ height: number,
+ pageX: number,
+ pageY: number,
+ ) => {
invariant(
verticalBounds,
'verticalBounds should be present in openRobotextTooltipModal',
diff --git a/native/chat/settings/compose-subchannel-modal.react.js b/native/chat/settings/compose-subchannel-modal.react.js
--- a/native/chat/settings/compose-subchannel-modal.react.js
+++ b/native/chat/settings/compose-subchannel-modal.react.js
@@ -69,7 +69,7 @@
+styles: typeof unboundStyles,
};
class ComposeSubchannelModal extends React.PureComponent<Props> {
- render() {
+ render(): React.Node {
return (
<Modal modalStyle={this.props.styles.modal}>
<Text style={this.props.styles.visibility}>Chat type</Text>
diff --git a/native/chat/settings/delete-thread.react.js b/native/chat/settings/delete-thread.react.js
--- a/native/chat/settings/delete-thread.react.js
+++ b/native/chat/settings/delete-thread.react.js
@@ -142,7 +142,7 @@
this.mounted = false;
}
- render() {
+ render(): React.Node {
const buttonContent =
this.props.loadingStatus === 'loading' ? (
<ActivityIndicator size="small" color="white" />
@@ -207,7 +207,7 @@
);
};
- async deleteThread() {
+ async deleteThread(): Promise<LeaveThreadPayload> {
const { threadInfo, navDispatch } = this.props;
navDispatch({
type: clearThreadsActionType,
diff --git a/native/chat/settings/emoji-thread-avatar-creation.react.js b/native/chat/settings/emoji-thread-avatar-creation.react.js
--- a/native/chat/settings/emoji-thread-avatar-creation.react.js
+++ b/native/chat/settings/emoji-thread-avatar-creation.react.js
@@ -5,6 +5,7 @@
import { EditThreadAvatarContext } from 'lib/components/base-edit-thread-avatar-provider.react.js';
import { savedEmojiAvatarSelectorForThread } from 'lib/selectors/thread-selectors.js';
+import type { UpdateUserAvatarRequest } from 'lib/types/avatar-types.js';
import type {
MinimallyEncodedRawThreadInfo,
MinimallyEncodedThreadInfo,
@@ -47,7 +48,7 @@
const nativeSetThreadAvatar = useNativeSetThreadAvatar();
const setAvatar = React.useCallback(
- async avatarRequest => {
+ async (avatarRequest: UpdateUserAvatarRequest) => {
const result = await nativeSetThreadAvatar(threadID, avatarRequest);
displayActionResultModal('Avatar updated!');
return result;
diff --git a/native/chat/settings/thread-settings-color.react.js b/native/chat/settings/thread-settings-color.react.js
--- a/native/chat/settings/thread-settings-color.react.js
+++ b/native/chat/settings/thread-settings-color.react.js
@@ -54,7 +54,7 @@
+styles: typeof unboundStyles,
};
class ThreadSettingsColor extends React.PureComponent<Props> {
- render() {
+ render(): React.Node {
let colorButton;
if (this.props.loadingStatus !== 'loading') {
colorButton = (
diff --git a/native/chat/settings/thread-settings-description.react.js b/native/chat/settings/thread-settings-description.react.js
--- a/native/chat/settings/thread-settings-description.react.js
+++ b/native/chat/settings/thread-settings-description.react.js
@@ -111,7 +111,7 @@
class ThreadSettingsDescription extends React.PureComponent<Props> {
textInput: ?React.ElementRef<typeof BaseTextInput>;
- render() {
+ render(): React.Node {
if (
this.props.descriptionEditValue !== null &&
this.props.descriptionEditValue !== undefined
@@ -197,7 +197,7 @@
return null;
}
- renderButton() {
+ renderButton(): React.Node {
if (this.props.loadingStatus === 'loading') {
return (
<ActivityIndicator
@@ -264,7 +264,9 @@
});
};
- async editDescription(newDescription: string) {
+ async editDescription(
+ newDescription: string,
+ ): Promise<ChangeThreadSettingsPayload> {
try {
return await this.props.changeThreadSettings({
threadID: this.props.threadInfo.id,
diff --git a/native/chat/settings/thread-settings-home-notifs.react.js b/native/chat/settings/thread-settings-home-notifs.react.js
--- a/native/chat/settings/thread-settings-home-notifs.react.js
+++ b/native/chat/settings/thread-settings-home-notifs.react.js
@@ -66,7 +66,7 @@
};
}
- render() {
+ render(): React.Node {
const componentLabel = 'Background';
return (
<View style={this.props.styles.row}>
diff --git a/native/chat/settings/thread-settings-leave-thread.react.js b/native/chat/settings/thread-settings-leave-thread.react.js
--- a/native/chat/settings/thread-settings-leave-thread.react.js
+++ b/native/chat/settings/thread-settings-leave-thread.react.js
@@ -67,7 +67,7 @@
+navContext: ?NavContextType,
};
class ThreadSettingsLeaveThread extends React.PureComponent<Props> {
- render() {
+ render(): React.Node {
const { panelIosHighlightUnderlay, panelForegroundSecondaryLabel } =
this.props.colors;
const loadingIndicator =
@@ -122,7 +122,7 @@
);
};
- async leaveThread() {
+ async leaveThread(): Promise<LeaveThreadPayload> {
const threadID = this.props.threadInfo.id;
const { navContext } = this.props;
invariant(navContext, 'navContext should exist in leaveThread');
diff --git a/native/chat/settings/thread-settings-media-gallery.react.js b/native/chat/settings/thread-settings-media-gallery.react.js
--- a/native/chat/settings/thread-settings-media-gallery.react.js
+++ b/native/chat/settings/thread-settings-media-gallery.react.js
@@ -101,7 +101,7 @@
}, [activeTab, mediaInfos]);
const renderItem = React.useCallback(
- ({ item, index }) => (
+ ({ item, index }: { +item: Media, +index: number, ... }) => (
<MediaGalleryItem
item={item}
index={index}
diff --git a/native/chat/settings/thread-settings-member.react.js b/native/chat/settings/thread-settings-member.react.js
--- a/native/chat/settings/thread-settings-member.react.js
+++ b/native/chat/settings/thread-settings-member.react.js
@@ -119,7 +119,7 @@
class ThreadSettingsMember extends React.PureComponent<Props> {
editButton: ?React.ElementRef<typeof View>;
- render() {
+ render(): React.Node {
const userText = stringForUser(this.props.memberInfo);
let usernameInfo = null;
@@ -248,7 +248,7 @@
});
};
- dismissKeyboardIfShowing = () => {
+ dismissKeyboardIfShowing = (): boolean => {
const { keyboardState } = this.props;
return !!(keyboardState && keyboardState.dismissKeyboardIfShowing());
};
diff --git a/native/chat/settings/thread-settings-name.react.js b/native/chat/settings/thread-settings-name.react.js
--- a/native/chat/settings/thread-settings-name.react.js
+++ b/native/chat/settings/thread-settings-name.react.js
@@ -83,7 +83,7 @@
class ThreadSettingsName extends React.PureComponent<Props> {
textInput: ?React.ElementRef<typeof BaseTextInput>;
- render() {
+ render(): React.Node {
return (
<View style={this.props.styles.row}>
<Text style={this.props.styles.label}>Name</Text>
@@ -92,7 +92,7 @@
);
}
- renderButton() {
+ renderButton(): React.Node {
if (this.props.loadingStatus === 'loading') {
return (
<ActivityIndicator
@@ -114,7 +114,7 @@
return <SaveSettingButton onPress={this.onSubmit} />;
}
- renderContent() {
+ renderContent(): React.Node {
if (
this.props.nameEditValue === null ||
this.props.nameEditValue === undefined
@@ -152,7 +152,7 @@
this.textInput = textInput;
};
- threadEditName() {
+ threadEditName(): string {
return firstLine(
this.props.threadInfo.name ? this.props.threadInfo.name : '',
);
@@ -191,7 +191,7 @@
});
};
- async editName(newName: string) {
+ async editName(newName: string): Promise<ChangeThreadSettingsPayload> {
try {
return await this.props.changeThreadSettings({
threadID: this.props.threadInfo.id,
diff --git a/native/chat/settings/thread-settings-promote-sidebar.react.js b/native/chat/settings/thread-settings-promote-sidebar.react.js
--- a/native/chat/settings/thread-settings-promote-sidebar.react.js
+++ b/native/chat/settings/thread-settings-promote-sidebar.react.js
@@ -59,7 +59,7 @@
);
};
- render() {
+ render(): React.Node {
const { panelIosHighlightUnderlay, panelForegroundSecondaryLabel } =
this.props.colors;
const loadingIndicator =
diff --git a/native/chat/settings/thread-settings-push-notifs.react.js b/native/chat/settings/thread-settings-push-notifs.react.js
--- a/native/chat/settings/thread-settings-push-notifs.react.js
+++ b/native/chat/settings/thread-settings-push-notifs.react.js
@@ -79,7 +79,7 @@
};
}
- render() {
+ render(): React.Node {
const componentLabel = 'Push notifs';
let notificationsSettingsLinkingIcon: React.Node = undefined;
if (!this.props.hasPushPermissions) {
diff --git a/native/chat/settings/thread-settings.react.js b/native/chat/settings/thread-settings.react.js
--- a/native/chat/settings/thread-settings.react.js
+++ b/native/chat/settings/thread-settings.react.js
@@ -312,7 +312,7 @@
};
}
- static scrollDisabled(props: Props) {
+ static scrollDisabled(props: Props): boolean {
const { overlayContext } = props;
invariant(overlayContext, 'ThreadSettings should have OverlayContext');
return overlayContext.scrollBlockingModalStatus !== 'closed';
@@ -340,548 +340,557 @@
}
}
- threadBasicsListDataSelector = createSelector(
- (propsAndState: PropsAndState) => propsAndState.threadInfo,
- (propsAndState: PropsAndState) => propsAndState.parentThreadInfo,
- (propsAndState: PropsAndState) => propsAndState.nameEditValue,
- (propsAndState: PropsAndState) => propsAndState.colorEditValue,
- (propsAndState: PropsAndState) => propsAndState.descriptionEditValue,
- (propsAndState: PropsAndState) => propsAndState.descriptionTextHeight,
- (propsAndState: PropsAndState) => !propsAndState.somethingIsSaving,
- (propsAndState: PropsAndState) => propsAndState.navigation.navigate,
- (propsAndState: PropsAndState) => propsAndState.route.key,
- (
- threadInfo: ResolvedThreadInfo | MinimallyEncodedResolvedThreadInfo,
- parentThreadInfo:
- | ?ResolvedThreadInfo
- | ?MinimallyEncodedResolvedThreadInfo,
- nameEditValue: ?string,
- colorEditValue: string,
- descriptionEditValue: ?string,
- descriptionTextHeight: ?number,
- canStartEditing: boolean,
- navigate: ThreadSettingsNavigate,
- routeKey: string,
- ) => {
- const canEditThreadAvatar = threadHasPermission(
- threadInfo,
- threadPermissions.EDIT_THREAD_AVATAR,
- );
- const canEditThreadName = threadHasPermission(
- threadInfo,
- threadPermissions.EDIT_THREAD_NAME,
- );
- const canEditThreadDescription = threadHasPermission(
- threadInfo,
- threadPermissions.EDIT_THREAD_DESCRIPTION,
- );
- const canEditThreadColor = threadHasPermission(
- threadInfo,
- threadPermissions.EDIT_THREAD_COLOR,
- );
+ threadBasicsListDataSelector: PropsAndState => $ReadOnlyArray<ChatSettingsItem> =
+ createSelector(
+ (propsAndState: PropsAndState) => propsAndState.threadInfo,
+ (propsAndState: PropsAndState) => propsAndState.parentThreadInfo,
+ (propsAndState: PropsAndState) => propsAndState.nameEditValue,
+ (propsAndState: PropsAndState) => propsAndState.colorEditValue,
+ (propsAndState: PropsAndState) => propsAndState.descriptionEditValue,
+ (propsAndState: PropsAndState) => propsAndState.descriptionTextHeight,
+ (propsAndState: PropsAndState) => !propsAndState.somethingIsSaving,
+ (propsAndState: PropsAndState) => propsAndState.navigation.navigate,
+ (propsAndState: PropsAndState) => propsAndState.route.key,
+ (
+ threadInfo: ResolvedThreadInfo | MinimallyEncodedResolvedThreadInfo,
+ parentThreadInfo:
+ | ?ResolvedThreadInfo
+ | ?MinimallyEncodedResolvedThreadInfo,
+ nameEditValue: ?string,
+ colorEditValue: string,
+ descriptionEditValue: ?string,
+ descriptionTextHeight: ?number,
+ canStartEditing: boolean,
+ navigate: ThreadSettingsNavigate,
+ routeKey: string,
+ ) => {
+ const canEditThreadAvatar = threadHasPermission(
+ threadInfo,
+ threadPermissions.EDIT_THREAD_AVATAR,
+ );
+ const canEditThreadName = threadHasPermission(
+ threadInfo,
+ threadPermissions.EDIT_THREAD_NAME,
+ );
+ const canEditThreadDescription = threadHasPermission(
+ threadInfo,
+ threadPermissions.EDIT_THREAD_DESCRIPTION,
+ );
+ const canEditThreadColor = threadHasPermission(
+ threadInfo,
+ threadPermissions.EDIT_THREAD_COLOR,
+ );
- const canChangeAvatar = canEditThreadAvatar && canStartEditing;
- const canChangeName = canEditThreadName && canStartEditing;
- const canChangeDescription = canEditThreadDescription && canStartEditing;
- const canChangeColor = canEditThreadColor && canStartEditing;
-
- const listData: ChatSettingsItem[] = [];
- listData.push({
- itemType: 'header',
- key: 'avatarHeader',
- title: 'Channel Avatar',
- categoryType: 'unpadded',
- });
- listData.push({
- itemType: 'avatar',
- key: 'avatar',
- threadInfo,
- canChangeSettings: canChangeAvatar,
- });
- listData.push({
- itemType: 'footer',
- key: 'avatarFooter',
- categoryType: 'outline',
- });
-
- listData.push({
- itemType: 'header',
- key: 'basicsHeader',
- title: 'Basics',
- categoryType: 'full',
- });
- listData.push({
- itemType: 'name',
- key: 'name',
- threadInfo,
- nameEditValue,
- canChangeSettings: canChangeName,
- });
- listData.push({
- itemType: 'color',
- key: 'color',
- threadInfo,
- colorEditValue,
- canChangeSettings: canChangeColor,
- navigate,
- threadSettingsRouteKey: routeKey,
- });
- listData.push({
- itemType: 'footer',
- key: 'basicsFooter',
- categoryType: 'full',
- });
+ const canChangeAvatar = canEditThreadAvatar && canStartEditing;
+ const canChangeName = canEditThreadName && canStartEditing;
+ const canChangeDescription =
+ canEditThreadDescription && canStartEditing;
+ const canChangeColor = canEditThreadColor && canStartEditing;
- if (
- (descriptionEditValue !== null && descriptionEditValue !== undefined) ||
- threadInfo.description ||
- canEditThreadDescription
- ) {
+ const listData: ChatSettingsItem[] = [];
+ listData.push({
+ itemType: 'header',
+ key: 'avatarHeader',
+ title: 'Channel Avatar',
+ categoryType: 'unpadded',
+ });
listData.push({
- itemType: 'description',
- key: 'description',
+ itemType: 'avatar',
+ key: 'avatar',
threadInfo,
- descriptionEditValue,
- descriptionTextHeight,
- canChangeSettings: canChangeDescription,
+ canChangeSettings: canChangeAvatar,
+ });
+ listData.push({
+ itemType: 'footer',
+ key: 'avatarFooter',
+ categoryType: 'outline',
});
- }
- const isMember = viewerIsMember(threadInfo);
- if (isMember) {
listData.push({
itemType: 'header',
- key: 'subscriptionHeader',
- title: 'Subscription',
+ key: 'basicsHeader',
+ title: 'Basics',
categoryType: 'full',
});
listData.push({
- itemType: 'pushNotifs',
- key: 'pushNotifs',
+ itemType: 'name',
+ key: 'name',
+ threadInfo,
+ nameEditValue,
+ canChangeSettings: canChangeName,
+ });
+ listData.push({
+ itemType: 'color',
+ key: 'color',
threadInfo,
+ colorEditValue,
+ canChangeSettings: canChangeColor,
+ navigate,
+ threadSettingsRouteKey: routeKey,
+ });
+ listData.push({
+ itemType: 'footer',
+ key: 'basicsFooter',
+ categoryType: 'full',
});
- if (threadInfo.type !== threadTypes.SIDEBAR) {
+
+ if (
+ (descriptionEditValue !== null &&
+ descriptionEditValue !== undefined) ||
+ threadInfo.description ||
+ canEditThreadDescription
+ ) {
+ listData.push({
+ itemType: 'description',
+ key: 'description',
+ threadInfo,
+ descriptionEditValue,
+ descriptionTextHeight,
+ canChangeSettings: canChangeDescription,
+ });
+ }
+
+ const isMember = viewerIsMember(threadInfo);
+ if (isMember) {
+ listData.push({
+ itemType: 'header',
+ key: 'subscriptionHeader',
+ title: 'Subscription',
+ categoryType: 'full',
+ });
listData.push({
- itemType: 'homeNotifs',
- key: 'homeNotifs',
+ itemType: 'pushNotifs',
+ key: 'pushNotifs',
threadInfo,
});
+ if (threadInfo.type !== threadTypes.SIDEBAR) {
+ listData.push({
+ itemType: 'homeNotifs',
+ key: 'homeNotifs',
+ threadInfo,
+ });
+ }
+ listData.push({
+ itemType: 'footer',
+ key: 'subscriptionFooter',
+ categoryType: 'full',
+ });
}
+
+ listData.push({
+ itemType: 'header',
+ key: 'privacyHeader',
+ title: 'Privacy',
+ categoryType: 'full',
+ });
+ listData.push({
+ itemType: 'visibility',
+ key: 'visibility',
+ threadInfo,
+ });
+ listData.push({
+ itemType: 'parent',
+ key: 'parent',
+ threadInfo,
+ parentThreadInfo,
+ });
listData.push({
itemType: 'footer',
- key: 'subscriptionFooter',
+ key: 'privacyFooter',
categoryType: 'full',
});
- }
-
- listData.push({
- itemType: 'header',
- key: 'privacyHeader',
- title: 'Privacy',
- categoryType: 'full',
- });
- listData.push({
- itemType: 'visibility',
- key: 'visibility',
- threadInfo,
- });
- listData.push({
- itemType: 'parent',
- key: 'parent',
- threadInfo,
- parentThreadInfo,
- });
- listData.push({
- itemType: 'footer',
- key: 'privacyFooter',
- categoryType: 'full',
- });
- return listData;
- },
- );
-
- subchannelsListDataSelector = createSelector(
- (propsAndState: PropsAndState) => propsAndState.threadInfo,
- (propsAndState: PropsAndState) => propsAndState.navigation.navigate,
- (propsAndState: PropsAndState) => propsAndState.childThreadInfos,
- (propsAndState: PropsAndState) => propsAndState.numSubchannelsShowing,
- (
- threadInfo: ResolvedThreadInfo | MinimallyEncodedResolvedThreadInfo,
- navigate: ThreadSettingsNavigate,
- childThreads: ?$ReadOnlyArray<
- ResolvedThreadInfo | MinimallyEncodedResolvedThreadInfo,
- >,
- numSubchannelsShowing: number,
- ) => {
- const listData: ChatSettingsItem[] = [];
-
- const subchannels = childThreads?.filter(threadIsChannel) ?? [];
- const canCreateSubchannels = threadHasPermission(
- threadInfo,
- threadPermissions.CREATE_SUBCHANNELS,
- );
- if (subchannels.length === 0 && !canCreateSubchannels) {
return listData;
- }
+ },
+ );
- listData.push({
- itemType: 'header',
- key: 'subchannelHeader',
- title: 'Subchannels',
- categoryType: 'unpadded',
- });
+ subchannelsListDataSelector: PropsAndState => $ReadOnlyArray<ChatSettingsItem> =
+ createSelector(
+ (propsAndState: PropsAndState) => propsAndState.threadInfo,
+ (propsAndState: PropsAndState) => propsAndState.navigation.navigate,
+ (propsAndState: PropsAndState) => propsAndState.childThreadInfos,
+ (propsAndState: PropsAndState) => propsAndState.numSubchannelsShowing,
+ (
+ threadInfo: ResolvedThreadInfo | MinimallyEncodedResolvedThreadInfo,
+ navigate: ThreadSettingsNavigate,
+ childThreads: ?$ReadOnlyArray<
+ ResolvedThreadInfo | MinimallyEncodedResolvedThreadInfo,
+ >,
+ numSubchannelsShowing: number,
+ ) => {
+ const listData: ChatSettingsItem[] = [];
+
+ const subchannels = childThreads?.filter(threadIsChannel) ?? [];
+ const canCreateSubchannels = threadHasPermission(
+ threadInfo,
+ threadPermissions.CREATE_SUBCHANNELS,
+ );
+ if (subchannels.length === 0 && !canCreateSubchannels) {
+ return listData;
+ }
- if (canCreateSubchannels) {
listData.push({
- itemType: 'addSubchannel',
- key: 'addSubchannel',
+ itemType: 'header',
+ key: 'subchannelHeader',
+ title: 'Subchannels',
+ categoryType: 'unpadded',
});
- }
- const numItems = Math.min(numSubchannelsShowing, subchannels.length);
- for (let i = 0; i < numItems; i++) {
- const subchannelInfo = subchannels[i];
+ if (canCreateSubchannels) {
+ listData.push({
+ itemType: 'addSubchannel',
+ key: 'addSubchannel',
+ });
+ }
+
+ const numItems = Math.min(numSubchannelsShowing, subchannels.length);
+ for (let i = 0; i < numItems; i++) {
+ const subchannelInfo = subchannels[i];
+ listData.push({
+ itemType: 'childThread',
+ key: `childThread${subchannelInfo.id}`,
+ threadInfo: subchannelInfo,
+ firstListItem: i === 0 && !canCreateSubchannels,
+ lastListItem: i === numItems - 1 && numItems === subchannels.length,
+ });
+ }
+
+ if (numItems < subchannels.length) {
+ listData.push({
+ itemType: 'seeMore',
+ key: 'seeMoreSubchannels',
+ onPress: this.onPressSeeMoreSubchannels,
+ });
+ }
+
listData.push({
- itemType: 'childThread',
- key: `childThread${subchannelInfo.id}`,
- threadInfo: subchannelInfo,
- firstListItem: i === 0 && !canCreateSubchannels,
- lastListItem: i === numItems - 1 && numItems === subchannels.length,
+ itemType: 'footer',
+ key: 'subchannelFooter',
+ categoryType: 'unpadded',
});
- }
- if (numItems < subchannels.length) {
+ return listData;
+ },
+ );
+
+ sidebarsListDataSelector: PropsAndState => $ReadOnlyArray<ChatSettingsItem> =
+ createSelector(
+ (propsAndState: PropsAndState) => propsAndState.navigation.navigate,
+ (propsAndState: PropsAndState) => propsAndState.childThreadInfos,
+ (propsAndState: PropsAndState) => propsAndState.numSidebarsShowing,
+ (
+ navigate: ThreadSettingsNavigate,
+ childThreads: ?$ReadOnlyArray<
+ ResolvedThreadInfo | MinimallyEncodedResolvedThreadInfo,
+ >,
+ numSidebarsShowing: number,
+ ) => {
+ const listData: ChatSettingsItem[] = [];
+
+ const sidebars =
+ childThreads?.filter(
+ childThreadInfo => childThreadInfo.type === threadTypes.SIDEBAR,
+ ) ?? [];
+ if (sidebars.length === 0) {
+ return listData;
+ }
+
listData.push({
- itemType: 'seeMore',
- key: 'seeMoreSubchannels',
- onPress: this.onPressSeeMoreSubchannels,
+ itemType: 'header',
+ key: 'sidebarHeader',
+ title: 'Threads',
+ categoryType: 'unpadded',
+ });
+
+ const numItems = Math.min(numSidebarsShowing, sidebars.length);
+ for (let i = 0; i < numItems; i++) {
+ const sidebarInfo = sidebars[i];
+ listData.push({
+ itemType: 'childThread',
+ key: `childThread${sidebarInfo.id}`,
+ threadInfo: sidebarInfo,
+ firstListItem: i === 0,
+ lastListItem: i === numItems - 1 && numItems === sidebars.length,
+ });
+ }
+
+ if (numItems < sidebars.length) {
+ listData.push({
+ itemType: 'seeMore',
+ key: 'seeMoreSidebars',
+ onPress: this.onPressSeeMoreSidebars,
+ });
+ }
+
+ listData.push({
+ itemType: 'footer',
+ key: 'sidebarFooter',
+ categoryType: 'unpadded',
});
- }
- listData.push({
- itemType: 'footer',
- key: 'subchannelFooter',
- categoryType: 'unpadded',
- });
-
- return listData;
- },
- );
-
- sidebarsListDataSelector = createSelector(
- (propsAndState: PropsAndState) => propsAndState.navigation.navigate,
- (propsAndState: PropsAndState) => propsAndState.childThreadInfos,
- (propsAndState: PropsAndState) => propsAndState.numSidebarsShowing,
- (
- navigate: ThreadSettingsNavigate,
- childThreads: ?$ReadOnlyArray<
- ResolvedThreadInfo | MinimallyEncodedResolvedThreadInfo,
- >,
- numSidebarsShowing: number,
- ) => {
- const listData: ChatSettingsItem[] = [];
-
- const sidebars =
- childThreads?.filter(
- childThreadInfo => childThreadInfo.type === threadTypes.SIDEBAR,
- ) ?? [];
- if (sidebars.length === 0) {
return listData;
- }
+ },
+ );
- listData.push({
- itemType: 'header',
- key: 'sidebarHeader',
- title: 'Threads',
- categoryType: 'unpadded',
- });
+ threadMembersListDataSelector: PropsAndState => $ReadOnlyArray<ChatSettingsItem> =
+ createSelector(
+ (propsAndState: PropsAndState) => propsAndState.threadInfo,
+ (propsAndState: PropsAndState) => !propsAndState.somethingIsSaving,
+ (propsAndState: PropsAndState) => propsAndState.navigation.navigate,
+ (propsAndState: PropsAndState) => propsAndState.route.key,
+ (propsAndState: PropsAndState) => propsAndState.numMembersShowing,
+ (propsAndState: PropsAndState) => propsAndState.verticalBounds,
+ (
+ threadInfo: ResolvedThreadInfo | MinimallyEncodedResolvedThreadInfo,
+ canStartEditing: boolean,
+ navigate: ThreadSettingsNavigate,
+ routeKey: string,
+ numMembersShowing: number,
+ verticalBounds: ?VerticalBounds,
+ ) => {
+ const listData: ChatSettingsItem[] = [];
+
+ const canAddMembers = threadHasPermission(
+ threadInfo,
+ threadPermissions.ADD_MEMBERS,
+ );
+ if (threadInfo.members.length === 0 && !canAddMembers) {
+ return listData;
+ }
- const numItems = Math.min(numSidebarsShowing, sidebars.length);
- for (let i = 0; i < numItems; i++) {
- const sidebarInfo = sidebars[i];
listData.push({
- itemType: 'childThread',
- key: `childThread${sidebarInfo.id}`,
- threadInfo: sidebarInfo,
- firstListItem: i === 0,
- lastListItem: i === numItems - 1 && numItems === sidebars.length,
+ itemType: 'header',
+ key: 'memberHeader',
+ title: 'Members',
+ categoryType: 'unpadded',
});
- }
- if (numItems < sidebars.length) {
+ if (canAddMembers) {
+ listData.push({
+ itemType: 'addMember',
+ key: 'addMember',
+ });
+ }
+
+ const numItems = Math.min(numMembersShowing, threadInfo.members.length);
+ for (let i = 0; i < numItems; i++) {
+ const memberInfo = threadInfo.members[i];
+ listData.push({
+ itemType: 'member',
+ key: `member${memberInfo.id}`,
+ memberInfo,
+ threadInfo,
+ canEdit: canStartEditing,
+ navigate,
+ firstListItem: i === 0 && !canAddMembers,
+ lastListItem:
+ i === numItems - 1 && numItems === threadInfo.members.length,
+ verticalBounds,
+ threadSettingsRouteKey: routeKey,
+ });
+ }
+
+ if (numItems < threadInfo.members.length) {
+ listData.push({
+ itemType: 'seeMore',
+ key: 'seeMoreMembers',
+ onPress: this.onPressSeeMoreMembers,
+ });
+ }
+
listData.push({
- itemType: 'seeMore',
- key: 'seeMoreSidebars',
- onPress: this.onPressSeeMoreSidebars,
+ itemType: 'footer',
+ key: 'memberFooter',
+ categoryType: 'unpadded',
});
- }
- listData.push({
- itemType: 'footer',
- key: 'sidebarFooter',
- categoryType: 'unpadded',
- });
-
- return listData;
- },
- );
-
- threadMembersListDataSelector = createSelector(
- (propsAndState: PropsAndState) => propsAndState.threadInfo,
- (propsAndState: PropsAndState) => !propsAndState.somethingIsSaving,
- (propsAndState: PropsAndState) => propsAndState.navigation.navigate,
- (propsAndState: PropsAndState) => propsAndState.route.key,
- (propsAndState: PropsAndState) => propsAndState.numMembersShowing,
- (propsAndState: PropsAndState) => propsAndState.verticalBounds,
- (
- threadInfo: ResolvedThreadInfo | MinimallyEncodedResolvedThreadInfo,
- canStartEditing: boolean,
- navigate: ThreadSettingsNavigate,
- routeKey: string,
- numMembersShowing: number,
- verticalBounds: ?VerticalBounds,
- ) => {
- const listData: ChatSettingsItem[] = [];
-
- const canAddMembers = threadHasPermission(
- threadInfo,
- threadPermissions.ADD_MEMBERS,
- );
- if (threadInfo.members.length === 0 && !canAddMembers) {
return listData;
- }
+ },
+ );
- listData.push({
- itemType: 'header',
- key: 'memberHeader',
- title: 'Members',
- categoryType: 'unpadded',
- });
+ mediaGalleryListDataSelector: PropsAndState => $ReadOnlyArray<ChatSettingsItem> =
+ createSelector(
+ (propsAndState: PropsAndState) => propsAndState.threadInfo,
+ (propsAndState: PropsAndState) => propsAndState.verticalBounds,
+ (
+ threadInfo: ThreadInfo | MinimallyEncodedThreadInfo,
+ verticalBounds: ?VerticalBounds,
+ ) => {
+ const listData: ChatSettingsItem[] = [];
+ const limit = 6;
- if (canAddMembers) {
listData.push({
- itemType: 'addMember',
- key: 'addMember',
+ itemType: 'actionHeader',
+ key: 'mediaGalleryHeader',
+ title: 'Media Gallery',
+ actionText: 'See more',
+ onPress: this.onPressSeeMoreMediaGallery,
});
- }
- const numItems = Math.min(numMembersShowing, threadInfo.members.length);
- for (let i = 0; i < numItems; i++) {
- const memberInfo = threadInfo.members[i];
listData.push({
- itemType: 'member',
- key: `member${memberInfo.id}`,
- memberInfo,
+ itemType: 'mediaGallery',
+ key: 'mediaGallery',
threadInfo,
- canEdit: canStartEditing,
- navigate,
- firstListItem: i === 0 && !canAddMembers,
- lastListItem:
- i === numItems - 1 && numItems === threadInfo.members.length,
+ limit,
verticalBounds,
- threadSettingsRouteKey: routeKey,
});
- }
- if (numItems < threadInfo.members.length) {
listData.push({
- itemType: 'seeMore',
- key: 'seeMoreMembers',
- onPress: this.onPressSeeMoreMembers,
+ itemType: 'footer',
+ key: 'mediaGalleryFooter',
+ categoryType: 'outline',
});
- }
- listData.push({
- itemType: 'footer',
- key: 'memberFooter',
- categoryType: 'unpadded',
- });
-
- return listData;
- },
- );
-
- mediaGalleryListDataSelector = createSelector(
- (propsAndState: PropsAndState) => propsAndState.threadInfo,
- (propsAndState: PropsAndState) => propsAndState.verticalBounds,
- (
- threadInfo: ThreadInfo | MinimallyEncodedThreadInfo,
- verticalBounds: ?VerticalBounds,
- ) => {
- const listData: ChatSettingsItem[] = [];
- const limit = 6;
-
- listData.push({
- itemType: 'actionHeader',
- key: 'mediaGalleryHeader',
- title: 'Media Gallery',
- actionText: 'See more',
- onPress: this.onPressSeeMoreMediaGallery,
- });
-
- listData.push({
- itemType: 'mediaGallery',
- key: 'mediaGallery',
- threadInfo,
- limit,
- verticalBounds,
- });
-
- listData.push({
- itemType: 'footer',
- key: 'mediaGalleryFooter',
- categoryType: 'outline',
- });
-
- return listData;
- },
- );
-
- actionsListDataSelector = createSelector(
- (propsAndState: PropsAndState) => propsAndState.threadInfo,
- (propsAndState: PropsAndState) => propsAndState.parentThreadInfo,
- (propsAndState: PropsAndState) => propsAndState.navigation.navigate,
- (propsAndState: PropsAndState) => propsAndState.styles,
- (propsAndState: PropsAndState) => propsAndState.userInfos,
- (propsAndState: PropsAndState) => propsAndState.viewerID,
- (
- threadInfo: ResolvedThreadInfo | MinimallyEncodedResolvedThreadInfo,
- parentThreadInfo:
- | ?ResolvedThreadInfo
- | ?MinimallyEncodedResolvedThreadInfo,
- navigate: ThreadSettingsNavigate,
- styles: typeof unboundStyles,
- userInfos: UserInfos,
- viewerID: ?string,
- ) => {
- const buttons = [];
-
- if (this.props.canPromoteSidebar) {
- buttons.push({
- itemType: 'promoteSidebar',
- key: 'promoteSidebar',
- threadInfo,
- navigate,
- });
- }
+ return listData;
+ },
+ );
- const canLeaveThread = threadHasPermission(
- threadInfo,
- threadPermissions.LEAVE_THREAD,
- );
+ actionsListDataSelector: PropsAndState => $ReadOnlyArray<ChatSettingsItem> =
+ createSelector(
+ (propsAndState: PropsAndState) => propsAndState.threadInfo,
+ (propsAndState: PropsAndState) => propsAndState.parentThreadInfo,
+ (propsAndState: PropsAndState) => propsAndState.navigation.navigate,
+ (propsAndState: PropsAndState) => propsAndState.styles,
+ (propsAndState: PropsAndState) => propsAndState.userInfos,
+ (propsAndState: PropsAndState) => propsAndState.viewerID,
+ (
+ threadInfo: ResolvedThreadInfo | MinimallyEncodedResolvedThreadInfo,
+ parentThreadInfo:
+ | ?ResolvedThreadInfo
+ | ?MinimallyEncodedResolvedThreadInfo,
+ navigate: ThreadSettingsNavigate,
+ styles: typeof unboundStyles,
+ userInfos: UserInfos,
+ viewerID: ?string,
+ ) => {
+ const buttons = [];
+
+ if (this.props.canPromoteSidebar) {
+ buttons.push({
+ itemType: 'promoteSidebar',
+ key: 'promoteSidebar',
+ threadInfo,
+ navigate,
+ });
+ }
- if (viewerIsMember(threadInfo) && canLeaveThread) {
- buttons.push({
- itemType: 'leaveThread',
- key: 'leaveThread',
+ const canLeaveThread = threadHasPermission(
threadInfo,
- navigate,
- });
- }
+ threadPermissions.LEAVE_THREAD,
+ );
- const canDeleteThread = threadHasPermission(
- threadInfo,
- threadPermissions.DELETE_THREAD,
- );
- if (canDeleteThread) {
- buttons.push({
- itemType: 'deleteThread',
- key: 'deleteThread',
+ if (viewerIsMember(threadInfo) && canLeaveThread) {
+ buttons.push({
+ itemType: 'leaveThread',
+ key: 'leaveThread',
+ threadInfo,
+ navigate,
+ });
+ }
+
+ const canDeleteThread = threadHasPermission(
threadInfo,
- navigate,
- });
- }
+ threadPermissions.DELETE_THREAD,
+ );
+ if (canDeleteThread) {
+ buttons.push({
+ itemType: 'deleteThread',
+ key: 'deleteThread',
+ threadInfo,
+ navigate,
+ });
+ }
- const threadIsPersonal = threadInfo.type === threadTypes.PERSONAL;
- if (threadIsPersonal && viewerID) {
- const otherMemberID = getSingleOtherUser(threadInfo, viewerID);
- if (otherMemberID) {
- const otherUserInfo = userInfos[otherMemberID];
- const availableRelationshipActions =
- getAvailableRelationshipButtons(otherUserInfo);
-
- for (const action of availableRelationshipActions) {
- buttons.push({
- itemType: 'editRelationship',
- key: action,
- threadInfo,
- navigate,
- relationshipButton: action,
+ const threadIsPersonal = threadInfo.type === threadTypes.PERSONAL;
+ if (threadIsPersonal && viewerID) {
+ const otherMemberID = getSingleOtherUser(threadInfo, viewerID);
+ if (otherMemberID) {
+ const otherUserInfo = userInfos[otherMemberID];
+ const availableRelationshipActions =
+ getAvailableRelationshipButtons(otherUserInfo);
+
+ for (const action of availableRelationshipActions) {
+ buttons.push({
+ itemType: 'editRelationship',
+ key: action,
+ threadInfo,
+ navigate,
+ relationshipButton: action,
+ });
+ }
+ }
+ }
+
+ const listData: ChatSettingsItem[] = [];
+ if (buttons.length === 0) {
+ return listData;
+ }
+
+ listData.push({
+ itemType: 'header',
+ key: 'actionsHeader',
+ title: 'Actions',
+ categoryType: 'unpadded',
+ });
+ for (let i = 0; i < buttons.length; i++) {
+ // Necessary for Flow...
+ if (buttons[i].itemType === 'editRelationship') {
+ listData.push({
+ ...buttons[i],
+ buttonStyle: [
+ i === 0 ? null : styles.nonTopButton,
+ i === buttons.length - 1 ? styles.lastButton : null,
+ ],
+ });
+ } else {
+ listData.push({
+ ...buttons[i],
+ buttonStyle: [
+ i === 0 ? null : styles.nonTopButton,
+ i === buttons.length - 1 ? styles.lastButton : null,
+ ],
});
}
}
- }
+ listData.push({
+ itemType: 'footer',
+ key: 'actionsFooter',
+ categoryType: 'unpadded',
+ });
- const listData: ChatSettingsItem[] = [];
- if (buttons.length === 0) {
return listData;
- }
+ },
+ );
- listData.push({
- itemType: 'header',
- key: 'actionsHeader',
- title: 'Actions',
- categoryType: 'unpadded',
- });
- for (let i = 0; i < buttons.length; i++) {
- // Necessary for Flow...
- if (buttons[i].itemType === 'editRelationship') {
- listData.push({
- ...buttons[i],
- buttonStyle: [
- i === 0 ? null : styles.nonTopButton,
- i === buttons.length - 1 ? styles.lastButton : null,
- ],
- });
- } else {
- listData.push({
- ...buttons[i],
- buttonStyle: [
- i === 0 ? null : styles.nonTopButton,
- i === buttons.length - 1 ? styles.lastButton : null,
- ],
- });
- }
- }
- listData.push({
- itemType: 'footer',
- key: 'actionsFooter',
- categoryType: 'unpadded',
- });
-
- return listData;
- },
- );
-
- listDataSelector = createSelector(
- this.threadBasicsListDataSelector,
- this.subchannelsListDataSelector,
- this.sidebarsListDataSelector,
- this.threadMembersListDataSelector,
- this.mediaGalleryListDataSelector,
- this.actionsListDataSelector,
- (
- threadBasicsListData: ChatSettingsItem[],
- subchannelsListData: ChatSettingsItem[],
- sidebarsListData: ChatSettingsItem[],
- threadMembersListData: ChatSettingsItem[],
- mediaGalleryListData: ChatSettingsItem[],
- actionsListData: ChatSettingsItem[],
- ) => [
- ...threadBasicsListData,
- ...subchannelsListData,
- ...sidebarsListData,
- ...threadMembersListData,
- ...mediaGalleryListData,
- ...actionsListData,
- ],
- );
-
- get listData() {
+ listDataSelector: PropsAndState => $ReadOnlyArray<ChatSettingsItem> =
+ createSelector(
+ this.threadBasicsListDataSelector,
+ this.subchannelsListDataSelector,
+ this.sidebarsListDataSelector,
+ this.threadMembersListDataSelector,
+ this.mediaGalleryListDataSelector,
+ this.actionsListDataSelector,
+ (
+ threadBasicsListData: $ReadOnlyArray<ChatSettingsItem>,
+ subchannelsListData: $ReadOnlyArray<ChatSettingsItem>,
+ sidebarsListData: $ReadOnlyArray<ChatSettingsItem>,
+ threadMembersListData: $ReadOnlyArray<ChatSettingsItem>,
+ mediaGalleryListData: $ReadOnlyArray<ChatSettingsItem>,
+ actionsListData: $ReadOnlyArray<ChatSettingsItem>,
+ ) => [
+ ...threadBasicsListData,
+ ...subchannelsListData,
+ ...sidebarsListData,
+ ...threadMembersListData,
+ ...mediaGalleryListData,
+ ...actionsListData,
+ ],
+ );
+
+ get listData(): $ReadOnlyArray<ChatSettingsItem> {
return this.listDataSelector({ ...this.props, ...this.state });
}
- render() {
+ render(): React.Node {
return (
<View
style={this.props.styles.container}
@@ -933,7 +942,7 @@
// ESLint doesn't recognize that invariant always throws
// eslint-disable-next-line consistent-return
- renderItem = (row: { item: ChatSettingsItem, ... }) => {
+ renderItem = (row: { +item: ChatSettingsItem, ... }): React.Node => {
const item = row.item;
if (item.itemType === 'header') {
return (
diff --git a/native/chat/text-message-tooltip-button.react.js b/native/chat/text-message-tooltip-button.react.js
--- a/native/chat/text-message-tooltip-button.react.js
+++ b/native/chat/text-message-tooltip-button.react.js
@@ -20,6 +20,7 @@
import SidebarInputBarHeightMeasurer from './sidebar-input-bar-height-measurer.react.js';
import { useAnimatedMessageTooltipButton } from './utils.js';
import EmojiKeyboard from '../components/emoji-keyboard.react.js';
+import type { EmojiSelection } from '../components/emoji-keyboard.react.js';
import type { AppNavigationProp } from '../navigation/app-navigator.react.js';
import { useSelector } from '../redux/redux-utils.js';
import { useTooltipActions } from '../tooltip/tooltip-hooks.js';
@@ -144,7 +145,7 @@
const { dismissTooltip } = useTooltipActions(navigation, tooltipRouteKey);
const onEmojiSelected = React.useCallback(
- emoji => {
+ (emoji: EmojiSelection) => {
sendReaction(emoji.emoji);
dismissTooltip();
},
diff --git a/native/chat/text-message-tooltip-modal.react.js b/native/chat/text-message-tooltip-modal.react.js
--- a/native/chat/text-message-tooltip-modal.react.js
+++ b/native/chat/text-message-tooltip-modal.react.js
@@ -23,6 +23,7 @@
type TooltipMenuProps,
} from '../tooltip/tooltip.react.js';
import type { ChatTextMessageInfoItemWithHeight } from '../types/chat-types.js';
+import type { TextStyle } from '../types/styles.js';
import { exitEditAlert } from '../utils/edit-messages-utils.js';
import { useNavigateToPinModal } from '../utils/toggle-pin-utils.js';
@@ -55,13 +56,13 @@
});
}, [inputState, navigateToThread, threadInfo, text]);
const renderReplyIcon = React.useCallback(
- style => <CommIcon name="reply" style={style} size={12} />,
+ (style: TextStyle) => <CommIcon name="reply" style={style} size={12} />,
[],
);
const onPressSidebar = useAnimatedNavigateToSidebar(route.params.item);
const renderSidebarIcon = React.useCallback(
- style => (
+ (style: TextStyle) => (
<SWMansionIcon name="message-circle-lines" style={style} size={16} />
),
[],
@@ -96,18 +97,24 @@
}
}, [inputState, messageEditingContext, messageInfo, text]);
const renderEditIcon = React.useCallback(
- style => <SWMansionIcon name="edit-1" style={style} size={16} />,
+ (style: TextStyle) => (
+ <SWMansionIcon name="edit-1" style={style} size={16} />
+ ),
[],
);
const onPressTogglePin = useNavigateToPinModal(overlayContext, route);
const renderPinIcon = React.useCallback(
- style => <CommIcon name="pin-outline" style={style} size={16} />,
+ (style: TextStyle) => (
+ <CommIcon name="pin-outline" style={style} size={16} />
+ ),
[],
);
const renderUnpinIcon = React.useCallback(
- style => <CommIcon name="unpin-outline" style={style} size={16} />,
+ (style: TextStyle) => (
+ <CommIcon name="unpin-outline" style={style} size={16} />
+ ),
[],
);
@@ -116,13 +123,15 @@
setTimeout(confirmCopy);
}, [text]);
const renderCopyIcon = React.useCallback(
- style => <SWMansionIcon name="copy" style={style} size={16} />,
+ (style: TextStyle) => <SWMansionIcon name="copy" style={style} size={16} />,
[],
);
const onPressReport = useOnPressReport(route);
const renderReportIcon = React.useCallback(
- style => <SWMansionIcon name="warning-circle" style={style} size={16} />,
+ (style: TextStyle) => (
+ <SWMansionIcon name="warning-circle" style={style} size={16} />
+ ),
[],
);
diff --git a/native/chat/text-message.react.js b/native/chat/text-message.react.js
--- a/native/chat/text-message.react.js
+++ b/native/chat/text-message.react.js
@@ -78,7 +78,7 @@
};
}
- render() {
+ render(): React.Node {
const {
item,
navigation,
@@ -136,21 +136,21 @@
this.message = message;
};
- canReply() {
+ canReply(): boolean {
return threadHasPermission(
this.props.item.threadInfo,
threadPermissions.VOICED,
);
}
- canNavigateToSidebar() {
+ canNavigateToSidebar(): boolean {
return (
- this.props.item.threadCreatedFromMessage ||
+ !!this.props.item.threadCreatedFromMessage ||
this.props.canCreateSidebarFromMessage
);
}
- visibleEntryIDs() {
+ visibleEntryIDs(): $ReadOnlyArray<string> {
const result = ['copy'];
if (this.canReply()) {
diff --git a/native/chat/thread-settings-button.react.js b/native/chat/thread-settings-button.react.js
--- a/native/chat/thread-settings-button.react.js
+++ b/native/chat/thread-settings-button.react.js
@@ -28,7 +28,7 @@
};
class ThreadSettingsButton extends React.PureComponent<Props> {
- render() {
+ render(): React.Node {
return (
<Button onPress={this.onPress} androidBorderlessRipple={true}>
<SWMansionIcon
diff --git a/native/community-creation/community-configuration.react.js b/native/community-creation/community-configuration.react.js
--- a/native/community-creation/community-configuration.react.js
+++ b/native/community-creation/community-configuration.react.js
@@ -61,7 +61,7 @@
const [announcementSetting, setAnnouncementSetting] = React.useState(false);
const [errorMessage, setErrorMessage] = React.useState<?string>();
- const onChangePendingCommunityName = React.useCallback(newValue => {
+ const onChangePendingCommunityName = React.useCallback((newValue: string) => {
setErrorMessage();
setPendingCommunityName(newValue);
}, []);
diff --git a/native/components/emoji-keyboard.react.js b/native/components/emoji-keyboard.react.js
--- a/native/components/emoji-keyboard.react.js
+++ b/native/components/emoji-keyboard.react.js
@@ -31,7 +31,7 @@
return JSON.parse(recentlyUsedEmojis ?? '[]');
};
-const onStateChangeCallback = nextRecentlyUsedEmojis =>
+const onStateChangeCallback = (nextRecentlyUsedEmojis: $ReadOnlyArray<mixed>) =>
AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(nextRecentlyUsedEmojis));
const useRecentPicksPersistenceArgs = {
diff --git a/native/components/full-screen-view-modal.react.js b/native/components/full-screen-view-modal.react.js
--- a/native/components/full-screen-view-modal.react.js
+++ b/native/components/full-screen-view-modal.react.js
@@ -40,7 +40,7 @@
derivedDimensionsInfoSelector,
} from '../selectors/dimensions-selectors.js';
import type { NativeMethods } from '../types/react-native.js';
-import type { AnimatedStyleObj } from '../types/styles.js';
+import type { AnimatedViewStyle, ViewStyle } from '../types/styles.js';
import type { UserProfileBottomSheetNavigationProp } from '../user-profile/user-profile-bottom-sheet-navigator.react.js';
import {
clamp,
@@ -175,16 +175,16 @@
closeButton: ?React.ElementRef<TouchableOpacityInstance>;
mediaIconsContainer: ?React.ElementRef<typeof View>;
- closeButtonX = new Value(-1);
- closeButtonY = new Value(-1);
- closeButtonWidth = new Value(0);
- closeButtonHeight = new Value(0);
- closeButtonLastState = new Value(1);
- mediaIconsX = new Value(-1);
- mediaIconsY = new Value(-1);
- mediaIconsWidth = new Value(0);
- mediaIconsHeight = new Value(0);
- actionLinksLastState = new Value(1);
+ closeButtonX: Value = new Value(-1);
+ closeButtonY: Value = new Value(-1);
+ closeButtonWidth: Value = new Value(0);
+ closeButtonHeight: Value = new Value(0);
+ closeButtonLastState: Value = new Value(1);
+ mediaIconsX: Value = new Value(-1);
+ mediaIconsY: Value = new Value(-1);
+ mediaIconsWidth: Value = new Value(0);
+ mediaIconsHeight: Value = new Value(0);
+ actionLinksLastState: Value = new Value(1);
centerX: Value;
centerY: Value;
@@ -959,7 +959,7 @@
return { width, height: safeAreaHeight };
}
- get contentViewContainerStyle(): AnimatedStyleObj {
+ get contentViewContainerStyle(): AnimatedViewStyle {
const { height, width } = this.props.contentDimensions;
const { height: frameHeight, width: frameWidth } = this.frame;
const top = (frameHeight - height) / 2 + this.props.dimensions.topInset;
@@ -979,13 +979,13 @@
};
}
- static isActive(props) {
+ static isActive(props: Props): boolean {
const { overlayContext } = props;
invariant(overlayContext, 'FullScreenViewModal should have OverlayContext');
return !overlayContext.isDismissing;
}
- get contentContainerStyle() {
+ get contentContainerStyle(): ViewStyle {
const { verticalBounds } = this.props.route.params;
const fullScreenHeight = this.props.dimensions.height;
const top = verticalBounds.y;
@@ -998,7 +998,7 @@
return [styles.contentContainer, verticalStyle];
}
- render() {
+ render(): React.Node {
const { children, saveContentCallback, copyContentCallback } = this.props;
const statusBar = FullScreenViewModal.isActive(this.props) ? (
diff --git a/native/components/keyboard-avoiding-view.react.js b/native/components/keyboard-avoiding-view.react.js
--- a/native/components/keyboard-avoiding-view.react.js
+++ b/native/components/keyboard-avoiding-view.react.js
@@ -120,7 +120,7 @@
}
};
- get relativeKeyboardHeight() {
+ get relativeKeyboardHeight(): number {
const { viewFrame, keyboardFrame } = this;
if (!viewFrame || !keyboardFrame) {
return 0;
@@ -145,7 +145,7 @@
// ESLint doesn't recognize that invariant always throws
// eslint-disable-next-line consistent-return
- render() {
+ render(): React.Node {
const {
behavior,
children,
diff --git a/native/components/link-button.react.js b/native/components/link-button.react.js
--- a/native/components/link-button.react.js
+++ b/native/components/link-button.react.js
@@ -29,7 +29,7 @@
+styles: typeof unboundStyles,
};
class LinkButton extends React.PureComponent<Props> {
- render() {
+ render(): React.Node {
const disabledStyle = this.props.disabled
? this.props.styles.disabled
: null;
diff --git a/native/components/node-height-measurer.react.js b/native/components/node-height-measurer.react.js
--- a/native/components/node-height-measurer.react.js
+++ b/native/components/node-height-measurer.react.js
@@ -495,7 +495,7 @@
const dummies = currentlyMeasuring.map(({ measureKey, dummy }) => {
const { children } = dummy.props;
const style = [dummy.props.style, styles.dummy];
- const onLayout = event =>
+ const onLayout = (event: LayoutEvent) =>
this.onDummyLayout(measureKey, iteration, event);
const node = React.cloneElement(dummy, {
style,
diff --git a/native/components/selectable-text-input.react.ios.js b/native/components/selectable-text-input.react.ios.js
--- a/native/components/selectable-text-input.react.ios.js
+++ b/native/components/selectable-text-input.react.ios.js
@@ -15,7 +15,7 @@
import type { SelectionChangeEvent } from '../types/react-native.js';
const SelectableTextInput = React.forwardRef(function BaseSelectableTextInput(
- props,
+ props: SelectableTextInputProps,
ref: ReactRefSetter<SelectableTextInputRef>,
): React.Node {
const {
diff --git a/native/components/selectable-text-input.react.js b/native/components/selectable-text-input.react.js
--- a/native/components/selectable-text-input.react.js
+++ b/native/components/selectable-text-input.react.js
@@ -13,7 +13,7 @@
import type { SelectionChangeEvent } from '../types/react-native.js';
const SelectableTextInput = React.forwardRef(function BaseSelectableTextInput(
- props,
+ props: SelectableTextInputProps,
ref: ReactRefSetter<SelectableTextInputRef>,
): React.Node {
const {
diff --git a/native/components/tag-input.react.js b/native/components/tag-input.react.js
--- a/native/components/tag-input.react.js
+++ b/native/components/tag-input.react.js
@@ -377,7 +377,7 @@
}
}
- render() {
+ render(): React.Node {
return (
<TouchableOpacity
onPress={this.onPress}
diff --git a/native/components/thread-list-thread.react.js b/native/components/thread-list-thread.react.js
--- a/native/components/thread-list-thread.react.js
+++ b/native/components/thread-list-thread.react.js
@@ -43,7 +43,7 @@
+styles: typeof unboundStyles,
};
class ThreadListThread extends React.PureComponent<Props> {
- render() {
+ render(): React.Node {
const { modalIosHighlightUnderlay: underlayColor } = this.props.colors;
return (
diff --git a/native/components/thread-list.react.js b/native/components/thread-list.react.js
--- a/native/components/thread-list.react.js
+++ b/native/components/thread-list.react.js
@@ -50,29 +50,30 @@
};
textInput: ?React.ElementRef<typeof TextInput>;
- listDataSelector = createSelector(
- (propsAndState: PropsAndState) => propsAndState.threadInfos,
- (propsAndState: PropsAndState) => propsAndState.searchText,
- (propsAndState: PropsAndState) => propsAndState.searchResults,
- (propsAndState: PropsAndState) => propsAndState.itemStyle,
- (propsAndState: PropsAndState) => propsAndState.itemTextStyle,
- (
- threadInfos: $ReadOnlyArray<ThreadInfo>,
- text: string,
- searchResults: Set<string>,
- ) =>
- text
- ? threadInfos.filter(threadInfo => searchResults.has(threadInfo.id))
- : // We spread to make sure the result of this selector updates when
- // any input param (namely itemStyle or itemTextStyle) changes
- [...threadInfos],
- );
-
- get listData() {
+ listDataSelector: PropsAndState => $ReadOnlyArray<ThreadInfo> =
+ createSelector(
+ (propsAndState: PropsAndState) => propsAndState.threadInfos,
+ (propsAndState: PropsAndState) => propsAndState.searchText,
+ (propsAndState: PropsAndState) => propsAndState.searchResults,
+ (propsAndState: PropsAndState) => propsAndState.itemStyle,
+ (propsAndState: PropsAndState) => propsAndState.itemTextStyle,
+ (
+ threadInfos: $ReadOnlyArray<ThreadInfo>,
+ text: string,
+ searchResults: Set<string>,
+ ): $ReadOnlyArray<ThreadInfo> =>
+ text
+ ? threadInfos.filter(threadInfo => searchResults.has(threadInfo.id))
+ : // We spread to make sure the result of this selector updates when
+ // any input param (namely itemStyle or itemTextStyle) changes
+ [...threadInfos],
+ );
+
+ get listData(): $ReadOnlyArray<ThreadInfo> {
return this.listDataSelector({ ...this.props, ...this.state });
}
- render() {
+ render(): React.Node {
let searchBar = null;
if (this.props.searchIndex) {
searchBar = (
@@ -103,11 +104,11 @@
static keyExtractor = (
threadInfo: ThreadInfo | MinimallyEncodedThreadInfo,
- ) => {
+ ): string => {
return threadInfo.id;
};
- renderItem = (row: { item: ThreadInfo, ... }) => {
+ renderItem = (row: { +item: ThreadInfo, ... }): React.Node => {
return (
<ThreadListThread
threadInfo={row.item}
@@ -121,7 +122,7 @@
static getItemLayout = (
data: ?$ReadOnlyArray<ThreadInfo | MinimallyEncodedThreadInfo>,
index: number,
- ) => {
+ ): { length: number, offset: number, index: number } => {
return { length: 24, offset: 24 * index, index };
};
diff --git a/native/components/user-list-user.react.js b/native/components/user-list-user.react.js
--- a/native/components/user-list-user.react.js
+++ b/native/components/user-list-user.react.js
@@ -49,7 +49,7 @@
+styles: typeof unboundStyles,
};
class UserListUser extends React.PureComponent<Props> {
- render() {
+ render(): React.Node {
const { userInfo } = this.props;
let notice = null;
if (userInfo.notice) {
diff --git a/native/components/user-list.react.js b/native/components/user-list.react.js
--- a/native/components/user-list.react.js
+++ b/native/components/user-list.react.js
@@ -21,7 +21,7 @@
+indicatorStyle: IndicatorStyle,
};
class UserList extends React.PureComponent<Props> {
- render() {
+ render(): React.Node {
return (
<FlatList
data={this.props.userInfos}
@@ -36,11 +36,11 @@
);
}
- static keyExtractor = (userInfo: UserListItem) => {
+ static keyExtractor = (userInfo: UserListItem): string => {
return userInfo.id;
};
- renderItem = (row: { item: UserListItem, ... }) => {
+ renderItem = (row: { +item: UserListItem, ... }): React.Node => {
return (
<UserListUser
userInfo={row.item}
@@ -53,7 +53,7 @@
static getItemLayout = (
data: ?$ReadOnlyArray<UserListItem>,
index: number,
- ) => {
+ ): { length: number, offset: number, index: number } => {
if (!data) {
return { length: 0, offset: 0, index };
}
diff --git a/native/crash.react.js b/native/crash.react.js
--- a/native/crash.react.js
+++ b/native/crash.react.js
@@ -65,9 +65,9 @@
+doneWaiting: boolean,
};
class Crash extends React.PureComponent<Props, State> {
- errorTitle = _shuffle(errorTitles)[0];
+ errorTitle: string = _shuffle(errorTitles)[0];
- constructor(props) {
+ constructor(props: Props) {
super(props);
this.state = {
errorReportID: null,
@@ -89,7 +89,7 @@
this.setState({ doneWaiting: true });
}
- render() {
+ render(): React.Node {
const errorText = [...this.props.errorData]
.reverse()
.map(errorData => errorData.error.message)
diff --git a/native/input/input-state-container.react.js b/native/input/input-state-container.react.js
--- a/native/input/input-state-container.react.js
+++ b/native/input/input-state-container.react.js
@@ -107,6 +107,7 @@
type PendingMultimediaUploads,
type MultimediaProcessingStep,
type MessagePendingUploads,
+ type InputState,
} from './input-state.js';
import { encryptMedia } from '../media/encryption-utils.js';
import { disposeTempFile } from '../media/file-utils.js';
@@ -128,6 +129,7 @@
[localMessageID: string]: ?$ReadOnlySet<string>,
};
type CompletedUploads = $ReadOnly<WritableCompletedUploads>;
+type ActiveURI = { +count: number, +onClear: $ReadOnlyArray<() => mixed> };
type BaseProps = {
+children: React.Node,
@@ -165,16 +167,16 @@
pendingUploads: {},
};
sendCallbacks: Array<() => void> = [];
- activeURIs = new Map();
+ activeURIs: Map<string, ActiveURI> = new Map();
editInputBarCallbacks: Array<
(params: EditInputBarMessageParameters) => void,
> = [];
scrollToMessageCallbacks: Array<(messageID: string) => void> = [];
- pendingThreadCreations = new Map<string, Promise<string>>();
- pendingThreadUpdateHandlers = new Map<
+ pendingThreadCreations: Map<string, Promise<string>> = new Map();
+ pendingThreadUpdateHandlers: Map<
string,
(ThreadInfo | MinimallyEncodedThreadInfo) => mixed,
- >();
+ > = new Map();
// TODO: flip the switch
// Note that this enables Blob service for encrypted media only
useBlobServiceUploads = false;
@@ -183,7 +185,7 @@
// sidebar, the sidebar gets created right away, but the message needs to wait
// for the uploads to complete before sending. We use this Set to track the
// message localIDs that need sidebarCreation: true.
- pendingSidebarCreationMessageLocalIDs = new Set<string>();
+ pendingSidebarCreationMessageLocalIDs: Set<string> = new Set();
static getCompletedUploads(props: Props, state: State): CompletedUploads {
const completedUploads: WritableCompletedUploads = {};
@@ -297,7 +299,9 @@
}
}
- async dispatchMultimediaMessageAction(messageInfo: RawMultimediaMessageInfo) {
+ async dispatchMultimediaMessageAction(
+ messageInfo: RawMultimediaMessageInfo,
+ ): Promise<void> {
if (!threadIsPending(messageInfo.threadID)) {
this.props.dispatchActionPromise(
sendMultimediaMessageActionTypes,
@@ -394,7 +398,7 @@
}
}
- inputStateSelector = createSelector(
+ inputStateSelector: State => InputState = createSelector(
(state: State) => state.pendingUploads,
(pendingUploads: PendingMultimediaUploads) => ({
pendingUploads,
@@ -432,7 +436,7 @@
);
};
- uploadInProgress = () => {
+ uploadInProgress = (): boolean => {
if (this.props.ongoingMessageCreation) {
return true;
}
@@ -1305,7 +1309,7 @@
});
}
- messageHasUploadFailure = (localMessageID: string) => {
+ messageHasUploadFailure = (localMessageID: string): boolean => {
const pendingUploads = this.state.pendingUploads[localMessageID];
if (!pendingUploads) {
return false;
@@ -1352,7 +1356,7 @@
rawMessageInfo: RawMultimediaMessageInfo,
localMessageID: string,
threadInfo: ThreadInfo | MinimallyEncodedThreadInfo,
- ) => {
+ ): Promise<void> => {
const pendingUploads = this.state.pendingUploads[localMessageID] ?? {};
const now = Date.now();
@@ -1615,7 +1619,10 @@
}
};
- waitForCaptureURIUnload(uri: string) {
+ waitForCaptureURIUnload(uri: string): Promise<{
+ +steps: $ReadOnlyArray<MediaMissionStep>,
+ +result: ?string,
+ }> {
const start = Date.now();
const path = pathFromURI(uri);
if (!path) {
@@ -1675,7 +1682,7 @@
}
};
- render() {
+ render(): React.Node {
const inputState = this.inputStateSelector(this.state);
return (
<InputStateContext.Provider value={inputState}>
diff --git a/native/keyboard/keyboard-input-host.react.js b/native/keyboard/keyboard-input-host.react.js
--- a/native/keyboard/keyboard-input-host.react.js
+++ b/native/keyboard/keyboard-input-host.react.js
@@ -46,12 +46,12 @@
}
}
- static mediaGalleryOpen(props: Props) {
+ static mediaGalleryOpen(props: Props): boolean {
const { keyboardState } = props;
return !!(keyboardState && keyboardState.mediaGalleryOpen);
}
- render() {
+ render(): React.Node {
const kbComponent = KeyboardInputHost.mediaGalleryOpen(this.props)
? mediaGalleryKeyboardName
: null;
diff --git a/native/media/camera-modal.react.js b/native/media/camera-modal.react.js
--- a/native/media/camera-modal.react.js
+++ b/native/media/camera-modal.react.js
@@ -19,17 +19,21 @@
PinchGestureHandler,
TapGestureHandler,
State as GestureState,
+ type PinchGestureEvent,
+ type TapGestureEvent,
} from 'react-native-gesture-handler';
import Orientation from 'react-native-orientation-locker';
import type { Orientations } from 'react-native-orientation-locker';
import Reanimated, {
EasingNode as ReanimatedEasing,
+ type EventResult,
} from 'react-native-reanimated';
import { SafeAreaView } from 'react-native-safe-area-context';
import { pathFromURI, filenameFromPathOrURI } from 'lib/media/file-utils.js';
import { useIsAppForegrounded } from 'lib/shared/lifecycle-utils.js';
import type { PhotoCapture } from 'lib/types/media-types.js';
+import type { ReactRef } from 'lib/types/react-types.js';
import type { Dispatch } from 'lib/types/redux-types.js';
import { useDispatch } from 'lib/utils/redux-utils.js';
@@ -219,6 +223,8 @@
]);
}
+type RNCameraStatus = 'READY' | 'PENDING_AUTHORIZATION' | 'NOT_AUTHORIZED';
+
type TouchableOpacityInstance = React.AbstractComponent<
React.ElementConfig<typeof TouchableOpacity>,
NativeMethods,
@@ -260,47 +266,47 @@
class CameraModal extends React.PureComponent<Props, State> {
camera: ?RNCamera;
- pinchEvent;
- pinchHandler = React.createRef();
- tapEvent;
- tapHandler = React.createRef();
+ pinchEvent: EventResult<PinchGestureEvent>;
+ pinchHandler: ReactRef<PinchGestureHandler> = React.createRef();
+ tapEvent: EventResult<TapGestureEvent>;
+ tapHandler: ReactRef<TapGestureHandler> = React.createRef();
animationCode: Node;
closeButton: ?React.ElementRef<TouchableOpacityInstance>;
- closeButtonX = new Value(-1);
- closeButtonY = new Value(-1);
- closeButtonWidth = new Value(0);
- closeButtonHeight = new Value(0);
+ closeButtonX: Value = new Value(-1);
+ closeButtonY: Value = new Value(-1);
+ closeButtonWidth: Value = new Value(0);
+ closeButtonHeight: Value = new Value(0);
photoButton: ?React.ElementRef<TouchableOpacityInstance>;
- photoButtonX = new Value(-1);
- photoButtonY = new Value(-1);
- photoButtonWidth = new Value(0);
- photoButtonHeight = new Value(0);
+ photoButtonX: Value = new Value(-1);
+ photoButtonY: Value = new Value(-1);
+ photoButtonWidth: Value = new Value(0);
+ photoButtonHeight: Value = new Value(0);
switchCameraButton: ?React.ElementRef<TouchableOpacityInstance>;
- switchCameraButtonX = new Value(-1);
- switchCameraButtonY = new Value(-1);
- switchCameraButtonWidth = new Value(0);
- switchCameraButtonHeight = new Value(0);
+ switchCameraButtonX: Value = new Value(-1);
+ switchCameraButtonY: Value = new Value(-1);
+ switchCameraButtonWidth: Value = new Value(0);
+ switchCameraButtonHeight: Value = new Value(0);
flashButton: ?React.ElementRef<TouchableOpacityInstance>;
- flashButtonX = new Value(-1);
- flashButtonY = new Value(-1);
- flashButtonWidth = new Value(0);
- flashButtonHeight = new Value(0);
+ flashButtonX: Value = new Value(-1);
+ flashButtonY: Value = new Value(-1);
+ flashButtonWidth: Value = new Value(0);
+ flashButtonHeight: Value = new Value(0);
- focusIndicatorX = new Value(-1);
- focusIndicatorY = new Value(-1);
- focusIndicatorScale = new Value(0);
- focusIndicatorOpacity = new Value(0);
+ focusIndicatorX: Value = new Value(-1);
+ focusIndicatorY: Value = new Value(-1);
+ focusIndicatorScale: Value = new Value(0);
+ focusIndicatorOpacity: Value = new Value(0);
- cancelIndicatorAnimation = new Value(0);
+ cancelIndicatorAnimation: Value = new Value(0);
cameraIDsFetched = false;
- stagingModeProgress = new Value(0);
- sendButtonProgress = new Animated.Value(0);
+ stagingModeProgress: Value = new Value(0);
+ sendButtonProgress: Animated.Value = new Animated.Value(0);
sendButtonStyle: ViewStyle;
overlayStyle: AnimatedViewStyle;
@@ -502,7 +508,7 @@
);
}
- static isActive(props) {
+ static isActive(props: Props): boolean {
const { overlayContext } = props;
if (!overlayContext) {
return true;
@@ -582,7 +588,7 @@
} catch (e) {}
}
- get containerStyle() {
+ get containerStyle(): AnimatedViewStyle {
const { overlayContext } = this.props;
if (!overlayContext) {
return styles.container;
@@ -593,7 +599,7 @@
};
}
- get focusIndicatorStyle() {
+ get focusIndicatorStyle(): AnimatedViewStyle {
return {
...styles.focusIndicator,
opacity: this.focusIndicatorOpacity,
@@ -605,7 +611,14 @@
};
}
- renderCamera = ({ camera, status }) => {
+ renderCamera = ({
+ camera,
+ status,
+ }: {
+ +camera: RNCamera & { +_cameraHandle?: mixed, ... },
+ status: RNCameraStatus,
+ ...
+ }): React.Node => {
if (camera && camera._cameraHandle) {
this.fetchCameraIDs(camera);
}
@@ -630,7 +643,7 @@
);
};
- renderStagingView() {
+ renderStagingView(): React.Node {
let image = null;
const { pendingPhotoCapture } = this.state;
if (pendingPhotoCapture) {
@@ -663,7 +676,7 @@
);
}
- renderCameraContent(status) {
+ renderCameraContent(status: RNCameraStatus): React.Node {
if (status === 'PENDING_AUTHORIZATION') {
return <ContentLoading fillType="flex" colors={colors.dark} />;
} else if (status === 'NOT_AUTHORIZED') {
@@ -746,7 +759,7 @@
);
}
- render() {
+ render(): React.Node {
const statusBar = CameraModal.isActive(this.props) ? (
<ConnectedStatusBar hidden />
) : null;
diff --git a/native/media/media-gallery-keyboard.react.js b/native/media/media-gallery-keyboard.react.js
--- a/native/media/media-gallery-keyboard.react.js
+++ b/native/media/media-gallery-keyboard.react.js
@@ -128,7 +128,7 @@
fetchingPhotos = false;
flatList: ?FlatList<MediaLibrarySelection>;
viewableIndices: number[] = [];
- queueModeProgress = new Animated.Value(0);
+ queueModeProgress: Animated.Value = new Animated.Value(0);
sendButtonStyle: ViewStyle;
mediaSelected = false;
@@ -153,7 +153,7 @@
};
}
- static getDerivedStateFromProps(props: Props) {
+ static getDerivedStateFromProps(props: Props): Partial<State> {
// We keep this in state since we pass this.state as
// FlatList's extraData prop
return { dimensions: props.dimensions };
@@ -161,7 +161,7 @@
componentDidMount() {
this.mounted = true;
- return this.fetchPhotos();
+ this.fetchPhotos();
}
componentWillUnmount() {
@@ -236,7 +236,7 @@
}
}
- guardedSetState(change) {
+ guardedSetState(change: Partial<State>) {
if (this.mounted) {
this.setState(change);
}
@@ -427,11 +427,11 @@
return granted;
}
- get queueModeActive() {
+ get queueModeActive(): boolean {
return !!this.state.queuedMediaURIs;
}
- renderItem = (row: { item: MediaLibrarySelection, ... }) => {
+ renderItem = (row: { +item: MediaLibrarySelection, ... }): React.Node => {
const { containerHeight, queuedMediaURIs } = this.state;
invariant(containerHeight, 'should be set');
const { uri } = row.item;
@@ -452,15 +452,15 @@
);
};
- ItemSeparator = () => {
+ ItemSeparator = (): React.Node => {
return <View style={this.props.styles.separator} />;
};
- static keyExtractor = (item: MediaLibrarySelection) => {
+ static keyExtractor = (item: MediaLibrarySelection): string => {
return item.uri;
};
- GalleryHeader = () => (
+ GalleryHeader = (): React.Node => (
<View style={this.props.styles.galleryHeader}>
<Text style={this.props.styles.galleryHeaderTitle}>Photos</Text>
<Button
@@ -474,7 +474,7 @@
</View>
);
- render() {
+ render(): React.Node {
let content;
const { selections, error, containerHeight } = this.state;
const bottomOffsetStyle: ViewStyle = {
diff --git a/native/media/media-utils.js b/native/media/media-utils.js
--- a/native/media/media-utils.js
+++ b/native/media/media-utils.js
@@ -66,7 +66,7 @@
reportPromise: Promise<$ReadOnlyArray<MediaMissionStep>>,
} {
let resolveResult;
- const sendResult = result => {
+ const sendResult = (result: MediaMissionFailure | MediaResult) => {
if (resolveResult) {
resolveResult(result);
}
diff --git a/native/media/multimedia.react.js b/native/media/multimedia.react.js
--- a/native/media/multimedia.react.js
+++ b/native/media/multimedia.react.js
@@ -42,7 +42,7 @@
+departingSource: ?Source,
};
class Multimedia extends React.PureComponent<Props, State> {
- static defaultProps = {
+ static defaultProps: Partial<Props> = {
spinnerColor: 'black',
};
@@ -55,7 +55,7 @@
};
}
- get inputState() {
+ get inputState(): InputState {
const { inputState } = this.props;
invariant(inputState, 'inputState should be set in Multimedia');
return inputState;
@@ -101,7 +101,7 @@
}
}
- render() {
+ render(): React.Node {
const images = [];
const { currentSource, departingSource } = this.state;
if (departingSource) {
@@ -117,7 +117,7 @@
source: Source,
invisibleLoad?: boolean = false,
triggerOnLoad?: boolean = true,
- ) {
+ ): React.Node {
const onLoadProp = triggerOnLoad ? this.onLoad : undefined;
if (source.kind === 'encrypted') {
return (
diff --git a/native/media/remote-image.react.js b/native/media/remote-image.react.js
--- a/native/media/remote-image.react.js
+++ b/native/media/remote-image.react.js
@@ -45,7 +45,7 @@
}
}
- render() {
+ render(): React.Node {
const { style, spinnerColor, invisibleLoad, uri, placeholder } = this.props;
const source = { uri };
diff --git a/native/media/save-media.js b/native/media/save-media.js
--- a/native/media/save-media.js
+++ b/native/media/save-media.js
@@ -136,7 +136,7 @@
reportPromise: Promise<$ReadOnlyArray<MediaMissionStep>>,
} {
let resolveResult;
- const sendResult = result => {
+ const sendResult = (result: MediaMissionResult) => {
if (resolveResult) {
resolveResult(result);
}
diff --git a/native/media/video-playback-modal.react.js b/native/media/video-playback-modal.react.js
--- a/native/media/video-playback-modal.react.js
+++ b/native/media/video-playback-modal.react.js
@@ -75,6 +75,12 @@
+item: ChatMultimediaMessageInfoItem,
};
+type ReactNativeVideoOnProgressData = {
+ +currentTime: number,
+ +playableDuration: number,
+ +seekableDuration: number,
+};
+
type Props = {
+navigation: AppNavigationProp<'VideoPlaybackModal'>,
+route: NavigationRoute<'VideoPlaybackModal'>,
@@ -197,7 +203,7 @@
const controlsShowing = useValue(1);
const outsideButtons = React.useCallback(
- (x, y) =>
+ (x: Animated.Value, y: Animated.Value) =>
and(
or(
eq(controlsShowing, 0),
@@ -586,13 +592,16 @@
videoRef.current.seek(0);
}, []);
- const progressCallback = React.useCallback(res => {
- setTimeElapsed(formatDuration(res.currentTime));
- setTotalDuration(formatDuration(res.seekableDuration));
- setPercentElapsed(
- Math.ceil((res.currentTime / res.seekableDuration) * 100),
- );
- }, []);
+ const progressCallback = React.useCallback(
+ (res: ReactNativeVideoOnProgressData) => {
+ setTimeElapsed(formatDuration(res.currentTime));
+ setTotalDuration(formatDuration(res.seekableDuration));
+ setPercentElapsed(
+ Math.ceil((res.currentTime / res.seekableDuration) * 100),
+ );
+ },
+ [],
+ );
const readyForDisplayCallback = React.useCallback(() => {
setSpinnerVisible(false);
diff --git a/native/navigation/community-drawer-content.react.js b/native/navigation/community-drawer-content.react.js
--- a/native/navigation/community-drawer-content.react.js
+++ b/native/navigation/community-drawer-content.react.js
@@ -31,6 +31,7 @@
import {
flattenDrawerItemsData,
filterOutThreadAndDescendantIDs,
+ type CommunityDrawerItemDataFlattened,
} from '../utils/drawer-utils.react.js';
const maxDepth = 2;
@@ -118,7 +119,12 @@
const navigateToThread = useNavigateToThread();
const renderItem = React.useCallback(
- ({ item }) => {
+ ({
+ item,
+ }: {
+ +item: CommunityDrawerItemDataFlattened,
+ ...
+ }): React.Node => {
const isCommunity = threadTypeIsCommunityRoot(item.threadInfo.type);
return (
<CommunityDrawerItem
diff --git a/native/navigation/nav-selectors.js b/native/navigation/nav-selectors.js
--- a/native/navigation/nav-selectors.js
+++ b/native/navigation/nav-selectors.js
@@ -46,7 +46,9 @@
import { useSelector } from '../redux/redux-utils.js';
import type { NavPlusRedux } from '../types/selector-types.js';
-const baseCreateIsForegroundSelector = (routeName: string) =>
+const baseCreateIsForegroundSelector: (
+ routeName: string,
+) => (context: ?NavContextType) => boolean = (routeName: string) =>
createSelector(
(context: ?NavContextType) => context && context.state,
(navigationState: ?PossiblyStaleNavigationState) => {
@@ -73,7 +75,9 @@
}, [navContext]);
}
-const baseCreateActiveTabSelector = (routeName: string) =>
+const baseCreateActiveTabSelector: (
+ routeName: string,
+) => (context: ?NavContextType) => boolean = (routeName: string) =>
createSelector(
(context: ?NavContextType) => context && context.state,
(navigationState: ?PossiblyStaleNavigationState) => {
diff --git a/native/navigation/orientation-handler.react.js b/native/navigation/orientation-handler.react.js
--- a/native/navigation/orientation-handler.react.js
+++ b/native/navigation/orientation-handler.react.js
@@ -33,7 +33,7 @@
}
}
- updateOrientation = orientation => {
+ updateOrientation = (orientation: Orientations) => {
if (orientation !== this.props.deviceOrientation) {
this.props.dispatch({
type: updateDeviceOrientationActionType,
@@ -42,7 +42,7 @@
}
};
- render() {
+ render(): React.Node {
return null;
}
}
diff --git a/native/navigation/root-navigator.react.js b/native/navigation/root-navigator.react.js
--- a/native/navigation/root-navigator.react.js
+++ b/native/navigation/root-navigator.react.js
@@ -10,6 +10,8 @@
StackNavigationHelpers,
StackNavigationProp,
StackRouterOptions,
+ RouteProp,
+ StackCardInterpolationProps,
} from '@react-navigation/core';
import {
createNavigatorFactory,
@@ -93,7 +95,10 @@
React.useState(true);
const mergedScreenOptions = React.useMemo(() => {
if (typeof screenOptions === 'function') {
- return input => ({
+ return (input: {
+ +route: RouteProp<>,
+ +navigation: RootNavigationHelpers<>,
+ }) => ({
...screenOptions(input),
keyboardHandlingEnabled,
});
@@ -152,7 +157,7 @@
});
const transitionPreset = {
...baseTransitionPreset,
- cardStyleInterpolator: interpolatorProps => {
+ cardStyleInterpolator: (interpolatorProps: StackCardInterpolationProps) => {
const baseCardStyleInterpolator =
baseTransitionPreset.cardStyleInterpolator(interpolatorProps);
const overlayOpacity = interpolatorProps.current.progress.interpolate({
diff --git a/native/navigation/tab-bar.react.js b/native/navigation/tab-bar.react.js
--- a/native/navigation/tab-bar.react.js
+++ b/native/navigation/tab-bar.react.js
@@ -37,7 +37,7 @@
const prevKeyboardState = prevKeyboardStateRef.current;
const setTabBar = React.useCallback(
- toValue => {
+ (toValue: number) => {
const keyboardIsShowing = keyboardState && keyboardState.keyboardShowing;
const keyboardWasShowing =
prevKeyboardState && prevKeyboardState.keyboardShowing;
@@ -68,7 +68,7 @@
const reduxTabBarHeight = useSelector(state => state.dimensions.tabBarHeight);
const dispatch = useDispatch();
const setReduxTabBarHeight = React.useCallback(
- height => {
+ (height: number) => {
if (height === reduxTabBarHeight) {
return;
}
diff --git a/native/navigation/tab-navigator.react.js b/native/navigation/tab-navigator.react.js
--- a/native/navigation/tab-navigator.react.js
+++ b/native/navigation/tab-navigator.react.js
@@ -46,14 +46,14 @@
const calendarTabOptions = {
tabBarLabel: 'Calendar',
// eslint-disable-next-line react/display-name
- tabBarIcon: ({ color }) => (
+ tabBarIcon: ({ color }: { +color: string, ... }) => (
<SWMansionIcon name="calendar" style={[styles.icon, { color }]} />
),
};
const getChatTabOptions = (badge: number) => ({
tabBarLabel: 'Inbox',
// eslint-disable-next-line react/display-name
- tabBarIcon: ({ color }) => (
+ tabBarIcon: ({ color }: { +color: string, ... }) => (
<SWMansionIcon name="message-square" style={[styles.icon, { color }]} />
),
tabBarBadge: badge ? badge : undefined,
@@ -61,14 +61,14 @@
const profileTabOptions = {
tabBarLabel: 'Profile',
// eslint-disable-next-line react/display-name
- tabBarIcon: ({ color }) => (
+ tabBarIcon: ({ color }: { +color: string, ... }) => (
<SWMansionIcon name="user-2" style={[styles.icon, { color }]} />
),
};
const appsTabOptions = {
tabBarLabel: 'Apps',
// eslint-disable-next-line react/display-name
- tabBarIcon: ({ color }) => (
+ tabBarIcon: ({ color }: { +color: string, ... }) => (
<SWMansionIcon name="globe-1" style={[styles.icon, { color }]} />
),
};
diff --git a/native/profile/appearance-preferences.react.js b/native/profile/appearance-preferences.react.js
--- a/native/profile/appearance-preferences.react.js
+++ b/native/profile/appearance-preferences.react.js
@@ -93,7 +93,7 @@
+colors: Colors,
};
class AppearancePreferences extends React.PureComponent<Props> {
- render() {
+ render(): React.Node {
const { panelIosHighlightUnderlay: underlay } = this.props.colors;
const options: Array<React.Node> = [];
diff --git a/native/profile/backup-menu.react.js b/native/profile/backup-menu.react.js
--- a/native/profile/backup-menu.react.js
+++ b/native/profile/backup-menu.react.js
@@ -48,7 +48,7 @@
}, [restoreBackupProtocol, userStore]);
const onBackupToggled = React.useCallback(
- value => {
+ (value: boolean) => {
dispatch({
type: setLocalSettingsActionType,
payload: { isBackupEnabled: value },
diff --git a/native/profile/custom-server-modal.react.js b/native/profile/custom-server-modal.react.js
--- a/native/profile/custom-server-modal.react.js
+++ b/native/profile/custom-server-modal.react.js
@@ -77,7 +77,7 @@
};
}
- render() {
+ render(): React.Node {
return (
<Modal
containerStyle={this.props.styles.container}
diff --git a/native/profile/default-notifications-preferences.react.js b/native/profile/default-notifications-preferences.react.js
--- a/native/profile/default-notifications-preferences.react.js
+++ b/native/profile/default-notifications-preferences.react.js
@@ -143,7 +143,7 @@
this.selectNotificationSetting(notificationTypes.BADGE_ONLY);
};
- render() {
+ render(): React.Node {
const { styles, selectedDefaultNotification } = this.props;
return (
<ScrollView
diff --git a/native/profile/dev-tools.react.js b/native/profile/dev-tools.react.js
--- a/native/profile/dev-tools.react.js
+++ b/native/profile/dev-tools.react.js
@@ -102,7 +102,7 @@
+dispatch: Dispatch,
};
class DevTools extends React.PureComponent<Props> {
- render() {
+ render(): React.Node {
const { panelIosHighlightUnderlay: underlay } = this.props.colors;
const serverButtons: Array<React.Node> = [];
@@ -206,7 +206,7 @@
);
}
- onPressCrash = () => {
+ onPressCrash = (): empty => {
throw new Error('User triggered crash through dev menu!');
};
diff --git a/native/profile/edit-password.react.js b/native/profile/edit-password.react.js
--- a/native/profile/edit-password.react.js
+++ b/native/profile/edit-password.react.js
@@ -129,7 +129,7 @@
this.mounted = false;
}
- render() {
+ render(): React.Node {
const buttonContent =
this.props.loadingStatus === 'loading' ? (
<ActivityIndicator size="small" color="white" />
diff --git a/native/profile/emoji-user-avatar-creation.react.js b/native/profile/emoji-user-avatar-creation.react.js
--- a/native/profile/emoji-user-avatar-creation.react.js
+++ b/native/profile/emoji-user-avatar-creation.react.js
@@ -5,6 +5,7 @@
import { EditUserAvatarContext } from 'lib/components/edit-user-avatar-provider.react.js';
import { savedEmojiAvatarSelectorForCurrentUser } from 'lib/selectors/user-selectors.js';
+import type { UpdateUserAvatarRequest } from 'lib/types/avatar-types.js';
import type { ProfileNavigationProp } from './profile.react.js';
import { useNativeSetUserAvatar } from '../avatars/avatar-hooks.js';
@@ -27,7 +28,7 @@
const nativeSetUserAvatar = useNativeSetUserAvatar();
const setAvatar = React.useCallback(
- async avatarRequest => {
+ async (avatarRequest: UpdateUserAvatarRequest): Promise<void> => {
const result = await nativeSetUserAvatar(avatarRequest);
displayActionResultModal('Avatar updated!');
return result;
diff --git a/native/profile/keyserver-selection-list.react.js b/native/profile/keyserver-selection-list.react.js
--- a/native/profile/keyserver-selection-list.react.js
+++ b/native/profile/keyserver-selection-list.react.js
@@ -16,7 +16,12 @@
return `${item.keyserverAdminUserInfo.id}${item.keyserverInfo.urlPrefix}`;
}
-function renderKeyserverListItem({ item }) {
+function renderKeyserverListItem({
+ item,
+}: {
+ +item: SelectedKeyserverInfo,
+ ...
+}) {
return <KeyserverSelectionListItem {...item} />;
}
diff --git a/native/profile/profile-screen.react.js b/native/profile/profile-screen.react.js
--- a/native/profile/profile-screen.react.js
+++ b/native/profile/profile-screen.react.js
@@ -162,7 +162,7 @@
};
class ProfileScreen extends React.PureComponent<Props> {
- get loggedOutOrLoggingOut() {
+ get loggedOutOrLoggingOut(): boolean {
return (
!this.props.currentUserInfo ||
this.props.currentUserInfo.anonymous ||
@@ -170,7 +170,7 @@
);
}
- render() {
+ render(): React.Node {
let developerTools,
defaultNotifications,
keyserverSelection,
diff --git a/native/profile/profile.react.js b/native/profile/profile.react.js
--- a/native/profile/profile.react.js
+++ b/native/profile/profile.react.js
@@ -4,6 +4,7 @@
StackNavigationProp,
StackNavigationHelpers,
StackHeaderProps,
+ StackHeaderLeftButtonProps,
} from '@react-navigation/core';
import { createStackNavigator } from '@react-navigation/stack';
import * as React from 'react';
@@ -107,7 +108,7 @@
const colors = useColors();
const headerLeftButton = React.useCallback(
- headerProps =>
+ (headerProps: StackHeaderLeftButtonProps) =>
headerProps.canGoBack ? (
<HeaderBackButton {...headerProps} />
) : (
diff --git a/native/profile/relationship-list-item.react.js b/native/profile/relationship-list-item.react.js
--- a/native/profile/relationship-list-item.react.js
+++ b/native/profile/relationship-list-item.react.js
@@ -10,6 +10,7 @@
} from 'lib/actions/relationship-actions.js';
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js';
import type { LoadingStatus } from 'lib/types/loading-types.js';
+import type { ReactRef } from 'lib/types/react-types.js';
import {
type RelationshipRequest,
type RelationshipAction,
@@ -118,9 +119,9 @@
+navigateToUserProfileBottomSheet: (userID: string) => mixed,
};
class RelationshipListItem extends React.PureComponent<Props> {
- editButton = React.createRef<React.ElementRef<typeof View>>();
+ editButton: ReactRef<React.ElementRef<typeof View>> = React.createRef();
- render() {
+ render(): React.Node {
const {
lastListItem,
removeUserLoadingStatus,
@@ -230,7 +231,7 @@
this.props.onSelect({ id, username });
};
- visibleEntryIDs() {
+ visibleEntryIDs(): [string] {
const { relationshipListRoute } = this.props;
const id = {
[FriendListRouteName]: 'unfriend',
@@ -300,7 +301,9 @@
);
}
- async updateFriendship(action: RelationshipAction) {
+ async updateFriendship(
+ action: RelationshipAction,
+ ): Promise<RelationshipErrors> {
try {
return await this.props.updateRelationships({
action,
diff --git a/native/profile/relationship-list.react.js b/native/profile/relationship-list.react.js
--- a/native/profile/relationship-list.react.js
+++ b/native/profile/relationship-list.react.js
@@ -96,7 +96,9 @@
const callSearchUsers = useServerCall(searchUsers);
const userInfos = useSelector(state => state.userStore.userInfos);
const searchUsersOnServer = React.useCallback(
- async (usernamePrefix: string) => {
+ async (
+ usernamePrefix: string,
+ ): Promise<$ReadOnlyArray<GlobalAccountUserInfo>> => {
if (usernamePrefix.length === 0) {
return [];
}
diff --git a/native/profile/toggle-report.react.js b/native/profile/toggle-report.react.js
--- a/native/profile/toggle-report.react.js
+++ b/native/profile/toggle-report.react.js
@@ -17,7 +17,7 @@
const isReportEnabled = useIsReportEnabled(reportType);
const onReportToggled = React.useCallback(
- value => {
+ (value: boolean) => {
dispatch({
type: updateReportsEnabledActionType,
payload: { [(reportType: string)]: value },
diff --git a/native/push/push-handler.react.js b/native/push/push-handler.react.js
--- a/native/push/push-handler.react.js
+++ b/native/push/push-handler.react.js
@@ -420,7 +420,7 @@
}
}
- requestAndroidNotificationsPermission = () => {
+ requestAndroidNotificationsPermission = (): Promise<boolean> => {
if (!this.androidNotificationsPermissionPromise) {
this.androidNotificationsPermissionPromise = (async () => {
const notifPermission =
@@ -675,7 +675,7 @@
handleAndroidNotificationIfActive = (
threadID: string,
texts: { body: string, title: ?string },
- ) => {
+ ): boolean => {
if (this.currentState !== 'active') {
return false;
}
@@ -683,7 +683,7 @@
return true;
};
- render() {
+ render(): React.Node {
return (
<InAppNotification
{...this.state.inAppNotifProps}
diff --git a/native/redux/client-db-utils.js b/native/redux/client-db-utils.js
--- a/native/redux/client-db-utils.js
+++ b/native/redux/client-db-utils.js
@@ -70,10 +70,13 @@
);
// Convert `rawThreadInfo`s to a map of `threadID` => `threadInfo`.
- const threadIDToThreadInfo = rawThreadInfos.reduce((acc, threadInfo) => {
- acc[threadInfo.id] = threadInfo;
- return acc;
- }, {});
+ const threadIDToThreadInfo = rawThreadInfos.reduce(
+ (acc: { [string]: RawThreadInfo }, threadInfo: RawThreadInfo) => {
+ acc[threadInfo.id] = threadInfo;
+ return acc;
+ },
+ {},
+ );
// Apply `migrationFunc` to `threadInfo`s.
const updatedThreadIDToThreadInfo: ThreadStoreThreadInfos =
diff --git a/native/redux/connectivity-updater.react.js b/native/redux/connectivity-updater.react.js
--- a/native/redux/connectivity-updater.react.js
+++ b/native/redux/connectivity-updater.react.js
@@ -8,12 +8,23 @@
import { updateConnectivityActiveType } from './action-types.js';
import { useSelector } from './redux-utils.js';
+type NetInfoStateType =
+ | 'none'
+ | 'unknown'
+ | 'cellular'
+ | 'wifi'
+ | 'bluetooth'
+ | 'ethernet'
+ | 'wimax'
+ | 'vpn'
+ | 'other';
+
export default function ConnectivityUpdater(): null {
const connectivity = useSelector(state => state.connectivity);
const dispatch = useDispatch();
const onConnectionChange = React.useCallback(
- ({ type }) => {
+ ({ type }: { +type: NetInfoStateType, ... }) => {
const connected = type !== 'none' && type !== 'unknown';
const hasWiFi = type === 'wifi';
if (
diff --git a/native/redux/persist.js b/native/redux/persist.js
--- a/native/redux/persist.js
+++ b/native/redux/persist.js
@@ -118,7 +118,7 @@
...state,
messageSentFromRoute: [],
}),
- [3]: state => ({
+ [3]: (state: any) => ({
currentUserInfo: state.currentUserInfo,
entryStore: state.entryStore,
threadInfos: state.threadInfos,
@@ -145,7 +145,7 @@
...state,
calendarFilters: defaultCalendarFilters,
}),
- [6]: state => ({
+ [6]: (state: any) => ({
...state,
threadInfos: undefined,
threadStore: {
@@ -153,7 +153,7 @@
inconsistencyResponses: [],
},
}),
- [7]: state => ({
+ [7]: (state: AppState) => ({
...state,
lastUserInteraction: undefined,
sessionID: undefined,
@@ -176,14 +176,14 @@
actualizedCalendarQuery: undefined,
},
}),
- [9]: state => ({
+ [9]: (state: any) => ({
...state,
connection: {
...state.connection,
lateResponses: [],
},
}),
- [10]: state => ({
+ [10]: (state: any) => ({
...state,
nextLocalID: highestLocalIDSelector(state) + 1,
connection: {
@@ -211,7 +211,7 @@
deviceOrientation: Orientation.getInitialOrientation(),
}),
[14]: (state: AppState) => state,
- [15]: state => ({
+ [15]: (state: any) => ({
...state,
threadStore: {
...state.threadStore,
@@ -229,7 +229,7 @@
},
queuedReports: [],
}),
- [16]: state => {
+ [16]: (state: any) => {
const result = {
...state,
messageSentFromRoute: undefined,
@@ -243,7 +243,7 @@
}
return result;
},
- [17]: state => ({
+ [17]: (state: any) => ({
...state,
userInfos: undefined,
userStore: {
@@ -251,14 +251,14 @@
inconsistencyResponses: [],
},
}),
- [18]: state => ({
+ [18]: (state: AppState) => ({
...state,
userStore: {
userInfos: state.userStore.userInfos,
inconsistencyReports: [],
},
}),
- [19]: state => {
+ [19]: (state: any) => {
const threadInfos: { [string]: RawThreadInfo } = {};
for (const threadID in state.threadStore.threadInfos) {
const threadInfo = state.threadStore.threadInfos[threadID];
@@ -286,7 +286,7 @@
messageTypes.SIDEBAR_SOURCE,
]),
}),
- [22]: state => {
+ [22]: (state: any) => {
for (const key in state.drafts) {
const value = state.drafts[key];
try {
@@ -302,19 +302,19 @@
drafts: undefined,
};
},
- [23]: state => ({
+ [23]: (state: AppState) => ({
...state,
globalThemeInfo: defaultGlobalThemeInfo,
}),
- [24]: state => ({
+ [24]: (state: AppState) => ({
...state,
enabledApps: defaultEnabledApps,
}),
- [25]: state => ({
+ [25]: (state: AppState) => ({
...state,
crashReportsEnabled: __DEV__,
}),
- [26]: state => {
+ [26]: (state: any) => {
const { currentUserInfo } = state;
if (currentUserInfo.anonymous) {
return state;
@@ -333,7 +333,7 @@
},
};
},
- [27]: state => ({
+ [27]: (state: any) => ({
...state,
queuedReports: undefined,
enabledReports: undefined,
@@ -358,7 +358,7 @@
],
},
}),
- [28]: state => {
+ [28]: (state: AppState) => {
const threadParentToChildren: { [string]: string[] } = {};
for (const threadID in state.threadStore.threadInfos) {
const threadInfo = state.threadStore.threadInfos[threadID];
@@ -463,7 +463,7 @@
},
[32]: (state: AppState) => unshimClientDB(state, [messageTypes.MULTIMEDIA]),
[33]: (state: AppState) => unshimClientDB(state, [messageTypes.REACTION]),
- [34]: state => {
+ [34]: (state: any) => {
const { threadIDsToNotifIDs, ...stateSansThreadIDsToNotifIDs } = state;
return stateSansThreadIDsToNotifIDs;
},
@@ -523,7 +523,7 @@
// 8. Convert rawThreadInfos to a map of threadID to threadInfo
const threadIDToThreadInfo = rawThreadInfosWithPinnedCount.reduce(
- (acc, threadInfo) => {
+ (acc: { [string]: RawThreadInfo }, threadInfo: RawThreadInfo) => {
acc[threadInfo.id] = threadInfo;
return acc;
},
@@ -568,7 +568,7 @@
return state;
},
- [37]: state => {
+ [37]: (state: AppState) => {
const operations = messageStoreOpsHandlers.convertOpsToClientDBOps([
{
type: 'remove_all_threads',
@@ -591,10 +591,10 @@
return state;
},
- [38]: state =>
+ [38]: (state: AppState) =>
updateClientDBThreadStoreThreadInfos(state, updateRolesAndPermissions),
[39]: (state: AppState) => unshimClientDB(state, [messageTypes.EDIT_MESSAGE]),
- [40]: state =>
+ [40]: (state: AppState) =>
updateClientDBThreadStoreThreadInfos(state, updateRolesAndPermissions),
[41]: (state: AppState) => {
const queuedReports = state.reportStore.queuedReports.map(report => ({
@@ -624,7 +624,7 @@
}
return state;
},
- [43]: async state => {
+ [43]: async (state: any) => {
const { messages, drafts, threads, messageStoreThreads } =
await commCoreModule.getClientDBStore();
@@ -677,7 +677,7 @@
inviteLinksStore: convertInviteLinksStoreToNewIDSchema(inviteLinksStore),
};
},
- [44]: async state => {
+ [44]: async (state: any) => {
const { cookie, ...rest } = state;
return {
@@ -685,7 +685,7 @@
keyserverStore: { keyserverInfos: { [ashoatKeyserverID]: { cookie } } },
};
},
- [45]: async state => {
+ [45]: async (state: any) => {
const { updatesCurrentAsOf, keyserverStore, ...rest } = state;
return {
@@ -702,7 +702,7 @@
},
};
},
- [46]: async state => {
+ [46]: async (state: AppState) => {
const { currentAsOf } = state.messageStore;
return {
@@ -713,7 +713,7 @@
},
};
},
- [47]: async state => {
+ [47]: async (state: any) => {
const { urlPrefix, keyserverStore, ...rest } = state;
return {
@@ -730,7 +730,7 @@
},
};
},
- [48]: async state => {
+ [48]: async (state: any) => {
const { connection, keyserverStore, ...rest } = state;
return {
@@ -747,7 +747,7 @@
},
};
},
- [49]: async state => {
+ [49]: async (state: AppState) => {
const { keyserverStore, ...rest } = state;
const { connection, ...keyserverRest } =
@@ -767,7 +767,7 @@
connection,
};
},
- [50]: async state => {
+ [50]: async (state: any) => {
const { connection, ...rest } = state;
const { actualizedCalendarQuery, ...connectionRest } = connection;
@@ -777,7 +777,7 @@
actualizedCalendarQuery,
};
},
- [51]: async state => {
+ [51]: async (state: any) => {
const { lastCommunicatedPlatformDetails, keyserverStore, ...rest } = state;
return {
@@ -794,14 +794,14 @@
},
};
},
- [52]: async state => ({
+ [52]: async (state: AppState) => ({
...state,
integrityStore: {
threadHashes: {},
threadHashingStatus: 'data_not_loaded',
},
}),
- [53]: state => {
+ [53]: (state: any) => {
if (!state.userStore.inconsistencyReports) {
return state;
}
@@ -833,7 +833,7 @@
},
};
},
- [54]: state => {
+ [54]: (state: any) => {
let updatedMessageStoreThreads: MessageStoreThreads = {};
for (const threadID: string in state.messageStore.threads) {
const { lastNavigatedTo, lastPruned, ...rest } =
@@ -853,7 +853,7 @@
},
};
},
- [55]: async state =>
+ [55]: async (state: AppState) =>
__DEV__
? {
...state,
@@ -869,7 +869,7 @@
},
}
: state,
- [56]: state => {
+ [56]: (state: any) => {
const { deviceToken, keyserverStore, ...rest } = state;
return {
@@ -886,7 +886,7 @@
},
};
},
- [57]: async state => {
+ [57]: async (state: any) => {
const {
// eslint-disable-next-line no-unused-vars
connection,
@@ -926,15 +926,18 @@
}
return state;
},
- [59]: state => {
+ [59]: (state: AppState) => {
const clientDBThreadInfos = commCoreModule.getAllThreadsSync();
const rawThreadInfos = clientDBThreadInfos.map(
convertClientDBThreadInfoToRawThreadInfo,
);
- const rawThreadInfosObject = rawThreadInfos.reduce((acc, threadInfo) => {
- acc[threadInfo.id] = threadInfo;
- return acc;
- }, {});
+ const rawThreadInfosObject = rawThreadInfos.reduce(
+ (acc: { [string]: RawThreadInfo }, threadInfo: RawThreadInfo) => {
+ acc[threadInfo.id] = threadInfo;
+ return acc;
+ },
+ {},
+ );
const migratedRawThreadInfos =
persistMigrationToRemoveSelectRolePermissions(rawThreadInfosObject);
@@ -964,7 +967,7 @@
return state;
},
- [60]: state =>
+ [60]: (state: AppState) =>
updateClientDBThreadStoreThreadInfos(state, updateRolesAndPermissions),
};
diff --git a/native/redux/update-roles-and-permissions.js b/native/redux/update-roles-and-permissions.js
--- a/native/redux/update-roles-and-permissions.js
+++ b/native/redux/update-roles-and-permissions.js
@@ -32,7 +32,7 @@
];
}
- const constructNodes = nodeID => ({
+ const constructNodes = (nodeID: string): ThreadTraversalNode => ({
threadID: nodeID,
children: parentThreadMap[nodeID]?.map(constructNodes) ?? null,
});
diff --git a/native/roles/roles-navigator.react.js b/native/roles/roles-navigator.react.js
--- a/native/roles/roles-navigator.react.js
+++ b/native/roles/roles-navigator.react.js
@@ -3,6 +3,7 @@
import type {
StackNavigationProp,
StackNavigationHelpers,
+ StackHeaderLeftButtonProps,
} from '@react-navigation/core';
import { createStackNavigator } from '@react-navigation/stack';
import * as React from 'react';
@@ -34,7 +35,7 @@
const communityRolesScreenOptions = {
headerTitle: 'Create role',
// eslint-disable-next-line react/display-name
- headerLeft: headerLeftProps => (
+ headerLeft: (headerLeftProps: StackHeaderLeftButtonProps) => (
<CommunityRolesHeaderLeftButton {...headerLeftProps} />
),
};
diff --git a/native/search/message-search.react.js b/native/search/message-search.react.js
--- a/native/search/message-search.react.js
+++ b/native/search/message-search.react.js
@@ -147,7 +147,7 @@
}, []);
const renderItem = React.useCallback(
- ({ item }) => {
+ ({ item }: { +item: ChatMessageItemWithHeight, ... }) => {
if (item.itemType === 'loader') {
return <ListLoadingIndicator />;
}
diff --git a/native/tooltip/tooltip.react.js b/native/tooltip/tooltip.react.js
--- a/native/tooltip/tooltip.react.js
+++ b/native/tooltip/tooltip.react.js
@@ -36,7 +36,11 @@
type LayoutCoordinates,
} from '../types/layout-types.js';
import type { LayoutEvent } from '../types/react-native.js';
-import { AnimatedView } from '../types/styles.js';
+import {
+ AnimatedView,
+ type ViewStyle,
+ type AnimatedViewStyle,
+} from '../types/styles.js';
/* eslint-disable import/no-named-as-default-member */
const { Value, Node, Extrapolate, add, multiply, interpolateNode } = Animated;
@@ -258,14 +262,14 @@
return 'below';
}
- get opacityStyle() {
+ get opacityStyle(): AnimatedViewStyle {
return {
...this.props.styles.backdrop,
opacity: this.backdropOpacity,
};
}
- get contentContainerStyle() {
+ get contentContainerStyle(): ViewStyle {
const { verticalBounds } = this.props.route.params;
const fullScreenHeight = this.props.dimensions.height;
const top = verticalBounds.y;
@@ -278,7 +282,7 @@
};
}
- get buttonStyle() {
+ get buttonStyle(): ViewStyle {
const { params } = this.props.route;
const { initialCoordinates, verticalBounds } = params;
const { x, y, width, height } = initialCoordinates;
@@ -290,14 +294,14 @@
};
}
- get margin() {
+ get margin(): number {
const customMargin = this.props.route.params.margin;
return customMargin !== null && customMargin !== undefined
? customMargin
: 20;
}
- get tooltipContainerStyle() {
+ get tooltipContainerStyle(): AnimatedViewStyle {
const { dimensions, route } = this.props;
const { initialCoordinates, verticalBounds, chatInputBarHeight } =
route.params;
@@ -356,7 +360,7 @@
return style;
}
- render() {
+ render(): React.Node {
const {
dimensions,
overlayContext,
@@ -473,7 +477,7 @@
);
}
- getTooltipItem() {
+ getTooltipItem(): React.ComponentType<TooltipItemBaseProps> {
const BoundTooltipItem = this.props.boundTooltipItem;
return BoundTooltipItem;
}
@@ -483,7 +487,7 @@
this.props.tooltipContext.showActionSheet();
};
- renderMoreIcon = () => {
+ renderMoreIcon = (): React.Node => {
const { styles } = this.props;
return (
<SWMansionIcon name="menu-vertical" style={styles.icon} size={16} />
@@ -507,7 +511,12 @@
}
};
}
- function ConnectedTooltip(props) {
+ function ConnectedTooltip(
+ props: $ReadOnly<{
+ ...BaseTooltipPropsType,
+ +hideTooltip: () => mixed,
+ }>,
+ ) {
const dimensions = useSelector(state => state.dimensions);
const overlayContext = React.useContext(OverlayContext);
const chatContext = React.useContext(ChatContext);
@@ -528,7 +537,7 @@
const styles = useStyles(unboundStyles);
const boundTooltipItem = React.useCallback(
- innerProps => {
+ (innerProps: TooltipItemBaseProps) => {
const containerStyle = isFixed
? [styles.itemContainer, styles.itemContainerFixed]
: styles.itemContainer;
diff --git a/native/utils/typeahead-utils.js b/native/utils/typeahead-utils.js
--- a/native/utils/typeahead-utils.js
+++ b/native/utils/typeahead-utils.js
@@ -18,20 +18,34 @@
`((^(.|\n)*\\s+)|^)@(${validChatNameRegexString})?$`,
);
+type FocusAndUpdateTextAndSelection = (
+ text: string,
+ selection: Selection,
+) => void;
+
export type TypeaheadTooltipActionsParams<SuggestionItemType> = {
+suggestions: $ReadOnlyArray<SuggestionItemType>,
+textBeforeAtSymbol: string,
+text: string,
+query: string,
- +focusAndUpdateTextAndSelection: (text: string, selection: Selection) => void,
+ +focusAndUpdateTextAndSelection: FocusAndUpdateTextAndSelection,
+};
+
+type MentionTypeaheadTooltipActionExecuteHandlerParams = {
+ +textBeforeAtSymbol: string,
+ +text: string,
+ +query: string,
+ +mentionText: string,
+ +focusAndUpdateTextAndSelection: FocusAndUpdateTextAndSelection,
};
+
function mentionTypeaheadTooltipActionExecuteHandler({
textBeforeAtSymbol,
text,
query,
mentionText,
focusAndUpdateTextAndSelection,
-}) {
+}: MentionTypeaheadTooltipActionExecuteHandlerParams) {
const { newText, newSelectionStart } = getNewTextAndSelection(
textBeforeAtSymbol,
text,
@@ -43,6 +57,7 @@
end: newSelectionStart,
});
}
+
function mentionTypeaheadTooltipActions({
suggestions,
textBeforeAtSymbol,

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 30, 1:04 PM (21 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2601030
Default Alt Text
D10015.diff (136 KB)

Event Timeline