Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3388166
D10015.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
136 KB
Referenced Files
None
Subscribers
None
D10015.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D10015: [Flow202][native][skip-ci] [31/x] Address missing-local-annot type errors
Attached
Detach File
Event Timeline
Log In to Comment