diff --git a/native/account/logged-out-modal.react.js b/native/account/logged-out-modal.react.js index a90beb9bc..b74311322 100644 --- a/native/account/logged-out-modal.react.js +++ b/native/account/logged-out-modal.react.js @@ -1,677 +1,677 @@ // @flow import _isEqual from 'lodash/fp/isEqual'; import * as React from 'react'; import { View, StyleSheet, Text, TouchableOpacity, Image, Keyboard, Platform, BackHandler, ActivityIndicator, } from 'react-native'; import Animated, { EasingNode } from 'react-native-reanimated'; import { SafeAreaView } from 'react-native-safe-area-context'; -import Icon from 'react-native-vector-icons/FontAwesome'; +import Icon from '@expo/vector-icons/FontAwesome'; import { useDispatch } from 'react-redux'; import { isLoggedIn } from 'lib/selectors/user-selectors'; import { logInActionSources } from 'lib/types/account-types'; import type { Dispatch } from 'lib/types/redux-types'; import { fetchNewCookieFromNativeCredentials } from 'lib/utils/action-utils'; import KeyboardAvoidingView from '../components/keyboard-avoiding-view.react'; import ConnectedStatusBar from '../connected-status-bar.react'; import { addKeyboardShowListener, addKeyboardDismissListener, removeKeyboardListener, } from '../keyboard/keyboard'; import { createIsForegroundSelector } from '../navigation/nav-selectors'; import { NavContext } from '../navigation/navigation-context'; import { LoggedOutModalRouteName } from '../navigation/route-names'; import { resetUserStateActionType } from '../redux/action-types'; import { useSelector } from '../redux/redux-utils'; import { usePersistedStateLoaded } from '../selectors/app-state-selectors'; import { type DerivedDimensionsInfo, derivedDimensionsInfoSelector, } from '../selectors/dimensions-selectors'; import { splashStyleSelector } from '../splash'; import type { EventSubscription, KeyboardEvent } from '../types/react-native'; import type { ImageStyle } from '../types/styles'; import { runTiming, ratchetAlongWithKeyboardHeight, } from '../utils/animation-utils'; import { type StateContainer, type StateChange, setStateForContainer, } from '../utils/state-container'; import { splashBackgroundURI } from './background-info'; import LogInPanel from './log-in-panel.react'; import type { LogInState } from './log-in-panel.react'; import LoggedOutStaffInfo from './logged-out-staff-info.react'; import RegisterPanel from './register-panel.react'; import type { RegisterState } from './register-panel.react'; import SIWEPanel from './siwe-panel.react'; let initialAppLoad = true; const safeAreaEdges = ['top', 'bottom']; /* eslint-disable import/no-named-as-default-member */ const { Value, Node, Clock, block, set, call, cond, not, and, eq, neq, lessThan, greaterOrEq, add, sub, divide, max, stopClock, clockRunning, } = Animated; /* eslint-enable import/no-named-as-default-member */ type LoggedOutMode = 'loading' | 'prompt' | 'log-in' | 'register' | 'siwe'; const modeNumbers: { [LoggedOutMode]: number } = { 'loading': 0, 'prompt': 1, 'log-in': 2, 'register': 3, 'siwe': 4, }; function isPastPrompt(modeValue: Node) { return and( neq(modeValue, modeNumbers['loading']), neq(modeValue, modeNumbers['prompt']), ); } type Props = { // Navigation state +isForeground: boolean, // Redux state +persistedStateLoaded: boolean, +rehydrateConcluded: boolean, +cookie: ?string, +urlPrefix: string, +loggedIn: boolean, +dimensions: DerivedDimensionsInfo, +splashStyle: ImageStyle, // Redux dispatch functions +dispatch: Dispatch, ... }; type State = { +mode: LoggedOutMode, +logInState: StateContainer, +registerState: StateContainer, }; class LoggedOutModal extends React.PureComponent { keyboardShowListener: ?EventSubscription; keyboardHideListener: ?EventSubscription; mounted = false; nextMode: LoggedOutMode = 'loading'; activeAlert = false; contentHeight: Value; keyboardHeightValue = new Value(0); modeValue: Value; buttonOpacity: Value; panelPaddingTopValue: Node; panelOpacityValue: Node; constructor(props: Props) { super(props); // Man, this is a lot of boilerplate just to containerize some state. // Mostly due to Flow typing requirements... const setLogInState = setStateForContainer( this.guardedSetState, (change: $Shape) => (fullState: State) => ({ logInState: { ...fullState.logInState, state: { ...fullState.logInState.state, ...change }, }, }), ); const setRegisterState = setStateForContainer( this.guardedSetState, (change: $Shape) => (fullState: State) => ({ registerState: { ...fullState.registerState, state: { ...fullState.registerState.state, ...change }, }, }), ); this.state = { mode: props.persistedStateLoaded ? 'prompt' : 'loading', logInState: { state: { usernameInputText: null, passwordInputText: null, }, setState: setLogInState, }, registerState: { state: { usernameInputText: '', passwordInputText: '', confirmPasswordInputText: '', }, setState: setRegisterState, }, }; if (props.persistedStateLoaded) { this.nextMode = 'prompt'; } this.contentHeight = new Value(props.dimensions.safeAreaHeight); this.modeValue = new Value(modeNumbers[this.nextMode]); this.buttonOpacity = new Value(props.persistedStateLoaded ? 1 : 0); this.panelPaddingTopValue = this.panelPaddingTop(); this.panelOpacityValue = this.panelOpacity(); } guardedSetState = (change: StateChange, callback?: () => mixed) => { if (this.mounted) { this.setState(change, callback); } }; setMode(newMode: LoggedOutMode) { this.nextMode = newMode; this.guardedSetState({ mode: newMode }); this.modeValue.setValue(modeNumbers[newMode]); } proceedToNextMode = () => { this.guardedSetState({ mode: this.nextMode }); }; componentDidMount() { this.mounted = true; if (this.props.rehydrateConcluded) { this.onInitialAppLoad(); } if (this.props.isForeground) { this.onForeground(); } } componentWillUnmount() { this.mounted = false; if (this.props.isForeground) { this.onBackground(); } } componentDidUpdate(prevProps: Props, prevState: State) { if (!prevProps.persistedStateLoaded && this.props.persistedStateLoaded) { this.setMode('prompt'); } if (!prevProps.rehydrateConcluded && this.props.rehydrateConcluded) { this.onInitialAppLoad(); } if (!prevProps.isForeground && this.props.isForeground) { this.onForeground(); } else if (prevProps.isForeground && !this.props.isForeground) { this.onBackground(); } if (this.state.mode === 'prompt' && prevState.mode !== 'prompt') { this.buttonOpacity.setValue(0); Animated.timing(this.buttonOpacity, { easing: EasingNode.out(EasingNode.ease), duration: 250, toValue: 1.0, }).start(); } const newContentHeight = this.props.dimensions.safeAreaHeight; const oldContentHeight = prevProps.dimensions.safeAreaHeight; if (newContentHeight !== oldContentHeight) { this.contentHeight.setValue(newContentHeight); } } onForeground() { this.keyboardShowListener = addKeyboardShowListener(this.keyboardShow); this.keyboardHideListener = addKeyboardDismissListener(this.keyboardHide); BackHandler.addEventListener('hardwareBackPress', this.hardwareBack); } onBackground() { if (this.keyboardShowListener) { removeKeyboardListener(this.keyboardShowListener); this.keyboardShowListener = null; } if (this.keyboardHideListener) { removeKeyboardListener(this.keyboardHideListener); this.keyboardHideListener = null; } BackHandler.removeEventListener('hardwareBackPress', this.hardwareBack); } // This gets triggered when an app is killed and restarted // Not when it is returned from being backgrounded async onInitialAppLoad() { if (!initialAppLoad) { return; } initialAppLoad = false; const { loggedIn, cookie, urlPrefix, dispatch } = this.props; const hasUserCookie = cookie && cookie.startsWith('user='); if (loggedIn === !!hasUserCookie) { return; } if (!__DEV__) { const actionSource = loggedIn ? logInActionSources.appStartReduxLoggedInButInvalidCookie : logInActionSources.appStartCookieLoggedInButInvalidRedux; const sessionChange = await fetchNewCookieFromNativeCredentials( dispatch, cookie, urlPrefix, actionSource, ); if ( sessionChange && sessionChange.cookie && sessionChange.cookie.startsWith('user=') ) { // success! we can expect subsequent actions to fix up the state return; } } this.props.dispatch({ type: resetUserStateActionType }); } hardwareBack = () => { if (this.nextMode !== 'prompt') { this.goBackToPrompt(); return true; } return false; }; panelPaddingTop() { const headerHeight = Platform.OS === 'ios' ? 62.33 : 58.54; const promptButtonsSize = Platform.OS === 'ios' ? 40 : 61; const logInContainerSize = 140; const registerPanelSize = Platform.OS === 'ios' ? 181 : 180; const containerSize = add( headerHeight, cond(not(isPastPrompt(this.modeValue)), promptButtonsSize, 0), cond(eq(this.modeValue, modeNumbers['log-in']), logInContainerSize, 0), cond(eq(this.modeValue, modeNumbers['register']), registerPanelSize, 0), ); const potentialPanelPaddingTop = divide( max(sub(this.contentHeight, this.keyboardHeightValue, containerSize), 0), 2, ); const panelPaddingTop = new Value(-1); const targetPanelPaddingTop = new Value(-1); const prevModeValue = new Value(modeNumbers[this.nextMode]); const clock = new Clock(); const keyboardTimeoutClock = new Clock(); return block([ cond(lessThan(panelPaddingTop, 0), [ set(panelPaddingTop, potentialPanelPaddingTop), set(targetPanelPaddingTop, potentialPanelPaddingTop), ]), cond( lessThan(this.keyboardHeightValue, 0), [ runTiming(keyboardTimeoutClock, 0, 1, true, { duration: 500 }), cond( not(clockRunning(keyboardTimeoutClock)), set(this.keyboardHeightValue, 0), ), ], stopClock(keyboardTimeoutClock), ), cond( and( greaterOrEq(this.keyboardHeightValue, 0), neq(prevModeValue, this.modeValue), ), [ stopClock(clock), cond( neq(isPastPrompt(prevModeValue), isPastPrompt(this.modeValue)), set(targetPanelPaddingTop, potentialPanelPaddingTop), ), set(prevModeValue, this.modeValue), ], ), ratchetAlongWithKeyboardHeight(this.keyboardHeightValue, [ stopClock(clock), set(targetPanelPaddingTop, potentialPanelPaddingTop), ]), cond( neq(panelPaddingTop, targetPanelPaddingTop), set( panelPaddingTop, runTiming(clock, panelPaddingTop, targetPanelPaddingTop), ), ), panelPaddingTop, ]); } panelOpacity() { const targetPanelOpacity = isPastPrompt(this.modeValue); const panelOpacity = new Value(-1); const prevPanelOpacity = new Value(-1); const prevTargetPanelOpacity = new Value(-1); const clock = new Clock(); return block([ cond(lessThan(panelOpacity, 0), [ set(panelOpacity, targetPanelOpacity), set(prevPanelOpacity, targetPanelOpacity), set(prevTargetPanelOpacity, targetPanelOpacity), ]), cond(greaterOrEq(this.keyboardHeightValue, 0), [ cond(neq(targetPanelOpacity, prevTargetPanelOpacity), [ stopClock(clock), set(prevTargetPanelOpacity, targetPanelOpacity), ]), cond( neq(panelOpacity, targetPanelOpacity), set(panelOpacity, runTiming(clock, panelOpacity, targetPanelOpacity)), ), ]), cond( and(eq(panelOpacity, 0), neq(prevPanelOpacity, 0)), call([], this.proceedToNextMode), ), set(prevPanelOpacity, panelOpacity), panelOpacity, ]); } keyboardShow = (event: KeyboardEvent) => { if ( event.startCoordinates && _isEqual(event.startCoordinates)(event.endCoordinates) ) { return; } const keyboardHeight = Platform.select({ // Android doesn't include the bottomInset in this height measurement android: event.endCoordinates.height, default: Math.max( event.endCoordinates.height - this.props.dimensions.bottomInset, 0, ), }); this.keyboardHeightValue.setValue(keyboardHeight); }; keyboardHide = () => { if (!this.activeAlert) { this.keyboardHeightValue.setValue(0); } }; setActiveAlert = (activeAlert: boolean) => { this.activeAlert = activeAlert; }; goBackToPrompt = () => { this.nextMode = 'prompt'; this.keyboardHeightValue.setValue(0); this.modeValue.setValue(modeNumbers['prompt']); Keyboard.dismiss(); }; render() { let panel = null; let buttons = null; let siweButton = null; if (__DEV__) { siweButton = ( SIWE ); } if (this.state.mode === 'siwe') { panel = ; } else if (this.state.mode === 'log-in') { panel = ( ); } else if (this.state.mode === 'register') { panel = ( ); } else if (this.state.mode === 'prompt') { const opacityStyle = { opacity: this.buttonOpacity }; buttons = ( {siweButton} LOG IN SIGN UP ); } else if (this.state.mode === 'loading') { panel = ( ); } const windowWidth = this.props.dimensions.width; const buttonStyle = { opacity: this.panelOpacityValue, left: windowWidth < 360 ? 28 : 40, }; const padding = { paddingTop: this.panelPaddingTopValue }; const animatedContent = ( Comm {panel} ); const backgroundSource = { uri: splashBackgroundURI }; return ( {animatedContent} {buttons} ); } onPressSIWE = () => { this.setMode('siwe'); }; onPressLogIn = () => { if (Platform.OS !== 'ios') { // For some strange reason, iOS's password management logic doesn't // realize that the username and password fields in LogInPanel are related // if the username field gets focused on mount. To avoid this issue we // need the username and password fields to both appear on-screen before // we focus the username field. However, when we set keyboardHeightValue // to -1 here, we are telling our Reanimated logic to wait until the // keyboard appears before showing LogInPanel. Since we need LogInPanel // to appear before the username field is focused, we need to avoid this // behavior on iOS. this.keyboardHeightValue.setValue(-1); } this.setMode('log-in'); }; onPressRegister = () => { this.keyboardHeightValue.setValue(-1); this.setMode('register'); }; } const styles = StyleSheet.create({ animationContainer: { flex: 1, }, backButton: { position: 'absolute', top: 13, }, button: { backgroundColor: '#FFFFFFAA', borderRadius: 6, marginBottom: 10, marginLeft: 40, marginRight: 40, marginTop: 10, paddingBottom: 6, paddingLeft: 18, paddingRight: 18, paddingTop: 6, }, buttonContainer: { bottom: 0, left: 0, paddingBottom: 20, position: 'absolute', right: 0, }, buttonText: { color: '#000000FF', fontFamily: 'OpenSans-Semibold', fontSize: 22, textAlign: 'center', }, container: { backgroundColor: 'transparent', flex: 1, }, header: { color: 'white', fontFamily: Platform.OS === 'ios' ? 'IBMPlexSans' : 'IBMPlexSans-Medium', fontSize: 56, fontWeight: '500', lineHeight: 66, textAlign: 'center', }, loadingIndicator: { paddingTop: 15, }, modalBackground: { bottom: 0, left: 0, position: 'absolute', right: 0, top: 0, }, }); const isForegroundSelector = createIsForegroundSelector( LoggedOutModalRouteName, ); const ConnectedLoggedOutModal: React.ComponentType<{ ... }> = React.memo<{ ... }>(function ConnectedLoggedOutModal(props: { ... }) { const navContext = React.useContext(NavContext); const isForeground = isForegroundSelector(navContext); const rehydrateConcluded = useSelector( state => !!(state._persist && state._persist.rehydrated && navContext), ); const persistedStateLoaded = usePersistedStateLoaded(); const cookie = useSelector(state => state.cookie); const urlPrefix = useSelector(state => state.urlPrefix); const loggedIn = useSelector(isLoggedIn); const dimensions = useSelector(derivedDimensionsInfoSelector); const splashStyle = useSelector(splashStyleSelector); const dispatch = useDispatch(); return ( ); }); export default ConnectedLoggedOutModal; diff --git a/native/account/panel-components.react.js b/native/account/panel-components.react.js index cad5e1f6f..2bb01a573 100644 --- a/native/account/panel-components.react.js +++ b/native/account/panel-components.react.js @@ -1,127 +1,127 @@ // @flow import * as React from 'react'; import { View, ActivityIndicator, Text, StyleSheet, ScrollView, } from 'react-native'; import Animated from 'react-native-reanimated'; -import Icon from 'react-native-vector-icons/FontAwesome'; +import Icon from '@expo/vector-icons/FontAwesome'; import type { LoadingStatus } from 'lib/types/loading-types'; import Button from '../components/button.react'; import { useSelector } from '../redux/redux-utils'; import type { ViewStyle } from '../types/styles'; type ButtonProps = { +text: string, +loadingStatus: LoadingStatus, +onSubmit: () => void, }; function PanelButton(props: ButtonProps): React.Node { let buttonIcon; if (props.loadingStatus === 'loading') { buttonIcon = ( ); } else { buttonIcon = ( ); } return ( ); } type PanelProps = { +opacityValue: Animated.Node, +children: React.Node, +style?: ViewStyle, }; function Panel(props: PanelProps): React.Node { const dimensions = useSelector(state => state.dimensions); const containerStyle = React.useMemo( () => [ styles.container, { opacity: props.opacityValue, marginTop: dimensions.height < 641 ? 15 : 40, }, props.style, ], [props.opacityValue, props.style, dimensions.height], ); return ( {props.children} ); } const styles = StyleSheet.create({ container: { backgroundColor: '#FFFFFFAA', borderRadius: 6, marginLeft: 20, marginRight: 20, paddingTop: 6, }, innerSubmitButton: { alignItems: 'flex-end', flexDirection: 'row', paddingVertical: 6, }, loadingIndicatorContainer: { paddingBottom: 2, width: 14, }, submitButton: { borderBottomRightRadius: 6, justifyContent: 'center', paddingLeft: 10, paddingRight: 18, }, submitButtonHorizontalContainer: { alignSelf: 'flex-end', }, submitButtonVerticalContainer: { flexGrow: 1, justifyContent: 'center', }, submitContentIconContainer: { paddingBottom: 5, width: 14, }, submitContentText: { color: '#555', fontFamily: 'OpenSans-Semibold', fontSize: 18, paddingRight: 7, }, }); export { PanelButton, Panel }; diff --git a/native/calendar/entry.react.js b/native/calendar/entry.react.js index df28480bd..f72f68c52 100644 --- a/native/calendar/entry.react.js +++ b/native/calendar/entry.react.js @@ -1,808 +1,808 @@ // @flow import invariant from 'invariant'; import _isEqual from 'lodash/fp/isEqual'; import _omit from 'lodash/fp/omit'; import * as React from 'react'; import { View, Text, TextInput as BaseTextInput, Platform, TouchableWithoutFeedback, Alert, LayoutAnimation, Keyboard, } from 'react-native'; -import Icon from 'react-native-vector-icons/FontAwesome'; +import Icon from '@expo/vector-icons/FontAwesome'; import { useDispatch } from 'react-redux'; import shallowequal from 'shallowequal'; import tinycolor from 'tinycolor2'; import { createEntryActionTypes, createEntry, saveEntryActionTypes, saveEntry, deleteEntryActionTypes, deleteEntry, concurrentModificationResetActionType, } from 'lib/actions/entry-actions'; import { registerFetchKey } from 'lib/reducers/loading-reducer'; import { entryKey } from 'lib/shared/entry-utils'; import { colorIsDark, threadHasPermission } from 'lib/shared/thread-utils'; import type { Shape } from 'lib/types/core'; import type { CreateEntryInfo, SaveEntryInfo, SaveEntryResult, SaveEntryPayload, CreateEntryPayload, DeleteEntryInfo, DeleteEntryResult, CalendarQuery, } from 'lib/types/entry-types'; import type { LoadingStatus } from 'lib/types/loading-types'; import type { Dispatch } from 'lib/types/redux-types'; import { type ThreadInfo, threadPermissions } from 'lib/types/thread-types'; import { useServerCall, useDispatchActionPromise, type DispatchActionPromise, } from 'lib/utils/action-utils'; import { dateString } from 'lib/utils/date-utils'; import { ServerError } from 'lib/utils/errors'; import sleep from 'lib/utils/sleep'; import { type MessageListParams, useNavigateToThread, } from '../chat/message-list-types'; import Button from '../components/button.react'; import { SingleLine } from '../components/single-line.react'; import TextInput from '../components/text-input.react'; import Markdown from '../markdown/markdown.react'; import { inlineMarkdownRules } from '../markdown/rules.react'; import { createIsForegroundSelector, nonThreadCalendarQuery, } from '../navigation/nav-selectors'; import { NavContext } from '../navigation/navigation-context'; import { ThreadPickerModalRouteName } from '../navigation/route-names'; import type { TabNavigationProp } from '../navigation/tab-navigator.react'; import { useSelector } from '../redux/redux-utils'; import { colors, useStyles } from '../themes/colors'; import type { LayoutEvent } from '../types/react-native'; import { waitForInteractions } from '../utils/timers'; import type { EntryInfoWithHeight } from './calendar.react'; import LoadingIndicator from './loading-indicator.react'; function hueDistance(firstColor: string, secondColor: string): number { const firstHue = tinycolor(firstColor).toHsv().h; const secondHue = tinycolor(secondColor).toHsv().h; const distance = Math.abs(firstHue - secondHue); return distance > 180 ? 360 - distance : distance; } const omitEntryInfo = _omit(['entryInfo']); function dummyNodeForEntryHeightMeasurement( entryText: string, ): React.Element { const text = entryText === '' ? ' ' : entryText; return ( {text} ); } type BaseProps = { +navigation: TabNavigationProp<'Calendar'>, +entryInfo: EntryInfoWithHeight, +threadInfo: ThreadInfo, +visible: boolean, +active: boolean, +makeActive: (entryKey: string, active: boolean) => void, +onEnterEditMode: (entryInfo: EntryInfoWithHeight) => void, +onConcludeEditMode: (entryInfo: EntryInfoWithHeight) => void, +onPressWhitespace: () => void, +entryRef: (entryKey: string, entry: ?InternalEntry) => void, }; type Props = { ...BaseProps, // Redux state +calendarQuery: () => CalendarQuery, +online: boolean, +styles: typeof unboundStyles, // Nav state +threadPickerActive: boolean, +navigateToThread: (params: MessageListParams) => void, // Redux dispatch functions +dispatch: Dispatch, +dispatchActionPromise: DispatchActionPromise, // async functions that hit server APIs +createEntry: (info: CreateEntryInfo) => Promise, +saveEntry: (info: SaveEntryInfo) => Promise, +deleteEntry: (info: DeleteEntryInfo) => Promise, }; type State = { +editing: boolean, +text: string, +loadingStatus: LoadingStatus, +height: number, }; class InternalEntry extends React.Component { textInput: ?React.ElementRef; creating: boolean = false; needsUpdateAfterCreation: boolean = false; needsDeleteAfterCreation: boolean = false; nextSaveAttemptIndex: number = 0; mounted: boolean = false; deleted: boolean = false; currentlySaving: ?string; constructor(props: Props) { super(props); this.state = { editing: false, text: props.entryInfo.text, loadingStatus: 'inactive', height: props.entryInfo.textHeight, }; this.state = { ...this.state, editing: InternalEntry.isActive(props, this.state), }; } guardedSetState(input: Shape) { if (this.mounted) { this.setState(input); } } shouldComponentUpdate(nextProps: Props, nextState: State): boolean { return ( !shallowequal(nextState, this.state) || !shallowequal(omitEntryInfo(nextProps), omitEntryInfo(this.props)) || !_isEqual(nextProps.entryInfo)(this.props.entryInfo) ); } componentDidUpdate(prevProps: Props, prevState: State) { const wasActive = InternalEntry.isActive(prevProps, prevState); const isActive = InternalEntry.isActive(this.props, this.state); if ( !isActive && (this.props.entryInfo.text !== prevProps.entryInfo.text || this.props.entryInfo.textHeight !== prevProps.entryInfo.textHeight) && (this.props.entryInfo.text !== this.state.text || this.props.entryInfo.textHeight !== this.state.height) ) { this.guardedSetState({ text: this.props.entryInfo.text, height: this.props.entryInfo.textHeight, }); this.currentlySaving = null; } if ( !this.props.active && this.state.text === prevState.text && this.state.height !== prevState.height && this.state.height !== this.props.entryInfo.textHeight ) { const approxMeasuredHeight = Math.round(this.state.height * 1000) / 1000; const approxExpectedHeight = Math.round(this.props.entryInfo.textHeight * 1000) / 1000; console.log( `Entry height for ${entryKey(this.props.entryInfo)} was expected to ` + `be ${approxExpectedHeight} but is actually ` + `${approxMeasuredHeight}. This means Calendar's FlatList isn't ` + 'getting the right item height for some of its nodes, which is ' + 'guaranteed to cause glitchy behavior. Please investigate!!', ); } // Our parent will set the active prop to false if something else gets // pressed or if the Entry is scrolled out of view. In either of those cases // we should complete the edit process. if (!this.props.active && prevProps.active) { this.completeEdit(); } if (this.state.height !== prevState.height || isActive !== wasActive) { LayoutAnimation.easeInEaseOut(); } if ( this.props.online && !prevProps.online && this.state.loadingStatus === 'error' ) { this.save(); } if ( this.state.editing && prevState.editing && (this.state.text.trim() === '') !== (prevState.text.trim() === '') ) { LayoutAnimation.easeInEaseOut(); } } componentDidMount() { this.mounted = true; this.props.entryRef(entryKey(this.props.entryInfo), this); } componentWillUnmount() { this.mounted = false; this.props.entryRef(entryKey(this.props.entryInfo), null); this.props.onConcludeEditMode(this.props.entryInfo); } static isActive(props: Props, state: State): boolean { return ( props.active || state.editing || !props.entryInfo.id || state.loadingStatus !== 'inactive' ); } render(): React.Node { const active = InternalEntry.isActive(this.props, this.state); const { editing } = this.state; const threadColor = `#${this.props.threadInfo.color}`; const darkColor = colorIsDark(this.props.threadInfo.color); let actionLinks = null; if (active) { const actionLinksColor = darkColor ? '#D3D3D3' : '#404040'; const actionLinksTextStyle = { color: actionLinksColor }; const { modalIosHighlightUnderlay: actionLinksUnderlayColor } = darkColor ? colors.dark : colors.light; const loadingIndicatorCanUseRed = hueDistance('red', threadColor) > 50; let editButtonContent = null; if (editing && this.state.text.trim() === '') { // nothing } else if (editing) { editButtonContent = ( SAVE ); } else { editButtonContent = ( EDIT ); } actionLinks = ( ); } const textColor = darkColor ? 'white' : 'black'; let textInput; if (editing) { const textInputStyle = { color: textColor, backgroundColor: threadColor, }; const selectionColor = darkColor ? '#129AFF' : '#036AFF'; textInput = ( ); } let rawText = this.state.text; if (rawText === '' || rawText.slice(-1) === '\n') { rawText += ' '; } const textStyle = { ...this.props.styles.text, color: textColor, opacity: textInput ? 0 : 1, }; // We use an empty View to set the height of the entry, and then position // the Text and TextInput absolutely. This allows to measure height changes // to the Text while controlling the actual height of the entry. const heightStyle = { height: this.state.height }; const entryStyle = { backgroundColor: threadColor }; const opacity = editing ? 1.0 : 0.6; const canEditEntry = threadHasPermission( this.props.threadInfo, threadPermissions.EDIT_ENTRIES, ); return ( ); } textInputRef: ( textInput: ?React.ElementRef, ) => void = textInput => { this.textInput = textInput; if (textInput && this.state.editing) { this.enterEditMode(); } }; enterEditMode: () => Promise = async () => { this.setActive(); this.props.onEnterEditMode(this.props.entryInfo); if (Platform.OS === 'android') { // If we don't do this, the TextInput focuses // but the soft keyboard doesn't come up await waitForInteractions(); await sleep(15); } this.focus(); }; focus: () => void = () => { const { textInput } = this; if (!textInput) { return; } textInput.focus(); }; onFocus: () => void = () => { if (this.props.threadPickerActive) { this.props.navigation.goBack(); } }; setActive: () => void = () => this.makeActive(true); completeEdit: () => void = () => { // This gets called from CalendarInputBar (save button above keyboard), // onPressEdit (save button in Entry action links), and in // componentDidUpdate above when Calendar sets this Entry to inactive. // Calendar does this if something else gets pressed or the Entry is // scrolled out of view. Note that an Entry won't consider itself inactive // until it's done updating the server with its state, and if the network // requests fail it may stay "active". if (this.textInput) { this.textInput.blur(); } this.onBlur(); }; onBlur: () => void = () => { if (this.state.text.trim() === '') { this.delete(); } else if (this.props.entryInfo.text !== this.state.text) { this.save(); } this.guardedSetState({ editing: false }); this.makeActive(false); this.props.onConcludeEditMode(this.props.entryInfo); }; save: () => void = () => { this.dispatchSave(this.props.entryInfo.id, this.state.text); }; onTextContainerLayout: (event: LayoutEvent) => void = event => { this.guardedSetState({ height: Math.ceil(event.nativeEvent.layout.height), }); }; onChangeText: (newText: string) => void = newText => { this.guardedSetState({ text: newText }); }; makeActive(active: boolean) { const { threadInfo } = this.props; if (!threadHasPermission(threadInfo, threadPermissions.EDIT_ENTRIES)) { return; } this.props.makeActive(entryKey(this.props.entryInfo), active); } dispatchSave(serverID: ?string, newText: string) { if (this.currentlySaving === newText) { return; } this.currentlySaving = newText; if (newText.trim() === '') { // We don't save the empty string, since as soon as the element becomes // inactive it'll get deleted return; } if (!serverID) { if (this.creating) { // We need the first save call to return so we know the ID of the entry // we're updating, so we'll need to handle this save later this.needsUpdateAfterCreation = true; return; } else { this.creating = true; } } this.guardedSetState({ loadingStatus: 'loading' }); if (!serverID) { this.props.dispatchActionPromise( createEntryActionTypes, this.createAction(newText), ); } else { this.props.dispatchActionPromise( saveEntryActionTypes, this.saveAction(serverID, newText), ); } } async createAction(text: string): Promise { const localID = this.props.entryInfo.localID; invariant(localID, "if there's no serverID, there should be a localID"); const curSaveAttempt = this.nextSaveAttemptIndex++; try { const response = await this.props.createEntry({ text, timestamp: this.props.entryInfo.creationTime, date: dateString( this.props.entryInfo.year, this.props.entryInfo.month, this.props.entryInfo.day, ), threadID: this.props.entryInfo.threadID, localID, calendarQuery: this.props.calendarQuery(), }); if (curSaveAttempt + 1 === this.nextSaveAttemptIndex) { this.guardedSetState({ loadingStatus: 'inactive' }); } this.creating = false; if (this.needsUpdateAfterCreation) { this.needsUpdateAfterCreation = false; this.dispatchSave(response.entryID, this.state.text); } if (this.needsDeleteAfterCreation) { this.needsDeleteAfterCreation = false; this.dispatchDelete(response.entryID); } return response; } catch (e) { if (curSaveAttempt + 1 === this.nextSaveAttemptIndex) { this.guardedSetState({ loadingStatus: 'error' }); } this.currentlySaving = null; this.creating = false; throw e; } } async saveAction( entryID: string, newText: string, ): Promise { const curSaveAttempt = this.nextSaveAttemptIndex++; try { const response = await this.props.saveEntry({ entryID, text: newText, prevText: this.props.entryInfo.text, timestamp: Date.now(), calendarQuery: this.props.calendarQuery(), }); if (curSaveAttempt + 1 === this.nextSaveAttemptIndex) { this.guardedSetState({ loadingStatus: 'inactive' }); } return { ...response, threadID: this.props.entryInfo.threadID }; } catch (e) { if (curSaveAttempt + 1 === this.nextSaveAttemptIndex) { this.guardedSetState({ loadingStatus: 'error' }); } this.currentlySaving = null; if (e instanceof ServerError && e.message === 'concurrent_modification') { const revertedText = e.payload?.db; const onRefresh = () => { this.guardedSetState({ loadingStatus: 'inactive', text: revertedText, }); this.props.dispatch({ type: concurrentModificationResetActionType, payload: { id: entryID, dbText: revertedText }, }); }; Alert.alert( 'Concurrent modification', 'It looks like somebody is attempting to modify that field at the ' + 'same time as you! Please try again.', [{ text: 'OK', onPress: onRefresh }], { cancelable: false }, ); } throw e; } } delete: () => void = () => { this.dispatchDelete(this.props.entryInfo.id); }; onPressEdit: () => void = () => { if (this.state.editing) { this.completeEdit(); } else { this.guardedSetState({ editing: true }); } }; dispatchDelete(serverID: ?string) { if (this.deleted) { return; } this.deleted = true; LayoutAnimation.easeInEaseOut(); const { localID } = this.props.entryInfo; this.props.dispatchActionPromise( deleteEntryActionTypes, this.deleteAction(serverID), undefined, { localID, serverID }, ); } async deleteAction(serverID: ?string): Promise { if (serverID) { return await this.props.deleteEntry({ entryID: serverID, prevText: this.props.entryInfo.text, calendarQuery: this.props.calendarQuery(), }); } else if (this.creating) { this.needsDeleteAfterCreation = true; } return null; } onPressThreadName: () => void = () => { Keyboard.dismiss(); this.props.navigateToThread({ threadInfo: this.props.threadInfo }); }; } const unboundStyles = { actionLinks: { flex: 1, flexDirection: 'row', justifyContent: 'space-between', marginTop: -5, }, button: { padding: 5, }, buttonContents: { flex: 1, flexDirection: 'row', }, container: { backgroundColor: 'listBackground', }, entry: { borderRadius: 8, margin: 5, overflow: 'hidden', }, leftLinks: { flex: 1, flexDirection: 'row', justifyContent: 'flex-start', paddingHorizontal: 5, }, leftLinksText: { fontSize: 12, fontWeight: 'bold', paddingLeft: 5, }, pencilIcon: { lineHeight: 13, paddingTop: 1, }, rightLinks: { flex: 1, flexDirection: 'row', justifyContent: 'flex-end', paddingHorizontal: 5, }, rightLinksText: { fontSize: 12, fontWeight: 'bold', }, text: { fontFamily: 'System', fontSize: 16, }, textContainer: { position: 'absolute', top: 0, paddingBottom: 6, paddingLeft: 10, paddingRight: 10, paddingTop: 5, transform: (Platform.select({ ios: [{ translateY: -1 / 3 }], default: [], }): $ReadOnlyArray<{ +translateY: number }>), }, textInput: { fontFamily: 'System', fontSize: 16, left: ((Platform.OS === 'android' ? 9.8 : 10): number), margin: 0, padding: 0, position: 'absolute', right: 10, top: ((Platform.OS === 'android' ? 4.8 : 0.5): number), }, }; registerFetchKey(saveEntryActionTypes); registerFetchKey(deleteEntryActionTypes); const activeThreadPickerSelector = createIsForegroundSelector( ThreadPickerModalRouteName, ); const Entry: React.ComponentType = React.memo( function ConnectedEntry(props: BaseProps) { const navContext = React.useContext(NavContext); const threadPickerActive = activeThreadPickerSelector(navContext); const calendarQuery = useSelector(state => nonThreadCalendarQuery({ redux: state, navContext, }), ); const online = useSelector( state => state.connection.status === 'connected', ); const styles = useStyles(unboundStyles); const navigateToThread = useNavigateToThread(); const dispatch = useDispatch(); const dispatchActionPromise = useDispatchActionPromise(); const callCreateEntry = useServerCall(createEntry); const callSaveEntry = useServerCall(saveEntry); const callDeleteEntry = useServerCall(deleteEntry); return ( ); }, ); export { InternalEntry, Entry, dummyNodeForEntryHeightMeasurement }; diff --git a/native/calendar/loading-indicator.react.js b/native/calendar/loading-indicator.react.js index 730588b3d..2ef5d65ca 100644 --- a/native/calendar/loading-indicator.react.js +++ b/native/calendar/loading-indicator.react.js @@ -1,34 +1,34 @@ // @flow import * as React from 'react'; import { ActivityIndicator, StyleSheet, Platform } from 'react-native'; -import Icon from 'react-native-vector-icons/Feather'; +import Icon from '@expo/vector-icons/Feather'; import type { LoadingStatus } from 'lib/types/loading-types'; type Props = { +loadingStatus: LoadingStatus, +color: string, +canUseRed: boolean, }; function LoadingIndicator(props: Props): React.Node { if (props.loadingStatus === 'error') { const colorStyle = props.canUseRed ? { color: 'red' } : { color: props.color }; return ; } else if (props.loadingStatus === 'loading') { return ; } else { return null; } } const styles = StyleSheet.create({ errorIcon: { fontSize: 16, paddingTop: Platform.OS === 'android' ? 6 : 4, }, }); export default LoadingIndicator; diff --git a/native/chat/chat-input-bar.react.js b/native/chat/chat-input-bar.react.js index bedb7af0e..c229e49d4 100644 --- a/native/chat/chat-input-bar.react.js +++ b/native/chat/chat-input-bar.react.js @@ -1,1002 +1,1002 @@ // @flow import invariant from 'invariant'; import _throttle from 'lodash/throttle'; import * as React from 'react'; import { View, TextInput, TouchableOpacity, Platform, Text, ActivityIndicator, TouchableWithoutFeedback, NativeAppEventEmitter, } from 'react-native'; import { TextInputKeyboardMangerIOS } from 'react-native-keyboard-input'; import Animated, { EasingNode } from 'react-native-reanimated'; -import Icon from 'react-native-vector-icons/Ionicons'; +import Icon from '@expo/vector-icons/Ionicons'; import { useDispatch } from 'react-redux'; import { moveDraftActionType, updateDraftActionType, } from 'lib/actions/draft-actions'; import { joinThreadActionTypes, joinThread, newThreadActionTypes, } from 'lib/actions/thread-actions'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors'; import { localIDPrefix, trimMessage } from 'lib/shared/message-utils'; import { threadHasPermission, viewerIsMember, threadFrozenDueToViewerBlock, threadActualMembers, checkIfDefaultMembersAreVoiced, draftKeyFromThreadID, colorIsDark, } from 'lib/shared/thread-utils'; import type { CalendarQuery } from 'lib/types/entry-types'; import type { LoadingStatus } from 'lib/types/loading-types'; import type { PhotoPaste } from 'lib/types/media-types'; import { messageTypes } from 'lib/types/message-types'; import type { Dispatch } from 'lib/types/redux-types'; import { type ThreadInfo, threadPermissions, type ClientThreadJoinRequest, type ThreadJoinPayload, } from 'lib/types/thread-types'; import { type UserInfos } from 'lib/types/user-types'; import { type DispatchActionPromise, useServerCall, useDispatchActionPromise, } from 'lib/utils/action-utils'; import Button from '../components/button.react'; import ClearableTextInput from '../components/clearable-text-input.react'; import SWMansionIcon from '../components/swmansion-icon.react'; import { type InputState, InputStateContext } from '../input/input-state'; import { getKeyboardHeight } from '../keyboard/keyboard'; import KeyboardInputHost from '../keyboard/keyboard-input-host.react'; import { type KeyboardState, KeyboardContext, } from '../keyboard/keyboard-state'; import { nonThreadCalendarQuery, activeThreadSelector, } from '../navigation/nav-selectors'; import { NavContext } from '../navigation/navigation-context'; import { type NavigationRoute, CameraModalRouteName, ImagePasteModalRouteName, } from '../navigation/route-names'; import { useSelector } from '../redux/redux-utils'; import { type Colors, useStyles, useColors } from '../themes/colors'; import type { LayoutEvent } from '../types/react-native'; import { type AnimatedViewStyle, AnimatedView } from '../types/styles'; import { runTiming } from '../utils/animation-utils'; import { ChatContext } from './chat-context'; import type { ChatNavigationProp } from './chat.react'; /* eslint-disable import/no-named-as-default-member */ const { Value, Clock, block, set, cond, neq, sub, interpolateNode, stopClock, } = Animated; /* eslint-enable import/no-named-as-default-member */ const expandoButtonsAnimationConfig = { duration: 150, easing: EasingNode.inOut(EasingNode.ease), }; const sendButtonAnimationConfig = { duration: 150, easing: EasingNode.inOut(EasingNode.ease), }; type BaseProps = { +threadInfo: ThreadInfo, }; type Props = { ...BaseProps, // Redux state +viewerID: ?string, +draft: string, +joinThreadLoadingStatus: LoadingStatus, +threadCreationInProgress: boolean, +calendarQuery: () => CalendarQuery, +nextLocalID: number, +userInfos: UserInfos, +colors: Colors, +styles: typeof unboundStyles, +onInputBarLayout?: (event: LayoutEvent) => mixed, +openCamera: () => mixed, // connectNav +isActive: boolean, // withKeyboardState +keyboardState: ?KeyboardState, // Redux dispatch functions +dispatch: Dispatch, +dispatchActionPromise: DispatchActionPromise, // async functions that hit server APIs +joinThread: (request: ClientThreadJoinRequest) => Promise, // withInputState +inputState: ?InputState, }; type State = { +text: string, +textEdited: boolean, +buttonsExpanded: boolean, }; class ChatInputBar extends React.PureComponent { textInput: ?React.ElementRef; clearableTextInput: ?ClearableTextInput; expandoButtonsOpen: Value; targetExpandoButtonsOpen: Value; expandoButtonsStyle: AnimatedViewStyle; cameraRollIconStyle: AnimatedViewStyle; cameraIconStyle: AnimatedViewStyle; expandIconStyle: AnimatedViewStyle; sendButtonContainerOpen: Value; targetSendButtonContainerOpen: Value; sendButtonContainerStyle: AnimatedViewStyle; constructor(props: Props) { super(props); this.state = { text: props.draft, textEdited: false, buttonsExpanded: true, }; this.setUpActionIconAnimations(); this.setUpSendIconAnimations(); } setUpActionIconAnimations() { this.expandoButtonsOpen = new Value(1); this.targetExpandoButtonsOpen = new Value(1); const prevTargetExpandoButtonsOpen = new Value(1); const expandoButtonClock = new Clock(); const expandoButtonsOpen = block([ cond(neq(this.targetExpandoButtonsOpen, prevTargetExpandoButtonsOpen), [ stopClock(expandoButtonClock), set(prevTargetExpandoButtonsOpen, this.targetExpandoButtonsOpen), ]), cond( neq(this.expandoButtonsOpen, this.targetExpandoButtonsOpen), set( this.expandoButtonsOpen, runTiming( expandoButtonClock, this.expandoButtonsOpen, this.targetExpandoButtonsOpen, true, expandoButtonsAnimationConfig, ), ), ), this.expandoButtonsOpen, ]); this.cameraRollIconStyle = { ...unboundStyles.cameraRollIcon, opacity: expandoButtonsOpen, }; this.cameraIconStyle = { ...unboundStyles.cameraIcon, opacity: expandoButtonsOpen, }; const expandoButtonsWidth = interpolateNode(expandoButtonsOpen, { inputRange: [0, 1], outputRange: [26, 66], }); this.expandoButtonsStyle = { ...unboundStyles.expandoButtons, width: expandoButtonsWidth, }; const expandOpacity = sub(1, expandoButtonsOpen); this.expandIconStyle = { ...unboundStyles.expandIcon, opacity: expandOpacity, }; } setUpSendIconAnimations() { const initialSendButtonContainerOpen = trimMessage(this.props.draft) ? 1 : 0; this.sendButtonContainerOpen = new Value(initialSendButtonContainerOpen); this.targetSendButtonContainerOpen = new Value( initialSendButtonContainerOpen, ); const prevTargetSendButtonContainerOpen = new Value( initialSendButtonContainerOpen, ); const sendButtonClock = new Clock(); const sendButtonContainerOpen = block([ cond( neq( this.targetSendButtonContainerOpen, prevTargetSendButtonContainerOpen, ), [ stopClock(sendButtonClock), set( prevTargetSendButtonContainerOpen, this.targetSendButtonContainerOpen, ), ], ), cond( neq(this.sendButtonContainerOpen, this.targetSendButtonContainerOpen), set( this.sendButtonContainerOpen, runTiming( sendButtonClock, this.sendButtonContainerOpen, this.targetSendButtonContainerOpen, true, sendButtonAnimationConfig, ), ), ), this.sendButtonContainerOpen, ]); const sendButtonContainerWidth = interpolateNode(sendButtonContainerOpen, { inputRange: [0, 1], outputRange: [4, 38], }); this.sendButtonContainerStyle = { width: sendButtonContainerWidth }; } static mediaGalleryOpen(props: Props) { const { keyboardState } = props; return !!(keyboardState && keyboardState.mediaGalleryOpen); } static systemKeyboardShowing(props: Props) { const { keyboardState } = props; return !!(keyboardState && keyboardState.systemKeyboardShowing); } get systemKeyboardShowing() { return ChatInputBar.systemKeyboardShowing(this.props); } immediatelyShowSendButton() { this.sendButtonContainerOpen.setValue(1); this.targetSendButtonContainerOpen.setValue(1); } updateSendButton(currentText: string) { if (this.shouldShowTextInput) { this.targetSendButtonContainerOpen.setValue(currentText === '' ? 0 : 1); } else { this.setUpSendIconAnimations(); } } componentDidMount() { if (this.props.isActive) { this.addReplyListener(); } } componentWillUnmount() { if (this.props.isActive) { this.removeReplyListener(); } } componentDidUpdate(prevProps: Props, prevState: State) { if ( this.state.textEdited && this.state.text && this.props.threadInfo.id !== prevProps.threadInfo.id ) { this.props.dispatch({ type: moveDraftActionType, payload: { oldKey: draftKeyFromThreadID(prevProps.threadInfo.id), newKey: draftKeyFromThreadID(this.props.threadInfo.id), }, }); } else if (!this.state.textEdited && this.props.draft !== prevProps.draft) { this.setState({ text: this.props.draft }); } if (this.props.isActive && !prevProps.isActive) { this.addReplyListener(); } else if (!this.props.isActive && prevProps.isActive) { this.removeReplyListener(); } const currentText = trimMessage(this.state.text); const prevText = trimMessage(prevState.text); if ( (currentText === '' && prevText !== '') || (currentText !== '' && prevText === '') ) { this.updateSendButton(currentText); } const systemKeyboardIsShowing = ChatInputBar.systemKeyboardShowing( this.props, ); const systemKeyboardWasShowing = ChatInputBar.systemKeyboardShowing( prevProps, ); if (systemKeyboardIsShowing && !systemKeyboardWasShowing) { this.hideButtons(); } else if (!systemKeyboardIsShowing && systemKeyboardWasShowing) { this.expandButtons(); } const imageGalleryIsOpen = ChatInputBar.mediaGalleryOpen(this.props); const imageGalleryWasOpen = ChatInputBar.mediaGalleryOpen(prevProps); if (!imageGalleryIsOpen && imageGalleryWasOpen) { this.hideButtons(); } else if (imageGalleryIsOpen && !imageGalleryWasOpen) { this.expandButtons(); this.setIOSKeyboardHeight(); } } addReplyListener() { invariant( this.props.inputState, 'inputState should be set in addReplyListener', ); this.props.inputState.addReplyListener(this.focusAndUpdateText); } removeReplyListener() { invariant( this.props.inputState, 'inputState should be set in removeReplyListener', ); this.props.inputState.removeReplyListener(this.focusAndUpdateText); } setIOSKeyboardHeight() { if (Platform.OS !== 'ios') { return; } const { textInput } = this; if (!textInput) { return; } const keyboardHeight = getKeyboardHeight(); if (keyboardHeight === null || keyboardHeight === undefined) { return; } TextInputKeyboardMangerIOS.setKeyboardHeight(textInput, keyboardHeight); } get shouldShowTextInput(): boolean { if (threadHasPermission(this.props.threadInfo, threadPermissions.VOICED)) { return true; } // If the thread is created by somebody else while the viewer is attempting // to create it, the threadInfo might be modified in-place // and won't list the viewer as a member, // which will end up hiding the input. // In this case, we will assume that our creation action // will get translated into a join, and as long // as members are voiced, we can show the input. if (!this.props.threadCreationInProgress) { return false; } return checkIfDefaultMembersAreVoiced(this.props.threadInfo); } render() { const isMember = viewerIsMember(this.props.threadInfo); const canJoin = threadHasPermission( this.props.threadInfo, threadPermissions.JOIN_THREAD, ); let joinButton = null; if (!isMember && canJoin && !this.props.threadCreationInProgress) { let buttonContent; if (this.props.joinThreadLoadingStatus === 'loading') { buttonContent = ( ); } else { const textStyle = colorIsDark(this.props.threadInfo.color) ? this.props.styles.joinButtonTextLight : this.props.styles.joinButtonTextDark; buttonContent = ( Join Chat ); } joinButton = ( ); } let content; const defaultMembersAreVoiced = checkIfDefaultMembersAreVoiced( this.props.threadInfo, ); if (this.shouldShowTextInput) { content = this.renderInput(); } else if ( threadFrozenDueToViewerBlock( this.props.threadInfo, this.props.viewerID, this.props.userInfos, ) && threadActualMembers(this.props.threadInfo.members).length === 2 ) { content = ( You can't send messages to a user that you've blocked. ); } else if (isMember) { content = ( You don't have permission to send messages. ); } else if (defaultMembersAreVoiced && canJoin) { content = null; } else { content = ( You don't have permission to send messages. ); } const keyboardInputHost = Platform.OS === 'android' ? null : ( ); return ( {joinButton} {content} {keyboardInputHost} ); } renderInput() { const expandoButton = ( ); const threadColor = `#${this.props.threadInfo.color}`; return ( {this.state.buttonsExpanded ? expandoButton : null} {this.state.buttonsExpanded ? null : expandoButton} ); } textInputRef = (textInput: ?React.ElementRef) => { this.textInput = textInput; }; clearableTextInputRef = (clearableTextInput: ?ClearableTextInput) => { this.clearableTextInput = clearableTextInput; }; updateText = (text: string) => { this.setState({ text, textEdited: true }); this.saveDraft(text); }; saveDraft = _throttle(text => { this.props.dispatch({ type: updateDraftActionType, payload: { key: draftKeyFromThreadID(this.props.threadInfo.id), text, }, }); }, 400); focusAndUpdateText = (text: string) => { const { textInput } = this; if (!textInput) { return; } const currentText = this.state.text; if (!currentText.startsWith(text)) { const prependedText = text.concat(currentText); this.updateText(prependedText); this.immediatelyShowSendButton(); this.immediatelyHideButtons(); } textInput.focus(); }; onSend = async () => { if (!trimMessage(this.state.text)) { return; } this.updateSendButton(''); const { clearableTextInput } = this; invariant( clearableTextInput, 'clearableTextInput should be sent in onSend', ); let text = await clearableTextInput.getValueAndReset(); text = trimMessage(text); if (!text) { return; } const localID = `${localIDPrefix}${this.props.nextLocalID}`; const creatorID = this.props.viewerID; invariant(creatorID, 'should have viewer ID in order to send a message'); invariant( this.props.inputState, 'inputState should be set in ChatInputBar.onSend', ); this.props.inputState.sendTextMessage( { type: messageTypes.TEXT, localID, threadID: this.props.threadInfo.id, text, creatorID, time: Date.now(), }, this.props.threadInfo, ); }; onPressJoin = () => { this.props.dispatchActionPromise(joinThreadActionTypes, this.joinAction()); }; async joinAction() { const query = this.props.calendarQuery(); return await this.props.joinThread({ threadID: this.props.threadInfo.id, calendarQuery: { startDate: query.startDate, endDate: query.endDate, filters: [ ...query.filters, { type: 'threads', threadIDs: [this.props.threadInfo.id] }, ], }, }); } expandButtons = () => { if (this.state.buttonsExpanded) { return; } this.targetExpandoButtonsOpen.setValue(1); this.setState({ buttonsExpanded: true }); }; hideButtons() { if ( ChatInputBar.mediaGalleryOpen(this.props) || !this.systemKeyboardShowing || !this.state.buttonsExpanded ) { return; } this.targetExpandoButtonsOpen.setValue(0); this.setState({ buttonsExpanded: false }); } immediatelyHideButtons() { this.expandoButtonsOpen.setValue(0); this.targetExpandoButtonsOpen.setValue(0); this.setState({ buttonsExpanded: false }); } showMediaGallery = () => { const { keyboardState } = this.props; invariant(keyboardState, 'keyboardState should be initialized'); keyboardState.showMediaGallery(this.props.threadInfo); }; dismissKeyboard = () => { const { keyboardState } = this.props; keyboardState && keyboardState.dismissKeyboard(); }; } const unboundStyles = { cameraIcon: { paddingBottom: Platform.OS === 'android' ? 11 : 8, paddingRight: 5, }, cameraRollIcon: { paddingBottom: Platform.OS === 'android' ? 11 : 8, paddingRight: 5, }, container: { backgroundColor: 'listBackground', paddingLeft: Platform.OS === 'android' ? 10 : 5, }, expandButton: { bottom: 0, position: 'absolute', right: 0, }, expandIcon: { paddingBottom: Platform.OS === 'android' ? 13 : 11, paddingRight: 2, }, expandoButtons: { alignSelf: 'flex-end', }, explanation: { color: 'listBackgroundSecondaryLabel', paddingBottom: 4, paddingTop: 1, textAlign: 'center', }, innerExpandoButtons: { alignItems: 'flex-end', alignSelf: 'flex-end', flexDirection: 'row', }, inputContainer: { flexDirection: 'row', }, joinButton: { borderRadius: 8, flex: 1, justifyContent: 'center', marginHorizontal: 12, marginVertical: 3, }, joinButtonContainer: { flexDirection: 'row', height: 48, marginBottom: 8, }, joinButtonContent: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', }, joinButtonTextLight: { color: 'white', fontSize: 20, marginHorizontal: 4, }, joinButtonTextDark: { color: 'black', fontSize: 20, marginHorizontal: 4, }, joinThreadLoadingIndicator: { paddingVertical: 2, }, sendButton: { position: 'absolute', bottom: 4, left: 0, }, sendIcon: { paddingLeft: 9, paddingRight: 8, paddingVertical: 6, }, textInput: { backgroundColor: 'listInputBackground', borderRadius: 12, color: 'listForegroundLabel', fontSize: 16, marginLeft: 4, marginRight: 4, marginTop: 6, marginBottom: 8, maxHeight: 250, paddingHorizontal: 10, paddingVertical: 5, }, }; const joinThreadLoadingStatusSelector = createLoadingStatusSelector( joinThreadActionTypes, ); const createThreadLoadingStatusSelector = createLoadingStatusSelector( newThreadActionTypes, ); type ConnectedChatInputBarBaseProps = { ...BaseProps, +onInputBarLayout?: (event: LayoutEvent) => mixed, +openCamera: () => mixed, }; function ConnectedChatInputBarBase(props: ConnectedChatInputBarBaseProps) { const navContext = React.useContext(NavContext); const keyboardState = React.useContext(KeyboardContext); const inputState = React.useContext(InputStateContext); const viewerID = useSelector( state => state.currentUserInfo && state.currentUserInfo.id, ); const draft = useSelector( state => state.draftStore.drafts[draftKeyFromThreadID(props.threadInfo.id)] ?? '', ); const joinThreadLoadingStatus = useSelector(joinThreadLoadingStatusSelector); const createThreadLoadingStatus = useSelector( createThreadLoadingStatusSelector, ); const threadCreationInProgress = createThreadLoadingStatus === 'loading'; const calendarQuery = useSelector(state => nonThreadCalendarQuery({ redux: state, navContext, }), ); const nextLocalID = useSelector(state => state.nextLocalID); const userInfos = useSelector(state => state.userStore.userInfos); const styles = useStyles(unboundStyles); const colors = useColors(); const isActive = React.useMemo( () => props.threadInfo.id === activeThreadSelector(navContext), [props.threadInfo.id, navContext], ); const dispatch = useDispatch(); const dispatchActionPromise = useDispatchActionPromise(); const callJoinThread = useServerCall(joinThread); return ( ); } type DummyChatInputBarProps = { ...BaseProps, +onHeightMeasured: (height: number) => mixed, }; const noop = () => {}; function DummyChatInputBar(props: DummyChatInputBarProps): React.Node { const { onHeightMeasured, ...restProps } = props; const onInputBarLayout = React.useCallback( (event: LayoutEvent) => { const { height } = event.nativeEvent.layout; onHeightMeasured(height); }, [onHeightMeasured], ); return ( ); } type ChatInputBarProps = { ...BaseProps, +navigation: ChatNavigationProp<'MessageList'>, +route: NavigationRoute<'MessageList'>, }; const ConnectedChatInputBar: React.ComponentType = React.memo( function ConnectedChatInputBar(props: ChatInputBarProps) { const { navigation, route, ...restProps } = props; const keyboardState = React.useContext(KeyboardContext); const { threadInfo } = props; const imagePastedCallback = React.useCallback( imagePastedEvent => { if (threadInfo.id !== imagePastedEvent.threadID) { return; } const pastedImage: PhotoPaste = { step: 'photo_paste', dimensions: { height: imagePastedEvent.height, width: imagePastedEvent.width, }, filename: imagePastedEvent.fileName, uri: 'file://' + imagePastedEvent.filePath, selectTime: 0, sendTime: 0, retries: 0, }; navigation.navigate<'ImagePasteModal'>({ name: ImagePasteModalRouteName, params: { imagePasteStagingInfo: pastedImage, thread: threadInfo, }, }); }, [navigation, threadInfo], ); React.useEffect(() => { const imagePasteListener = NativeAppEventEmitter.addListener( 'imagePasted', imagePastedCallback, ); return () => imagePasteListener.remove(); }, [imagePastedCallback]); const chatContext = React.useContext(ChatContext); invariant(chatContext, 'should be set'); const { setChatInputBarHeight, deleteChatInputBarHeight } = chatContext; const onInputBarLayout = React.useCallback( (event: LayoutEvent) => { const { height } = event.nativeEvent.layout; setChatInputBarHeight(threadInfo.id, height); }, [threadInfo.id, setChatInputBarHeight], ); React.useEffect(() => { return () => { deleteChatInputBarHeight(threadInfo.id); }; }, [deleteChatInputBarHeight, threadInfo.id]); const openCamera = React.useCallback(() => { keyboardState?.dismissKeyboard(); navigation.navigate<'CameraModal'>({ name: CameraModalRouteName, params: { presentedFrom: route.key, thread: threadInfo, }, }); }, [keyboardState, navigation, route.key, threadInfo]); return ( ); }, ); export { ConnectedChatInputBar as ChatInputBar, DummyChatInputBar }; diff --git a/native/chat/chat-thread-list-see-more-sidebars.react.js b/native/chat/chat-thread-list-see-more-sidebars.react.js index 59735364a..7c1900e47 100644 --- a/native/chat/chat-thread-list-see-more-sidebars.react.js +++ b/native/chat/chat-thread-list-see-more-sidebars.react.js @@ -1,70 +1,70 @@ // @flow import * as React from 'react'; import { Text } from 'react-native'; -import Icon from 'react-native-vector-icons/Ionicons'; +import Icon from '@expo/vector-icons/Ionicons'; import type { ThreadInfo } from 'lib/types/thread-types'; import Button from '../components/button.react'; import { useColors, useStyles } from '../themes/colors'; import { sidebarHeight } from './sidebar-item.react'; type Props = { +threadInfo: ThreadInfo, +unread: boolean, +onPress: (threadInfo: ThreadInfo) => void, }; function ChatThreadListSeeMoreSidebars(props: Props): React.Node { const { onPress, threadInfo, unread } = props; const onPressButton = React.useCallback(() => onPress(threadInfo), [ onPress, threadInfo, ]); const colors = useColors(); const styles = useStyles(unboundStyles); const unreadStyle = unread ? styles.unread : null; return ( ); } const unboundStyles = { unread: { color: 'listForegroundLabel', fontWeight: 'bold', }, button: { height: sidebarHeight, flexDirection: 'row', display: 'flex', paddingLeft: 28, paddingRight: 18, alignItems: 'center', backgroundColor: 'listBackground', }, icon: { paddingLeft: 5, color: 'listForegroundSecondaryLabel', width: 35, }, text: { color: 'listForegroundSecondaryLabel', flex: 1, fontSize: 16, paddingLeft: 3, paddingBottom: 2, }, }; export default ChatThreadListSeeMoreSidebars; diff --git a/native/chat/chat-thread-list.react.js b/native/chat/chat-thread-list.react.js index 9dd692284..92bba122b 100644 --- a/native/chat/chat-thread-list.react.js +++ b/native/chat/chat-thread-list.react.js @@ -1,647 +1,647 @@ // @flow import invariant from 'invariant'; import _sum from 'lodash/fp/sum'; import * as React from 'react'; import { View, FlatList, Platform, TextInput, TouchableWithoutFeedback, BackHandler, } from 'react-native'; import { FloatingAction } from 'react-native-floating-action'; import Animated from 'react-native-reanimated'; -import IonIcon from 'react-native-vector-icons/Ionicons'; +import IonIcon from '@expo/vector-icons/Ionicons'; import { createSelector } from 'reselect'; import { searchUsers } from 'lib/actions/user-actions'; import { type ChatThreadItem, useFlattenedChatListData, } from 'lib/selectors/chat-selectors'; import { threadSearchIndex as threadSearchIndexSelector } from 'lib/selectors/nav-selectors'; import { usersWithPersonalThreadSelector } from 'lib/selectors/user-selectors'; import SearchIndex from 'lib/shared/search-index'; import { createPendingThread, getThreadListSearchResults, } from 'lib/shared/thread-utils'; import type { UserSearchResult } from 'lib/types/search-types'; import type { ThreadInfo } from 'lib/types/thread-types'; import { threadTypes } from 'lib/types/thread-types'; import type { GlobalAccountUserInfo, UserInfo } from 'lib/types/user-types'; import { useServerCall } from 'lib/utils/action-utils'; import Button from '../components/button.react'; import Search from '../components/search.react'; import { SidebarListModalRouteName, HomeChatThreadListRouteName, BackgroundChatThreadListRouteName, type NavigationRoute, } from '../navigation/route-names'; import type { TabNavigationProp } from '../navigation/tab-navigator.react'; import { useSelector } from '../redux/redux-utils'; import { type IndicatorStyle, indicatorStyleSelector, useStyles, } from '../themes/colors'; import type { ScrollEvent } from '../types/react-native'; import { AnimatedView, type AnimatedStyleObj } from '../types/styles'; import { animateTowards } from '../utils/animation-utils'; import { ChatThreadListItem, chatThreadListItemHeight, spacerHeight, } from './chat-thread-list-item.react'; import type { ChatTopTabsNavigationProp, ChatNavigationProp, } from './chat.react'; import { type MessageListParams, useNavigateToThread, } from './message-list-types'; import { sidebarHeight } from './sidebar-item.react'; const floatingActions = [ { text: 'Compose', icon: , name: 'compose', position: 1, }, ]; /* eslint-disable import/no-named-as-default-member */ const { Value, Node, interpolateNode } = Animated; /* eslint-enable import/no-named-as-default-member */ type Item = | ChatThreadItem | { +type: 'search', +searchText: string } | { +type: 'empty', +emptyItem: React.ComponentType<{}> }; type BaseProps = { +navigation: | ChatTopTabsNavigationProp<'HomeChatThreadList'> | ChatTopTabsNavigationProp<'BackgroundChatThreadList'>, +route: | NavigationRoute<'HomeChatThreadList'> | NavigationRoute<'BackgroundChatThreadList'>, +filterThreads: (threadItem: ThreadInfo) => boolean, +emptyItem?: React.ComponentType<{}>, }; type Props = { ...BaseProps, // Redux state +chatListData: $ReadOnlyArray, +viewerID: ?string, +threadSearchIndex: SearchIndex, +styles: typeof unboundStyles, +indicatorStyle: IndicatorStyle, +usersWithPersonalThread: $ReadOnlySet, +navigateToThread: (params: MessageListParams) => void, // async functions that hit server APIs +searchUsers: (usernamePrefix: string) => Promise, }; type SearchStatus = 'inactive' | 'activating' | 'active'; type State = { +searchStatus: SearchStatus, +searchText: string, +threadsSearchResults: Set, +usersSearchResults: $ReadOnlyArray, +openedSwipeableId: string, +numItemsToDisplay: number, }; type PropsAndState = { ...Props, ...State }; class ChatThreadList extends React.PureComponent { state: State = { searchStatus: 'inactive', searchText: '', threadsSearchResults: new Set(), usersSearchResults: [], openedSwipeableId: '', numItemsToDisplay: 25, }; searchInput: ?React.ElementRef; flatList: ?FlatList; scrollPos = 0; clearNavigationBlurListener: ?() => mixed; searchCancelButtonOpen: Value = new Value(0); searchCancelButtonProgress: Node; searchCancelButtonOffset: Node; constructor(props: Props) { super(props); this.searchCancelButtonProgress = animateTowards( this.searchCancelButtonOpen, 100, ); this.searchCancelButtonOffset = interpolateNode( this.searchCancelButtonProgress, { inputRange: [0, 1], outputRange: [0, 56] }, ); } componentDidMount() { this.clearNavigationBlurListener = this.props.navigation.addListener( 'blur', () => { this.setState({ numItemsToDisplay: 25 }); }, ); const chatNavigation: ?ChatNavigationProp< 'ChatThreadList', > = this.props.navigation.getParent(); invariant(chatNavigation, 'ChatNavigator should be within TabNavigator'); const tabNavigation: ?TabNavigationProp< 'Chat', > = chatNavigation.getParent(); invariant(tabNavigation, 'ChatNavigator should be within TabNavigator'); tabNavigation.addListener('tabPress', this.onTabPress); BackHandler.addEventListener('hardwareBackPress', this.hardwareBack); } componentWillUnmount() { this.clearNavigationBlurListener && this.clearNavigationBlurListener(); const chatNavigation: ?ChatNavigationProp< 'ChatThreadList', > = this.props.navigation.getParent(); invariant(chatNavigation, 'ChatNavigator should be within TabNavigator'); const tabNavigation: ?TabNavigationProp< 'Chat', > = chatNavigation.getParent(); invariant(tabNavigation, 'ChatNavigator should be within TabNavigator'); tabNavigation.removeListener('tabPress', this.onTabPress); BackHandler.removeEventListener('hardwareBackPress', this.hardwareBack); } hardwareBack = () => { if (!this.props.navigation.isFocused()) { return false; } const { searchStatus } = this.state; const isActiveOrActivating = searchStatus === 'active' || searchStatus === 'activating'; if (!isActiveOrActivating) { return false; } this.onSearchCancel(); return true; }; componentDidUpdate(prevProps: Props, prevState: State) { const { searchStatus } = this.state; const prevSearchStatus = prevState.searchStatus; const isActiveOrActivating = searchStatus === 'active' || searchStatus === 'activating'; const wasActiveOrActivating = prevSearchStatus === 'active' || prevSearchStatus === 'activating'; if (isActiveOrActivating && !wasActiveOrActivating) { this.searchCancelButtonOpen.setValue(1); } else if (!isActiveOrActivating && wasActiveOrActivating) { this.searchCancelButtonOpen.setValue(0); } const { flatList } = this; if (!flatList) { return; } if (this.state.searchText !== prevState.searchText) { flatList.scrollToOffset({ offset: 0, animated: false }); return; } if (searchStatus === 'activating' && prevSearchStatus === 'inactive') { flatList.scrollToOffset({ offset: 0, animated: true }); } } onTabPress = () => { if (!this.props.navigation.isFocused()) { return; } if (this.scrollPos > 0 && this.flatList) { this.flatList.scrollToOffset({ offset: 0, animated: true }); } else if (this.props.route.name === BackgroundChatThreadListRouteName) { this.props.navigation.navigate({ name: HomeChatThreadListRouteName }); } }; onSearchFocus = () => { if (this.state.searchStatus !== 'inactive') { return; } if (this.scrollPos === 0) { this.setState({ searchStatus: 'active' }); } else { this.setState({ searchStatus: 'activating' }); } }; clearSearch() { const { flatList } = this; flatList && flatList.scrollToOffset({ offset: 0, animated: false }); this.setState({ searchStatus: 'inactive' }); } onSearchBlur = () => { if (this.state.searchStatus !== 'active') { return; } this.clearSearch(); }; onSearchCancel = () => { this.onChangeSearchText(''); this.clearSearch(); }; renderSearch(additionalProps?: $Shape>) { const animatedSearchBoxStyle: AnimatedStyleObj = { marginRight: this.searchCancelButtonOffset, }; const searchBoxStyle = [ this.props.styles.searchBox, animatedSearchBoxStyle, ]; const buttonStyle = [ this.props.styles.cancelSearchButtonText, { opacity: this.searchCancelButtonProgress }, ]; return ( ); } searchInputRef = (searchInput: ?React.ElementRef) => { this.searchInput = searchInput; }; renderItem = (row: { item: Item, ... }) => { const item = row.item; if (item.type === 'search') { return ( {this.renderSearch({ active: false })} ); } if (item.type === 'empty') { const EmptyItem = item.emptyItem; return ; } return ( ); }; static keyExtractor = (item: Item) => { if (item.type === 'chatThreadItem') { return item.threadInfo.id; } else if (item.type === 'empty') { return 'empty'; } else { return 'search'; } }; static getItemLayout = (data: ?$ReadOnlyArray, index: number) => { if (!data) { return { length: 0, offset: 0, index }; } const offset = ChatThreadList.heightOfItems( data.filter((_, i) => i < index), ); const item = data[index]; const length = item ? ChatThreadList.itemHeight(item) : 0; return { length, offset, index }; }; static itemHeight = (item: Item) => { if (item.type === 'search') { return Platform.OS === 'ios' ? 54.5 : 55; } // itemHeight for emptyItem might be wrong because of line wrapping // but we don't care because we'll only ever be rendering this item // by itself and it should always be on-screen if (item.type === 'empty') { return 123; } let height = chatThreadListItemHeight; height += item.sidebars.length * sidebarHeight; if (item.sidebars.length > 0) { height += spacerHeight; } return height; }; static heightOfItems(data: $ReadOnlyArray): number { return _sum(data.map(ChatThreadList.itemHeight)); } listDataSelector = createSelector( (propsAndState: PropsAndState) => propsAndState.chatListData, (propsAndState: PropsAndState) => propsAndState.searchStatus, (propsAndState: PropsAndState) => propsAndState.searchText, (propsAndState: PropsAndState) => propsAndState.threadsSearchResults, (propsAndState: PropsAndState) => propsAndState.emptyItem, (propsAndState: PropsAndState) => propsAndState.usersSearchResults, (propsAndState: PropsAndState) => propsAndState.filterThreads, (propsAndState: PropsAndState) => propsAndState.viewerID, ( reduxChatListData: $ReadOnlyArray, searchStatus: SearchStatus, searchText: string, threadsSearchResults: Set, emptyItem?: React.ComponentType<{}>, usersSearchResults: $ReadOnlyArray, filterThreads: ThreadInfo => boolean, viewerID: ?string, ): $ReadOnlyArray => { const chatThreadItems = getThreadListSearchResults( reduxChatListData, searchText, filterThreads, threadsSearchResults, usersSearchResults, viewerID, ); const chatItems: Item[] = [...chatThreadItems]; if (emptyItem && chatItems.length === 0) { chatItems.push({ type: 'empty', emptyItem }); } if (searchStatus === 'inactive' || searchStatus === 'activating') { chatItems.unshift({ type: 'search', searchText }); } return chatItems; }, ); partialListDataSelector = createSelector( this.listDataSelector, (propsAndState: PropsAndState) => propsAndState.numItemsToDisplay, (items: $ReadOnlyArray, numItemsToDisplay: number) => items.slice(0, numItemsToDisplay), ); get fullListData() { return this.listDataSelector({ ...this.props, ...this.state }); } get listData() { return this.partialListDataSelector({ ...this.props, ...this.state }); } onEndReached = () => { if (this.listData.length === this.fullListData.length) { return; } this.setState(prevState => ({ numItemsToDisplay: prevState.numItemsToDisplay + 25, })); }; render() { let floatingAction; if (Platform.OS === 'android') { floatingAction = ( ); } let fixedSearch; const { searchStatus } = this.state; if (searchStatus === 'active') { fixedSearch = this.renderSearch({ autoFocus: true }); } const scrollEnabled = searchStatus === 'inactive' || searchStatus === 'active'; // this.props.viewerID is in extraData since it's used by MessagePreview // within ChatThreadListItem return ( {fixedSearch} {floatingAction} ); } flatListRef = (flatList: ?FlatList) => { this.flatList = flatList; }; onScroll = (event: ScrollEvent) => { const oldScrollPos = this.scrollPos; this.scrollPos = event.nativeEvent.contentOffset.y; if (this.scrollPos !== 0 || oldScrollPos === 0) { return; } if (this.state.searchStatus === 'activating') { this.setState({ searchStatus: 'active' }); } }; async searchUsers(usernamePrefix: string) { if (usernamePrefix.length === 0) { return []; } const { userInfos } = await this.props.searchUsers(usernamePrefix); return userInfos.filter( info => !this.props.usersWithPersonalThread.has(info.id) && info.id !== this.props.viewerID, ); } onChangeSearchText = async (searchText: string) => { const results = this.props.threadSearchIndex.getSearchResults(searchText); this.setState({ searchText, threadsSearchResults: new Set(results), numItemsToDisplay: 25, }); const usersSearchResults = await this.searchUsers(searchText); this.setState({ usersSearchResults }); }; onPressItem = ( threadInfo: ThreadInfo, pendingPersonalThreadUserInfo?: UserInfo, ) => { this.onChangeSearchText(''); if (this.searchInput) { this.searchInput.blur(); } this.props.navigateToThread({ threadInfo, pendingPersonalThreadUserInfo }); }; onPressSeeMoreSidebars = (threadInfo: ThreadInfo) => { this.onChangeSearchText(''); if (this.searchInput) { this.searchInput.blur(); } this.props.navigation.navigate<'SidebarListModal'>({ name: SidebarListModalRouteName, params: { threadInfo }, }); }; onSwipeableWillOpen = (threadInfo: ThreadInfo) => { this.setState(state => ({ ...state, openedSwipeableId: threadInfo.id })); }; composeThread = () => { if (!this.props.viewerID) { return; } const threadInfo = createPendingThread({ viewerID: this.props.viewerID, threadType: threadTypes.PRIVATE, }); this.props.navigateToThread({ threadInfo, searching: true }); }; } const unboundStyles = { icon: { fontSize: 28, }, container: { flex: 1, }, searchContainer: { backgroundColor: 'listBackground', display: 'flex', justifyContent: 'center', flexDirection: 'row', }, searchBox: { flex: 1, }, search: { marginBottom: 8, marginHorizontal: 18, marginTop: 16, }, cancelSearchButton: { position: 'absolute', right: 0, top: 0, bottom: 0, display: 'flex', justifyContent: 'center', }, cancelSearchButtonText: { color: 'link', fontSize: 16, paddingHorizontal: 16, paddingTop: 8, }, flatList: { flex: 1, backgroundColor: 'listBackground', }, }; const ConnectedChatThreadList: React.ComponentType = React.memo( function ConnectedChatThreadList(props: BaseProps) { const boundChatListData = useFlattenedChatListData(); const viewerID = useSelector( state => state.currentUserInfo && state.currentUserInfo.id, ); const threadSearchIndex = useSelector(threadSearchIndexSelector); const styles = useStyles(unboundStyles); const indicatorStyle = useSelector(indicatorStyleSelector); const callSearchUsers = useServerCall(searchUsers); const usersWithPersonalThread = useSelector( usersWithPersonalThreadSelector, ); const navigateToThread = useNavigateToThread(); return ( ); }, ); export default ConnectedChatThreadList; diff --git a/native/chat/composed-message.react.js b/native/chat/composed-message.react.js index bc452c7af..2167656d2 100644 --- a/native/chat/composed-message.react.js +++ b/native/chat/composed-message.react.js @@ -1,244 +1,244 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; import { StyleSheet, View } from 'react-native'; import Animated from 'react-native-reanimated'; -import Icon from 'react-native-vector-icons/Feather'; +import Icon from '@expo/vector-icons/Feather'; import { createMessageReply } from 'lib/shared/message-utils'; import { assertComposableMessageType } from 'lib/types/message-types'; import { type InputState, InputStateContext } from '../input/input-state'; import { type Colors, useColors } from '../themes/colors'; import type { ChatMessageInfoItemWithHeight } from '../types/chat-types'; import { type AnimatedStyleObj, AnimatedView } from '../types/styles'; import { clusterEndHeight, inlineSidebarStyle, inlineSidebarLeftStyle, inlineSidebarRightStyle, composedMessageStyle, } from './chat-constants'; import { useComposedMessageMaxWidth } from './composed-message-width'; import { FailedSend } from './failed-send.react'; import { InlineSidebar } from './inline-sidebar.react'; import { MessageHeader } from './message-header.react'; import { useNavigateToSidebar } from './sidebar-navigation'; import SwipeableMessage from './swipeable-message.react'; import { useContentAndHeaderOpacity, useDeliveryIconOpacity } from './utils'; /* eslint-disable import/no-named-as-default-member */ const { Node } = Animated; /* eslint-enable import/no-named-as-default-member */ type SwipeOptions = 'reply' | 'sidebar' | 'both' | 'none'; type BaseProps = { ...React.ElementConfig, +item: ChatMessageInfoItemWithHeight, +sendFailed: boolean, +focused: boolean, +swipeOptions: SwipeOptions, +children: React.Node, }; type Props = { ...BaseProps, // Redux state +composedMessageMaxWidth: number, +colors: Colors, +contentAndHeaderOpacity: number | Node, +deliveryIconOpacity: number | Node, // withInputState +inputState: ?InputState, +navigateToSidebar: () => void, }; class ComposedMessage extends React.PureComponent { render() { assertComposableMessageType(this.props.item.messageInfo.type); const { item, sendFailed, focused, swipeOptions, children, composedMessageMaxWidth, colors, inputState, navigateToSidebar, contentAndHeaderOpacity, deliveryIconOpacity, ...viewProps } = this.props; const { id, creator } = item.messageInfo; const { isViewer } = creator; const alignStyle = isViewer ? styles.rightChatBubble : styles.leftChatBubble; let containerMarginBottom = 5; if (item.endsCluster) { containerMarginBottom += clusterEndHeight; } const containerStyle = [ styles.alignment, { marginBottom: containerMarginBottom }, ]; const messageBoxStyle = { maxWidth: composedMessageMaxWidth }; let deliveryIcon = null; let failedSendInfo = null; if (isViewer) { let deliveryIconName; let deliveryIconColor = `#${item.threadInfo.color}`; if (id !== null && id !== undefined) { deliveryIconName = 'check-circle'; } else if (sendFailed) { deliveryIconName = 'x-circle'; deliveryIconColor = colors.redText; failedSendInfo = ; } else { deliveryIconName = 'circle'; } const animatedStyle: AnimatedStyleObj = { opacity: deliveryIconOpacity }; deliveryIcon = ( ); } const triggerReply = swipeOptions === 'reply' || swipeOptions === 'both' ? this.reply : undefined; const triggerSidebar = swipeOptions === 'sidebar' || swipeOptions === 'both' ? navigateToSidebar : undefined; const messageBox = ( {children} ); let inlineSidebar = null; if (item.threadCreatedFromMessage) { const positioning = isViewer ? 'right' : 'left'; const inlineSidebarPositionStyle = positioning === 'left' ? styles.leftInlineSidebar : styles.rightInlineSidebar; inlineSidebar = ( ); } return ( {deliveryIcon} {messageBox} {failedSendInfo} {inlineSidebar} ); } reply = () => { const { inputState, item } = this.props; invariant(inputState, 'inputState should be set in reply'); invariant(item.messageInfo.text, 'text should be set in reply'); inputState.addReply(createMessageReply(item.messageInfo.text)); }; } const styles = StyleSheet.create({ alignment: { marginLeft: composedMessageStyle.marginLeft, marginRight: composedMessageStyle.marginRight, }, content: { alignItems: 'center', flexDirection: 'row-reverse', }, icon: { fontSize: 16, textAlign: 'center', }, iconContainer: { marginLeft: 2, width: 16, }, inlineSidebar: { marginBottom: inlineSidebarStyle.marginBottom, marginTop: inlineSidebarStyle.marginTop, }, leftChatBubble: { justifyContent: 'flex-end', }, leftInlineSidebar: { justifyContent: 'flex-start', position: 'relative', top: inlineSidebarLeftStyle.topOffset, }, messageBox: { marginRight: 5, }, rightChatBubble: { justifyContent: 'flex-start', }, rightInlineSidebar: { alignSelf: 'flex-end', position: 'relative', right: inlineSidebarRightStyle.marginRight, top: inlineSidebarRightStyle.topOffset, }, }); const ConnectedComposedMessage: React.ComponentType = React.memo( function ConnectedComposedMessage(props: BaseProps) { const composedMessageMaxWidth = useComposedMessageMaxWidth(); const colors = useColors(); const inputState = React.useContext(InputStateContext); const navigateToSidebar = useNavigateToSidebar(props.item); const contentAndHeaderOpacity = useContentAndHeaderOpacity(props.item); const deliveryIconOpacity = useDeliveryIconOpacity(props.item); return ( ); }, ); export default ConnectedComposedMessage; diff --git a/native/chat/inline-multimedia.react.js b/native/chat/inline-multimedia.react.js index 306fca568..d4370d309 100644 --- a/native/chat/inline-multimedia.react.js +++ b/native/chat/inline-multimedia.react.js @@ -1,149 +1,149 @@ // @flow import * as React from 'react'; import { View, StyleSheet, Text } from 'react-native'; import * as Progress from 'react-native-progress'; -import Icon from 'react-native-vector-icons/Feather'; -import IonIcon from 'react-native-vector-icons/Ionicons'; +import Icon from '@expo/vector-icons/Feather'; +import IonIcon from '@expo/vector-icons/Ionicons'; import tinycolor from 'tinycolor2'; import { isLocalUploadID } from 'lib/media/media-utils'; import type { MediaInfo } from 'lib/types/media-types'; import GestureTouchableOpacity from '../components/gesture-touchable-opacity.react'; import type { PendingMultimediaUpload } from '../input/input-state'; import Multimedia from '../media/multimedia.react'; type Props = { +mediaInfo: MediaInfo, +onPress: () => void, +postInProgress: boolean, +pendingUpload: ?PendingMultimediaUpload, +spinnerColor: string, }; function InlineMultimedia(props: Props): React.Node { const { mediaInfo, pendingUpload, postInProgress } = props; let failed = isLocalUploadID(mediaInfo.id) && !postInProgress; let progressPercent = 1; let processingStep; if (pendingUpload) { ({ progressPercent, failed, processingStep } = pendingUpload); } let progressIndicator; if (failed) { progressIndicator = ( ); } else if (progressPercent !== 1) { const progressOverlay = ( {`${Math.floor(progressPercent * 100).toString()}%`} {processingStep ? processingStep : 'pending'} ); const primaryColor = tinycolor(props.spinnerColor); const secondaryColor = primaryColor.isDark() ? primaryColor.lighten(20).toString() : primaryColor.darken(20).toString(); const progressSpinnerProps = { size: 120, indeterminate: progressPercent === 0, progress: progressPercent, fill: secondaryColor, unfilledColor: secondaryColor, color: props.spinnerColor, thickness: 10, borderWidth: 0, }; let progressSpinner; if (processingStep === 'transcoding') { progressSpinner = ; } else { progressSpinner = ; } progressIndicator = ( {progressSpinner} {progressOverlay} ); } let playButton; if (mediaInfo.type === 'video') { playButton = ( ); } return ( {progressIndicator ? progressIndicator : playButton} ); } const styles = StyleSheet.create({ centerContainer: { alignItems: 'center', bottom: 0, justifyContent: 'center', left: 0, position: 'absolute', right: 0, top: 0, }, expand: { flex: 1, }, playButton: { color: 'white', opacity: 0.9, textShadowColor: '#000', textShadowOffset: { width: 0, height: 1 }, textShadowRadius: 1, }, processingStepText: { color: 'white', fontSize: 12, textShadowColor: '#000', textShadowRadius: 1, }, progressOverlay: { alignItems: 'center', justifyContent: 'center', position: 'absolute', }, progressPercentText: { color: 'white', fontSize: 24, fontWeight: 'bold', textShadowColor: '#000', textShadowRadius: 1, }, uploadError: { color: 'white', textShadowColor: '#000', textShadowOffset: { width: 0, height: 1 }, textShadowRadius: 1, }, }); export default InlineMultimedia; diff --git a/native/chat/message-list-header-title.react.js b/native/chat/message-list-header-title.react.js index 13f82688e..9a8e2b05d 100644 --- a/native/chat/message-list-header-title.react.js +++ b/native/chat/message-list-header-title.react.js @@ -1,113 +1,113 @@ // @flow import { HeaderTitle, type StackHeaderTitleInputProps, } from '@react-navigation/elements'; import * as React from 'react'; import { View, Platform } from 'react-native'; -import Icon from 'react-native-vector-icons/Ionicons'; +import Icon from '@expo/vector-icons/Ionicons'; import type { ThreadInfo } from 'lib/types/thread-types'; import { firstLine } from 'lib/utils/string-utils'; import Button from '../components/button.react'; import { ThreadSettingsRouteName } from '../navigation/route-names'; import { useStyles } from '../themes/colors'; import type { ChatNavigationProp } from './chat.react'; type BaseProps = { +threadInfo: ThreadInfo, +navigate: $PropertyType, 'navigate'>, +isSearchEmpty: boolean, +areSettingsEnabled: boolean, ...StackHeaderTitleInputProps, }; type Props = { ...BaseProps, +styles: typeof unboundStyles, }; class MessageListHeaderTitle extends React.PureComponent { render() { const { threadInfo, navigate, isSearchEmpty, areSettingsEnabled, styles, ...rest } = this.props; let icon, fakeIcon; if (Platform.OS === 'ios' && areSettingsEnabled) { icon = ( ); fakeIcon = ( ); } const title = isSearchEmpty ? 'New Message' : threadInfo.uiName; return ( ); } onPress = () => { const threadInfo = this.props.threadInfo; this.props.navigate<'ThreadSettings'>({ name: ThreadSettingsRouteName, params: { threadInfo }, key: `${ThreadSettingsRouteName}${threadInfo.id}`, }); }; } const unboundStyles = { button: { flex: 1, }, container: { flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: Platform.OS === 'android' ? 'flex-start' : 'center', }, fakeIcon: { paddingRight: 7, paddingTop: 3, flex: 1, minWidth: 25, opacity: 0, }, forwardIcon: { paddingLeft: 7, paddingTop: 3, color: 'headerChevron', flex: 1, minWidth: 25, }, }; const ConnectedMessageListHeaderTitle: React.ComponentType = React.memo( function ConnectedMessageListHeaderTitle(props: BaseProps) { const styles = useStyles(unboundStyles); return ; }, ); export default ConnectedMessageListHeaderTitle; diff --git a/native/chat/new-messages-pill.react.js b/native/chat/new-messages-pill.react.js index ef3f7cd51..e3a3f5664 100644 --- a/native/chat/new-messages-pill.react.js +++ b/native/chat/new-messages-pill.react.js @@ -1,73 +1,73 @@ // @flow import * as React from 'react'; import { TouchableOpacity, View, Text, Platform, Animated } from 'react-native'; -import Icon from 'react-native-vector-icons/FontAwesome'; +import Icon from '@expo/vector-icons/FontAwesome'; import { useStyles } from '../themes/colors'; import type { ViewStyle } from '../types/styles'; type Props = { +onPress: () => mixed, +newMessageCount: number, +containerStyle?: ViewStyle, +style?: ViewStyle, ...React.ElementConfig, }; function NewMessagesPill(props: Props): React.Node { const { onPress, newMessageCount, containerStyle, style, ...containerProps } = props; const styles = useStyles(unboundStyles); return ( {newMessageCount} ); } const unboundStyles = { countBubble: { alignItems: 'center', backgroundColor: 'vibrantGreenButton', borderRadius: 25, height: 25, justifyContent: 'center', paddingBottom: Platform.OS === 'android' ? 2 : 0, paddingLeft: 1, position: 'absolute', right: -8, top: -8, width: 25, }, countText: { color: 'white', textAlign: 'center', }, button: { backgroundColor: 'floatingButtonBackground', borderColor: 'floatingButtonLabel', borderRadius: 30, borderWidth: 4, paddingHorizontal: 12, paddingVertical: 6, }, icon: { color: 'floatingButtonLabel', fontSize: 32, fontWeight: 'bold', }, }; export default NewMessagesPill; diff --git a/native/chat/relationship-prompt.react.js b/native/chat/relationship-prompt.react.js index e44fb20c6..c1e2e1393 100644 --- a/native/chat/relationship-prompt.react.js +++ b/native/chat/relationship-prompt.react.js @@ -1,166 +1,166 @@ // @flow import * as React from 'react'; import { Alert, Text, View } from 'react-native'; -import Icon from 'react-native-vector-icons/FontAwesome5'; +import Icon from '@expo/vector-icons/FontAwesome5'; import { useRelationshipPrompt } from 'lib/hooks/relationship-prompt'; import { userRelationshipStatus } from 'lib/types/relationship-types'; import type { ThreadInfo } from 'lib/types/thread-types'; import type { UserInfo } from 'lib/types/user-types'; import Button from '../components/button.react'; import { useStyles } from '../themes/colors'; type Props = { +pendingPersonalThreadUserInfo: ?UserInfo, +threadInfo: ThreadInfo, }; const RelationshipPrompt: React.ComponentType = React.memo( function RelationshipPrompt({ pendingPersonalThreadUserInfo, threadInfo, }: Props) { const onErrorCallback = React.useCallback(() => { Alert.alert('Unknown error', 'Uhh... try again?', [{ text: 'OK' }]); }, []); const { otherUserInfo, callbacks: { blockUser, unblockUser, friendUser, unfriendUser }, } = useRelationshipPrompt( threadInfo, onErrorCallback, pendingPersonalThreadUserInfo, ); const styles = useStyles(unboundStyles); if ( !otherUserInfo || !otherUserInfo.username || otherUserInfo.relationshipStatus === userRelationshipStatus.FRIEND ) { return null; } if ( otherUserInfo.relationshipStatus === userRelationshipStatus.BLOCKED_VIEWER ) { return ( ); } if ( otherUserInfo.relationshipStatus === userRelationshipStatus.BOTH_BLOCKED || otherUserInfo.relationshipStatus === userRelationshipStatus.BLOCKED_BY_VIEWER ) { return ( ); } if ( otherUserInfo.relationshipStatus === userRelationshipStatus.REQUEST_RECEIVED ) { return ( ); } if ( otherUserInfo.relationshipStatus === userRelationshipStatus.REQUEST_SENT ) { return ( ); } return ( ); }, ); const unboundStyles = { container: { paddingVertical: 10, paddingHorizontal: 5, backgroundColor: 'panelBackground', flexDirection: 'row', }, button: { padding: 10, borderRadius: 5, flex: 1, flexDirection: 'row', justifyContent: 'center', marginHorizontal: 5, }, greenButton: { backgroundColor: 'vibrantGreenButton', }, redButton: { backgroundColor: 'vibrantRedButton', }, buttonText: { fontSize: 11, color: 'white', fontWeight: 'bold', textAlign: 'center', marginLeft: 5, }, }; export default RelationshipPrompt; diff --git a/native/chat/settings/color-selector-modal.react.js b/native/chat/settings/color-selector-modal.react.js index 3ed750693..7d8323545 100644 --- a/native/chat/settings/color-selector-modal.react.js +++ b/native/chat/settings/color-selector-modal.react.js @@ -1,183 +1,183 @@ // @flow import * as React from 'react'; import { TouchableHighlight, Alert } from 'react-native'; -import Icon from 'react-native-vector-icons/FontAwesome'; +import Icon from '@expo/vector-icons/FontAwesome'; import { changeThreadSettingsActionTypes, changeThreadSettings, } from 'lib/actions/thread-actions'; import { type ThreadInfo, type ChangeThreadSettingsPayload, type UpdateThreadRequest, } from 'lib/types/thread-types'; import type { DispatchActionPromise } from 'lib/utils/action-utils'; import { useServerCall, useDispatchActionPromise, } from 'lib/utils/action-utils'; import ColorSelector from '../../components/color-selector.react'; import Modal from '../../components/modal.react'; import type { RootNavigationProp } from '../../navigation/root-navigator.react'; import type { NavigationRoute } from '../../navigation/route-names'; import { useSelector } from '../../redux/redux-utils'; import { type Colors, useStyles, useColors } from '../../themes/colors'; export type ColorSelectorModalParams = { +presentedFrom: string, +color: string, +threadInfo: ThreadInfo, +setColor: (color: string) => void, }; type BaseProps = { +navigation: RootNavigationProp<'ColorSelectorModal'>, +route: NavigationRoute<'ColorSelectorModal'>, }; type Props = { ...BaseProps, // Redux state +colors: Colors, +styles: typeof unboundStyles, +windowWidth: number, // Redux dispatch functions +dispatchActionPromise: DispatchActionPromise, // async functions that hit server APIs +changeThreadSettings: ( request: UpdateThreadRequest, ) => Promise, }; function ColorSelectorModal(props: Props): React.Node { const { changeThreadSettings: updateThreadSettings, dispatchActionPromise, windowWidth, } = props; const { threadInfo, setColor } = props.route.params; const close = props.navigation.goBackOnce; const onErrorAcknowledged = React.useCallback(() => { setColor(threadInfo.color); }, [setColor, threadInfo.color]); const editColor = React.useCallback( async (newColor: string) => { const threadID = threadInfo.id; try { return await updateThreadSettings({ threadID, changes: { color: newColor }, }); } catch (e) { Alert.alert( 'Unknown error', 'Uhh... try again?', [{ text: 'OK', onPress: onErrorAcknowledged }], { cancelable: false }, ); throw e; } }, [onErrorAcknowledged, threadInfo.id, updateThreadSettings], ); const onColorSelected = React.useCallback( (color: string) => { const colorEditValue = color.substr(1); setColor(colorEditValue); close(); dispatchActionPromise( changeThreadSettingsActionTypes, editColor(colorEditValue), { customKeyName: `${changeThreadSettingsActionTypes.started}:color` }, ); }, [setColor, close, dispatchActionPromise, editColor], ); const { colorSelectorContainer, closeButton, closeButtonIcon } = props.styles; // Based on the assumption we are always in portrait, // and consequently width is the lowest dimensions const modalStyle = React.useMemo( () => [colorSelectorContainer, { height: 0.75 * windowWidth }], [colorSelectorContainer, windowWidth], ); const { modalIosHighlightUnderlay } = props.colors; const { color } = props.route.params; return ( ); } const unboundStyles = { closeButton: { borderRadius: 3, height: 18, position: 'absolute', right: 5, top: 5, width: 18, }, closeButtonIcon: { color: 'modalBackgroundSecondaryLabel', left: 3, position: 'absolute', }, colorSelector: { bottom: 10, left: 10, position: 'absolute', right: 10, top: 10, }, colorSelectorContainer: { backgroundColor: 'modalBackground', borderRadius: 5, flex: 0, marginHorizontal: 15, marginVertical: 20, }, }; const ConnectedColorSelectorModal: React.ComponentType = React.memo( function ConnectedColorSelectorModal(props: BaseProps) { const styles = useStyles(unboundStyles); const colors = useColors(); const windowWidth = useSelector(state => state.dimensions.width); const dispatchActionPromise = useDispatchActionPromise(); const callChangeThreadSettings = useServerCall(changeThreadSettings); return ( ); }, ); export default ConnectedColorSelectorModal; diff --git a/native/chat/settings/compose-subchannel-modal.react.js b/native/chat/settings/compose-subchannel-modal.react.js index 55ee91626..85a30b81e 100644 --- a/native/chat/settings/compose-subchannel-modal.react.js +++ b/native/chat/settings/compose-subchannel-modal.react.js @@ -1,150 +1,150 @@ // @flow import * as React from 'react'; import { Text } from 'react-native'; -import IonIcon from 'react-native-vector-icons/Ionicons'; +import IonIcon from '@expo/vector-icons/Ionicons'; import { threadTypeDescriptions } from 'lib/shared/thread-utils'; import { type ThreadInfo, threadTypes } from 'lib/types/thread-types'; import Button from '../../components/button.react'; import Modal from '../../components/modal.react'; import SWMansionIcon from '../../components/swmansion-icon.react'; import type { RootNavigationProp } from '../../navigation/root-navigator.react'; import type { NavigationRoute } from '../../navigation/route-names'; import { ComposeSubchannelRouteName } from '../../navigation/route-names'; import { type Colors, useStyles, useColors } from '../../themes/colors'; export type ComposeSubchannelModalParams = { +presentedFrom: string, +threadInfo: ThreadInfo, }; type BaseProps = { +navigation: RootNavigationProp<'ComposeSubchannelModal'>, +route: NavigationRoute<'ComposeSubchannelModal'>, }; type Props = { ...BaseProps, +colors: Colors, +styles: typeof unboundStyles, }; class ComposeSubchannelModal extends React.PureComponent { render() { return ( Chat type ); } onPressOpen = () => { const threadInfo = this.props.route.params.threadInfo; this.props.navigation.navigate<'ComposeSubchannel'>({ name: ComposeSubchannelRouteName, params: { threadType: threadTypes.COMMUNITY_OPEN_SUBTHREAD, parentThreadInfo: threadInfo, }, key: `${ComposeSubchannelRouteName}|` + `${threadInfo.id}|${threadTypes.COMMUNITY_OPEN_SUBTHREAD}`, }); }; onPressSecret = () => { const threadInfo = this.props.route.params.threadInfo; this.props.navigation.navigate<'ComposeSubchannel'>({ name: ComposeSubchannelRouteName, params: { threadType: threadTypes.COMMUNITY_SECRET_SUBTHREAD, parentThreadInfo: threadInfo, }, key: `${ComposeSubchannelRouteName}|` + `${threadInfo.id}|${threadTypes.COMMUNITY_SECRET_SUBTHREAD}`, }); }; } const unboundStyles = { forwardIcon: { color: 'modalForegroundSecondaryLabel', paddingLeft: 10, }, modal: { flex: 0, }, option: { alignItems: 'center', flexDirection: 'row', paddingHorizontal: 10, paddingVertical: 20, }, optionExplanation: { color: 'modalBackgroundLabel', flex: 1, fontSize: 14, paddingLeft: 20, textAlign: 'center', }, optionText: { color: 'modalBackgroundLabel', fontSize: 20, paddingLeft: 5, }, visibility: { color: 'modalBackgroundLabel', fontSize: 24, textAlign: 'center', }, visibilityIcon: { color: 'modalBackgroundLabel', paddingRight: 3, }, }; const ConnectedComposeSubchannelModal: React.ComponentType = React.memo( function ConnectedComposeSubchannelModal(props: BaseProps) { const styles = useStyles(unboundStyles); const colors = useColors(); return ( ); }, ); export default ConnectedComposeSubchannelModal; diff --git a/native/chat/settings/thread-settings-list-action.react.js b/native/chat/settings/thread-settings-list-action.react.js index 5bd752d24..e906c1a99 100644 --- a/native/chat/settings/thread-settings-list-action.react.js +++ b/native/chat/settings/thread-settings-list-action.react.js @@ -1,152 +1,152 @@ // @flow import * as React from 'react'; import { View, Text, Platform } from 'react-native'; -import type { IoniconsGlyphs } from 'react-native-vector-icons/Ionicons'; -import Icon from 'react-native-vector-icons/Ionicons'; +import type { IoniconsGlyphs } from '@expo/vector-icons/Ionicons'; +import Icon from '@expo/vector-icons/Ionicons'; import Button from '../../components/button.react'; import { useStyles } from '../../themes/colors'; import type { ViewStyle, TextStyle } from '../../types/styles'; type ListActionProps = { +onPress: () => void, +text: string, +iconName: IoniconsGlyphs, +iconSize: number, +iconStyle?: TextStyle, +buttonStyle?: ViewStyle, +styles: typeof unboundStyles, }; function ThreadSettingsListAction(props: ListActionProps) { return ( ); } type SeeMoreProps = { +onPress: () => void, }; function ThreadSettingsSeeMore(props: SeeMoreProps): React.Node { const styles = useStyles(unboundStyles); return ( ); } type AddMemberProps = { +onPress: () => void, }; function ThreadSettingsAddMember(props: AddMemberProps): React.Node { const styles = useStyles(unboundStyles); return ( ); } type AddChildChannelProps = { +onPress: () => void, }; function ThreadSettingsAddSubchannel(props: AddChildChannelProps): React.Node { const styles = useStyles(unboundStyles); return ( ); } const unboundStyles = { addSubchannelButton: { paddingTop: Platform.OS === 'ios' ? 4 : 1, }, addIcon: { color: 'link', }, addItemRow: { backgroundColor: 'panelForeground', paddingHorizontal: 12, }, addMemberButton: { paddingTop: Platform.OS === 'ios' ? 4 : 1, }, container: { flex: 1, flexDirection: 'row', paddingHorizontal: 12, paddingVertical: 8, justifyContent: 'center', }, icon: { lineHeight: 20, }, seeMoreButton: { paddingBottom: Platform.OS === 'ios' ? 4 : 2, paddingTop: Platform.OS === 'ios' ? 2 : 0, }, seeMoreContents: { borderColor: 'panelForegroundBorder', borderTopWidth: 1, }, seeMoreIcon: { color: 'link', position: 'absolute', right: 10, top: Platform.OS === 'android' ? 17 : 15, }, seeMoreRow: { backgroundColor: 'panelForeground', paddingHorizontal: 12, }, text: { color: 'link', flex: 1, fontSize: 16, fontStyle: 'italic', }, }; export { ThreadSettingsSeeMore, ThreadSettingsAddMember, ThreadSettingsAddSubchannel, }; diff --git a/native/chat/swipeable-message.react.js b/native/chat/swipeable-message.react.js index b876aa715..3433d434d 100644 --- a/native/chat/swipeable-message.react.js +++ b/native/chat/swipeable-message.react.js @@ -1,366 +1,366 @@ // @flow import { GestureHandlerRefContext } from '@react-navigation/stack'; import * as Haptics from 'expo-haptics'; import * as React from 'react'; import { View } from 'react-native'; import { PanGestureHandler } from 'react-native-gesture-handler'; import Animated, { useAnimatedGestureHandler, useSharedValue, useAnimatedStyle, runOnJS, withSpring, interpolate, cancelAnimation, Extrapolate, type SharedValue, } from 'react-native-reanimated'; -import type { IconProps } from 'react-native-vector-icons'; +import type { IconProps } from '@expo/vector-icons'; import tinycolor from 'tinycolor2'; import CommIcon from '../components/comm-icon.react'; import { colors } from '../themes/colors'; import type { ViewStyle } from '../types/styles'; import { useMessageListScreenWidth } from './composed-message-width'; const primaryThreshold = 40; const secondaryThreshold = 120; function dividePastDistance(value, distance, factor) { 'worklet'; const absValue = Math.abs(value); if (absValue < distance) { return value; } const absFactor = value >= 0 ? 1 : -1; return absFactor * (distance + (absValue - distance) / factor); } function makeSpringConfig(velocity) { 'worklet'; return { stiffness: 257.1370588235294, damping: 19.003038357561845, mass: 1, overshootClamping: true, restDisplacementThreshold: 0.001, restSpeedThreshold: 0.001, velocity, }; } function interpolateOpacityForViewerPrimarySnake(translateX) { 'worklet'; return interpolate(translateX, [-20, -5], [1, 0], Extrapolate.CLAMP); } function interpolateOpacityForNonViewerPrimarySnake(translateX) { 'worklet'; return interpolate(translateX, [5, 20], [0, 1], Extrapolate.CLAMP); } function interpolateTranslateXForViewerSecondarySnake(translateX) { 'worklet'; return interpolate(translateX, [-130, -120, -60, 0], [-130, -120, -5, 20]); } function interpolateTranslateXForNonViewerSecondarySnake(translateX) { 'worklet'; return interpolate(translateX, [0, 80, 120, 130], [0, 30, 120, 130]); } type SwipeSnakeProps = { +isViewer: boolean, +translateX: SharedValue, +color: string, +children: React.Element>>, +opacityInterpolator?: number => number, // must be worklet +translateXInterpolator?: number => number, // must be worklet }; function SwipeSnake( props: SwipeSnakeProps, ): React.Node { const { translateX, isViewer, opacityInterpolator, translateXInterpolator, } = props; const transformStyle = useAnimatedStyle(() => { const opacity = opacityInterpolator ? opacityInterpolator(translateX.value) : undefined; const translate = translateXInterpolator ? translateXInterpolator(translateX.value) : translateX.value; return { transform: [ { translateX: translate, }, ], opacity, }; }, [isViewer, translateXInterpolator, opacityInterpolator]); const animationPosition = isViewer ? styles.right0 : styles.left0; const animationContainerStyle = React.useMemo(() => { return [styles.animationContainer, animationPosition]; }, [animationPosition]); const iconPosition = isViewer ? styles.left0 : styles.right0; const swipeSnakeContainerStyle = React.useMemo(() => { return [styles.swipeSnakeContainer, transformStyle, iconPosition]; }, [transformStyle, iconPosition]); const iconAlign = isViewer ? styles.alignStart : styles.alignEnd; const screenWidth = useMessageListScreenWidth(); const { color } = props; const swipeSnakeStyle = React.useMemo(() => { return [ styles.swipeSnake, iconAlign, { width: screenWidth, backgroundColor: color, }, ]; }, [iconAlign, screenWidth, color]); const { children } = props; const iconColor = tinycolor(color).isDark() ? colors.dark.listForegroundLabel : colors.light.listForegroundLabel; const coloredIcon = React.useMemo( () => React.cloneElement(children, { color: iconColor, }), [children, iconColor], ); return ( {coloredIcon} ); } type Props = { +triggerReply?: () => void, +triggerSidebar?: () => void, +isViewer: boolean, +messageBoxStyle: ViewStyle, +threadColor: string, +children: React.Node, }; function SwipeableMessage(props: Props): React.Node { const { isViewer, triggerReply, triggerSidebar } = props; const secondaryActionExists = triggerReply && triggerSidebar; const onPassPrimaryThreshold = React.useCallback(() => { const impactStrength = secondaryActionExists ? Haptics.ImpactFeedbackStyle.Medium : Haptics.ImpactFeedbackStyle.Heavy; Haptics.impactAsync(impactStrength); }, [secondaryActionExists]); const onPassSecondaryThreshold = React.useCallback(() => { if (secondaryActionExists) { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy); } }, [secondaryActionExists]); const primaryAction = React.useCallback(() => { if (triggerReply) { triggerReply(); } else if (triggerSidebar) { triggerSidebar(); } }, [triggerReply, triggerSidebar]); const secondaryAction = React.useCallback(() => { if (triggerReply && triggerSidebar) { triggerSidebar(); } }, [triggerReply, triggerSidebar]); const translateX = useSharedValue(0); const swipeEvent = useAnimatedGestureHandler( { onStart: (event, ctx) => { ctx.translationAtStart = translateX.value; cancelAnimation(translateX.value); }, onActive: (event, ctx) => { const translationX = ctx.translationAtStart + event.translationX; const baseActiveTranslation = isViewer ? Math.min(translationX, 0) : Math.max(translationX, 0); translateX.value = dividePastDistance( baseActiveTranslation, primaryThreshold, 2, ); const absValue = Math.abs(translateX.value); const pastPrimaryThreshold = absValue >= primaryThreshold; if (pastPrimaryThreshold && !ctx.prevPastPrimaryThreshold) { runOnJS(onPassPrimaryThreshold)(); } ctx.prevPastPrimaryThreshold = pastPrimaryThreshold; const pastSecondaryThreshold = absValue >= secondaryThreshold; if (pastSecondaryThreshold && !ctx.prevPastSecondaryThreshold) { runOnJS(onPassSecondaryThreshold)(); } ctx.prevPastSecondaryThreshold = pastSecondaryThreshold; }, onEnd: event => { const absValue = Math.abs(translateX.value); if (absValue >= secondaryThreshold && secondaryActionExists) { runOnJS(secondaryAction)(); } else if (absValue >= primaryThreshold) { runOnJS(primaryAction)(); } translateX.value = withSpring(0, makeSpringConfig(event.velocityX)); }, }, [ isViewer, onPassPrimaryThreshold, onPassSecondaryThreshold, primaryAction, secondaryAction, secondaryActionExists, ], ); const transformMessageBoxStyle = useAnimatedStyle( () => ({ transform: [{ translateX: translateX.value }], }), [], ); const { messageBoxStyle, children } = props; const reactNavGestureHandlerRef = React.useContext(GestureHandlerRefContext); const waitFor = reactNavGestureHandlerRef ?? undefined; if (!triggerReply && !triggerSidebar) { return ( {children} ); } const threadColor = `#${props.threadColor}`; const tinyThreadColor = tinycolor(threadColor); const snakes = []; if (triggerReply) { const replySnakeOpacityInterpolator = isViewer ? interpolateOpacityForViewerPrimarySnake : interpolateOpacityForNonViewerPrimarySnake; snakes.push( , ); } if (triggerReply && triggerSidebar) { const sidebarSnakeTranslateXInterpolator = isViewer ? interpolateTranslateXForViewerSecondarySnake : interpolateTranslateXForNonViewerSecondarySnake; const darkerThreadColor = tinyThreadColor .darken(tinyThreadColor.isDark() ? 10 : 20) .toString(); snakes.push( , ); } else if (triggerSidebar) { const sidebarSnakeOpacityInterpolator = isViewer ? interpolateOpacityForViewerPrimarySnake : interpolateOpacityForNonViewerPrimarySnake; snakes.push( , ); } snakes.push( {children} , ); return snakes; } const styles = { swipeSnakeContainer: { marginHorizontal: 20, justifyContent: 'center', position: 'absolute', top: 0, bottom: 0, }, animationContainer: { position: 'absolute', top: 0, bottom: 0, }, swipeSnake: { paddingHorizontal: 15, flex: 1, borderRadius: 25, height: 30, justifyContent: 'center', maxHeight: 50, }, left0: { left: 0, }, right0: { right: 0, }, alignStart: { alignItems: 'flex-start', }, alignEnd: { alignItems: 'flex-end', }, }; export default SwipeableMessage; diff --git a/native/chat/swipeable-thread.react.js b/native/chat/swipeable-thread.react.js index 1f0f36d48..f4a0a6993 100644 --- a/native/chat/swipeable-thread.react.js +++ b/native/chat/swipeable-thread.react.js @@ -1,94 +1,94 @@ // @flow import { useNavigation } from '@react-navigation/native'; import * as React from 'react'; -import MaterialIcon from 'react-native-vector-icons/MaterialCommunityIcons'; +import MaterialIcon from '@expo/vector-icons/MaterialCommunityIcons'; import useToggleUnreadStatus from 'lib/hooks/toggle-unread-status'; import type { ThreadInfo } from 'lib/types/thread-types'; import Swipeable from '../components/swipeable'; import { useColors } from '../themes/colors'; type Props = { +threadInfo: ThreadInfo, +mostRecentNonLocalMessage: ?string, +onSwipeableWillOpen: (threadInfo: ThreadInfo) => void, +currentlyOpenedSwipeableId?: string, +iconSize: number, +children: React.Node, }; function SwipeableThread(props: Props): React.Node { const swipeable = React.useRef(); const navigation = useNavigation(); React.useEffect(() => { return navigation.addListener('blur', () => { if (swipeable.current) { swipeable.current.close(); } }); }, [navigation, swipeable]); const { threadInfo, currentlyOpenedSwipeableId } = props; React.useEffect(() => { if (swipeable.current && threadInfo.id !== currentlyOpenedSwipeableId) { swipeable.current.close(); } }, [currentlyOpenedSwipeableId, swipeable, threadInfo.id]); const { onSwipeableWillOpen } = props; const onSwipeableRightWillOpen = React.useCallback(() => { onSwipeableWillOpen(threadInfo); }, [onSwipeableWillOpen, threadInfo]); const colors = useColors(); const { mostRecentNonLocalMessage, iconSize } = props; const swipeableClose = React.useCallback(() => { if (swipeable.current) { swipeable.current.close(); } }, []); const toggleUnreadStatus = useToggleUnreadStatus( threadInfo, mostRecentNonLocalMessage, swipeableClose, ); const swipeableActions = React.useMemo(() => { const isUnread = threadInfo.currentUser.unread; return [ { key: 'action1', onPress: toggleUnreadStatus, color: isUnread ? colors.vibrantRedButton : colors.vibrantGreenButton, content: ( ), }, ]; }, [ threadInfo.currentUser.unread, toggleUnreadStatus, colors.vibrantRedButton, colors.vibrantGreenButton, iconSize, ]); return ( {props.children} ); } export default SwipeableThread; diff --git a/native/chat/thread-settings-button.react.js b/native/chat/thread-settings-button.react.js index 8380093af..1e4e1ac7a 100644 --- a/native/chat/thread-settings-button.react.js +++ b/native/chat/thread-settings-button.react.js @@ -1,56 +1,56 @@ // @flow import * as React from 'react'; -import Icon from 'react-native-vector-icons/Ionicons'; +import Icon from '@expo/vector-icons/Ionicons'; import { type ThreadInfo } from 'lib/types/thread-types'; import Button from '../components/button.react'; import { ThreadSettingsRouteName } from '../navigation/route-names'; import { useStyles } from '../themes/colors'; import type { ChatNavigationProp } from './chat.react'; type BaseProps = { +threadInfo: ThreadInfo, +navigate: $PropertyType, 'navigate'>, }; type Props = { ...BaseProps, +styles: typeof unboundStyles, }; class ThreadSettingsButton extends React.PureComponent { render() { return ( ); } onPress = () => { const threadInfo = this.props.threadInfo; this.props.navigate<'ThreadSettings'>({ name: ThreadSettingsRouteName, params: { threadInfo }, key: `${ThreadSettingsRouteName}${threadInfo.id}`, }); }; } const unboundStyles = { button: { color: 'link', paddingHorizontal: 10, }, }; const ConnectedThreadSettingsButton: React.ComponentType = React.memo( function ConnectedThreadSettingsButton(props: BaseProps) { const styles = useStyles(unboundStyles); return ; }, ); export default ConnectedThreadSettingsButton; diff --git a/native/components/action-row.react.js b/native/components/action-row.react.js index d9c481133..79ed83771 100644 --- a/native/components/action-row.react.js +++ b/native/components/action-row.react.js @@ -1,88 +1,88 @@ // @flow import * as React from 'react'; import { View, Text as RawText } from 'react-native'; import RawIcon, { type IoniconsGlyphs, -} from 'react-native-vector-icons/Ionicons'; +} from '@expo/vector-icons/Ionicons'; import Button from '../components/button.react'; import { useColors, useStyles } from '../themes/colors'; type TextProps = { +content: string, +danger?: boolean, }; function Text(props: TextProps): React.Node { const { content, danger } = props; const styles = useStyles(actionRowStyles); return ( {content} ); } type IconProps = { +name: IoniconsGlyphs, }; function Icon(props: IconProps): React.Node { const { name } = props; const colors = useColors(); return ; } type RowProps = { +onPress?: () => void, +children: React.Node, }; function Row(props: RowProps): React.Node { const { onPress, children } = props; const styles = useStyles(actionRowStyles); const colors = useColors(); if (!onPress) { return {children}; } return ( ); } const actionRowStyles = { wrapper: { backgroundColor: 'panelForeground', flexDirection: 'row', paddingHorizontal: 24, paddingVertical: 10, }, button: { paddingHorizontal: 24, paddingVertical: 10, flexDirection: 'row', }, text: { color: 'panelForegroundLabel', flex: 1, fontSize: 16, }, dangerText: { color: 'redText', flex: 1, fontSize: 16, }, }; export default { Row, Icon, Text }; diff --git a/native/components/comm-icon.react.js b/native/components/comm-icon.react.js index 85f434495..d3352bf2b 100644 --- a/native/components/comm-icon.react.js +++ b/native/components/comm-icon.react.js @@ -1,13 +1,13 @@ // @flow -import { createIconSetFromIcoMoon, type Icon } from 'react-native-vector-icons'; +import { createIconSetFromIcoMoon, type Icon } from '@expo/vector-icons'; import icoMoonConfig from 'lib/shared/comm-icon-config.json'; const CommIcon: Class> = createIconSetFromIcoMoon( icoMoonConfig, 'CommIcons', 'CommIcons.ttf', ); export default CommIcon; diff --git a/native/components/swmansion-icon.react.js b/native/components/swmansion-icon.react.js index 214b5fc44..113d7322f 100644 --- a/native/components/swmansion-icon.react.js +++ b/native/components/swmansion-icon.react.js @@ -1,13 +1,13 @@ // @flow -import { createIconSetFromIcoMoon, type Icon } from 'react-native-vector-icons'; +import { createIconSetFromIcoMoon, type Icon } from '@expo/vector-icons'; import icoMoonConfig from 'lib/shared/swmansion-icon-config.json'; const SWMansionIcon: Class> = createIconSetFromIcoMoon( icoMoonConfig, 'SWMansionIcons', 'SWMansionIcons.ttf', ); export default SWMansionIcon; diff --git a/native/components/thread-ancestors-label.react.js b/native/components/thread-ancestors-label.react.js index 124486542..2218b4dd3 100644 --- a/native/components/thread-ancestors-label.react.js +++ b/native/components/thread-ancestors-label.react.js @@ -1,72 +1,72 @@ // @flow import * as React from 'react'; import { Text, View } from 'react-native'; -import Icon from 'react-native-vector-icons/FontAwesome5'; +import Icon from '@expo/vector-icons/FontAwesome5'; import { useAncestorThreads } from 'lib/shared/ancestor-threads'; import { type ThreadInfo } from 'lib/types/thread-types'; import { useColors, useStyles } from '../themes/colors'; type Props = { +threadInfo: ThreadInfo, }; function ThreadAncestorsLabel(props: Props): React.Node { const { threadInfo } = props; const { unread } = threadInfo.currentUser; const styles = useStyles(unboundStyles); const colors = useColors(); const ancestorThreads = useAncestorThreads(threadInfo); const chevronIcon = React.useMemo( () => ( ), [colors.listForegroundTertiaryLabel], ); const ancestorPath = React.useMemo(() => { const path = []; for (const thread of ancestorThreads) { path.push({thread.uiName}); path.push( ${thread.id}`} style={styles.chevron}> {chevronIcon} , ); } path.pop(); return path; }, [ancestorThreads, chevronIcon, styles.chevron]); const ancestorPathStyle = React.useMemo(() => { return unread ? [styles.pathText, styles.unread] : styles.pathText; }, [styles.pathText, styles.unread, unread]); return ( {ancestorPath} ); } const unboundStyles = { pathText: { opacity: 0.8, fontSize: 12, color: 'listForegroundTertiaryLabel', }, unread: { color: 'listForegroundLabel', }, chevron: { paddingHorizontal: 3, }, }; export default ThreadAncestorsLabel; diff --git a/native/components/thread-ancestors.react.js b/native/components/thread-ancestors.react.js index 5570c6d51..ec09c7230 100644 --- a/native/components/thread-ancestors.react.js +++ b/native/components/thread-ancestors.react.js @@ -1,111 +1,111 @@ // @flow import * as React from 'react'; import { View, ScrollView } from 'react-native'; -import Icon from 'react-native-vector-icons/FontAwesome5'; +import Icon from '@expo/vector-icons/FontAwesome5'; import { ancestorThreadInfos } from 'lib/selectors/thread-selectors'; import type { ThreadInfo } from 'lib/types/thread-types'; import { useNavigateToThread } from '../chat/message-list-types'; import { useSelector } from '../redux/redux-utils'; import { useColors, useStyles } from '../themes/colors'; import Button from './button.react'; import CommunityPill from './community-pill.react'; import ThreadPill from './thread-pill.react'; type Props = { +threadInfo: ThreadInfo, }; function ThreadAncestors(props: Props): React.Node { const { threadInfo } = props; const styles = useStyles(unboundStyles); const colors = useColors(); const ancestorThreads: $ReadOnlyArray = useSelector( ancestorThreadInfos(threadInfo.id), ); const rightArrow = React.useMemo( () => ( ), [colors.panelForegroundLabel], ); const navigateToThread = useNavigateToThread(); const pathElements = React.useMemo(() => { const elements = []; for (const [idx, ancestorThreadInfo] of ancestorThreads.entries()) { const isLastThread = idx === ancestorThreads.length - 1; const pill = idx === 0 ? ( ) : ( ); elements.push( {!isLastThread ? rightArrow : null} , ); } return {elements}; }, [ ancestorThreads, navigateToThread, rightArrow, styles.pathItem, styles.row, ]); return ( {pathElements} ); } const height = 48; const unboundStyles = { arrowIcon: { paddingHorizontal: 8, }, container: { height, backgroundColor: 'panelForeground', borderBottomWidth: 1, borderColor: 'panelForegroundBorder', }, contentContainer: { paddingHorizontal: 12, }, pathItem: { alignItems: 'center', flexDirection: 'row', height, }, row: { flexDirection: 'row', }, }; export default ThreadAncestors; diff --git a/native/components/thread-icon.react.js b/native/components/thread-icon.react.js index a4d36a68b..7d5ccd423 100644 --- a/native/components/thread-icon.react.js +++ b/native/components/thread-icon.react.js @@ -1,44 +1,44 @@ // @flow import * as React from 'react'; import { StyleSheet } from 'react-native'; -import EntypoIcon from 'react-native-vector-icons/Entypo'; +import EntypoIcon from '@expo/vector-icons/Entypo'; import { threadTypes, type ThreadType } from 'lib/types/thread-types'; import SWMansionIcon from './swmansion-icon.react'; type Props = { +threadType: ThreadType, +color: string, }; function ThreadIcon(props: Props): React.Node { const { threadType, color } = props; if ( threadType === threadTypes.COMMUNITY_OPEN_SUBTHREAD || threadType === threadTypes.COMMUNITY_OPEN_ANNOUNCEMENT_SUBTHREAD ) { return ; } else if (threadType === threadTypes.SIDEBAR) { return ( ); } else if (threadType === threadTypes.PERSONAL) { return ; } else { return ; } } const styles = StyleSheet.create({ sidebarIcon: { paddingTop: 2, }, }); export default ThreadIcon; diff --git a/native/crash.react.js b/native/crash.react.js index ed07bdac8..dd38a6e10 100644 --- a/native/crash.react.js +++ b/native/crash.react.js @@ -1,293 +1,293 @@ // @flow import Clipboard from '@react-native-clipboard/clipboard'; import invariant from 'invariant'; import _shuffle from 'lodash/fp/shuffle'; import * as React from 'react'; import { View, Text, Platform, StyleSheet, ScrollView, ActivityIndicator, } from 'react-native'; import ExitApp from 'react-native-exit-app'; -import Icon from 'react-native-vector-icons/FontAwesome'; +import Icon from '@expo/vector-icons/FontAwesome'; import { sendReportActionTypes, sendReport } from 'lib/actions/report-actions'; import { logOutActionTypes, logOut } from 'lib/actions/user-actions'; import { preRequestUserStateSelector } from 'lib/selectors/account-selectors'; import type { LogOutResult } from 'lib/types/account-types'; import type { ErrorData } from 'lib/types/report-types'; import { type ClientReportCreationRequest, type ReportCreationResponse, reportTypes, } from 'lib/types/report-types'; import type { PreRequestUserState } from 'lib/types/session-types'; import { actionLogger } from 'lib/utils/action-logger'; import { type DispatchActionPromise, useServerCall, useDispatchActionPromise, } from 'lib/utils/action-utils'; import { useIsReportEnabled } from 'lib/utils/report-utils'; import { sanitizeReduxReport, type ReduxCrashReport, } from 'lib/utils/sanitization'; import sleep from 'lib/utils/sleep'; import Button from './components/button.react'; import ConnectedStatusBar from './connected-status-bar.react'; import { persistConfig, codeVersion } from './redux/persist'; import { useSelector } from './redux/redux-utils'; import { wipeAndExit } from './utils/crash-utils'; const errorTitles = ['Oh no!!', 'Womp womp womp...']; type BaseProps = { +errorData: $ReadOnlyArray, }; type Props = { ...BaseProps, // Redux state +preRequestUserState: PreRequestUserState, // Redux dispatch functions +dispatchActionPromise: DispatchActionPromise, // async functions that hit server APIs +sendReport: ( request: ClientReportCreationRequest, ) => Promise, +logOut: (preRequestUserState: PreRequestUserState) => Promise, +crashReportingEnabled: boolean, }; type State = { +errorReportID: ?string, +doneWaiting: boolean, }; class Crash extends React.PureComponent { errorTitle = _shuffle(errorTitles)[0]; constructor(props) { super(props); this.state = { errorReportID: null, doneWaiting: !props.crashReportingEnabled, }; } componentDidMount() { if (this.state.doneWaiting) { return; } this.props.dispatchActionPromise(sendReportActionTypes, this.sendReport()); this.timeOut(); } async timeOut() { // If it takes more than 10s, give up and let the user exit await sleep(10000); this.setState({ doneWaiting: true }); } render() { const errorText = [...this.props.errorData] .reverse() .map(errorData => errorData.error.message) .join('\n'); let crashID; if (!this.state.doneWaiting) { crashID = ; } else if (this.state.doneWaiting && this.state.errorReportID) { crashID = ( Crash report ID: {this.state.errorReportID} ); } else { crashID = ( Crash reporting can be enabled in the Profile tab. ); } const buttonStyle = { opacity: Number(this.state.doneWaiting) }; return ( {this.errorTitle} I'm sorry, but the app crashed. {crashID} Here's some text that's probably not helpful: {errorText} ); } async sendReport() { const sanitizedReduxReport: ReduxCrashReport = sanitizeReduxReport({ preloadedState: actionLogger.preloadedState, currentState: actionLogger.currentState, actions: actionLogger.actions, }); const result = await this.props.sendReport({ type: reportTypes.ERROR, platformDetails: { platform: Platform.OS, codeVersion, stateVersion: persistConfig.version, }, errors: this.props.errorData.map(data => ({ errorMessage: data.error.message, stack: data.error.stack, componentStack: data.info && data.info.componentStack, })), ...sanitizedReduxReport, }); this.setState({ errorReportID: result.id, doneWaiting: true, }); } onPressKill = () => { if (!this.state.doneWaiting) { return; } ExitApp.exitApp(); }; onPressWipe = async () => { if (!this.state.doneWaiting) { return; } this.props.dispatchActionPromise(logOutActionTypes, this.logOutAndExit()); }; async logOutAndExit() { try { await this.props.logOut(this.props.preRequestUserState); } catch (e) {} await wipeAndExit(); } onCopyCrashReportID = () => { invariant(this.state.errorReportID, 'should be set'); Clipboard.setString(this.state.errorReportID); }; } const styles = StyleSheet.create({ button: { backgroundColor: '#FF0000', borderRadius: 5, marginHorizontal: 10, paddingHorizontal: 10, paddingVertical: 5, }, buttonText: { color: 'white', fontSize: 16, }, buttons: { flexDirection: 'row', }, container: { alignItems: 'center', backgroundColor: 'white', flex: 1, justifyContent: 'center', }, copyCrashReportIDButtonText: { color: '#036AFF', }, crashID: { flexDirection: 'row', paddingBottom: 12, paddingTop: 2, }, crashIDText: { color: 'black', paddingRight: 8, }, errorReportID: { flexDirection: 'row', height: 20, }, errorReportIDText: { color: 'black', paddingRight: 8, }, errorText: { color: 'black', fontFamily: Platform.select({ ios: 'Menlo', default: 'monospace', }), }, header: { color: 'black', fontSize: 24, paddingBottom: 24, }, scrollView: { flex: 1, marginBottom: 24, marginTop: 12, maxHeight: 200, paddingHorizontal: 50, }, text: { color: 'black', paddingBottom: 12, }, }); const ConnectedCrash: React.ComponentType = React.memo( function ConnectedCrash(props: BaseProps) { const preRequestUserState = useSelector(preRequestUserStateSelector); const dispatchActionPromise = useDispatchActionPromise(); const callSendReport = useServerCall(sendReport); const callLogOut = useServerCall(logOut); const crashReportingEnabled = useIsReportEnabled('crashReports'); return ( ); }, ); export default ConnectedCrash; diff --git a/native/ios/Comm.xcodeproj/project.pbxproj b/native/ios/Comm.xcodeproj/project.pbxproj index 5162b3188..9b7730094 100644 --- a/native/ios/Comm.xcodeproj/project.pbxproj +++ b/native/ios/Comm.xcodeproj/project.pbxproj @@ -1,1690 +1,1626 @@ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 1F537ACC7B60DC049C0ECFA7 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 769A87FB41BCE3FEF97FD59A /* ExpoModulesProvider.swift */; }; 71142A7726C2650B0039DCBD /* CommSecureStoreIOSWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71142A7626C2650A0039DCBD /* CommSecureStoreIOSWrapper.mm */; }; 711B408425DA97F9005F8F06 /* dummy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F26E81B24440D87004049C6 /* dummy.swift */; }; 713EE41126C66B80003D7C48 /* CryptoTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 713EE41026C66B80003D7C48 /* CryptoTest.mm */; }; 71762A75270D8AAE00F565ED /* PlatformSpecificTools.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71762A74270D8AAE00F565ED /* PlatformSpecificTools.mm */; }; 718DE99E2653D41C00365824 /* WorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 718DE99C2653D41C00365824 /* WorkerThread.cpp */; }; 71BE84492636A944002849D2 /* NativeModules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BE843B2636A944002849D2 /* NativeModules.cpp */; }; 71BE844A2636A944002849D2 /* CommCoreModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BE843C2636A944002849D2 /* CommCoreModule.cpp */; }; 71BE844B2636A944002849D2 /* SQLiteQueryExecutor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BE84412636A944002849D2 /* SQLiteQueryExecutor.cpp */; }; 71BF5B7126B3FF0900EDE27D /* Session.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BF5B6F26B3FF0900EDE27D /* Session.cpp */; }; 71BF5B7526B401D300EDE27D /* Tools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BF5B7326B401D300EDE27D /* Tools.cpp */; }; 71BF5B7F26BBDD7400EDE27D /* CryptoModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BF5B7B26BBDA6100EDE27D /* CryptoModule.cpp */; }; 71CA4A64262DA8E500835C89 /* Logger.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71CA4A63262DA8E500835C89 /* Logger.mm */; }; 71CA4AEC262F236100835C89 /* Tools.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71CA4AEB262F236100835C89 /* Tools.mm */; }; 71D4D7CC26C50B1000FCDBCD /* CommSecureStore.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71D4D7CB26C50B1000FCDBCD /* CommSecureStore.mm */; }; 724995D527B4103A00323FCE /* NotificationService.mm in Sources */ = {isa = PBXBuildFile; fileRef = 724995D427B4103A00323FCE /* NotificationService.mm */; }; 724995D927B4103A00323FCE /* NotificationService.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 724995D127B4103A00323FCE /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 724995FB27BA9E8D00323FCE /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 724995FA27BA9E8C00323FCE /* UserNotifications.framework */; }; 75291F0428F9A0D400F4C80E /* DeviceID.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 75291F0328F9A0AE00F4C80E /* DeviceID.cpp */; }; 7F0C6E31291C4468002AA2D9 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EEB3E70587B0ADAD05237B0 /* ExpoModulesProvider.swift */; }; 7F761E602201141E001B6FB7 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F761E292201141E001B6FB7 /* JavaScriptCore.framework */; }; 7F788C2C248AA2140098F071 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7F788C2B248AA2130098F071 /* SplashScreen.storyboard */; }; 7F8D602126535E060053CB29 /* OpenSans-Semibold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7F8D601E26535E060053CB29 /* OpenSans-Semibold.ttf */; }; 7F8D602226535E060053CB29 /* Anaheim-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7F8D601F26535E060053CB29 /* Anaheim-Regular.ttf */; }; 7F8D602326535E060053CB29 /* OpenSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7F8D602026535E060053CB29 /* OpenSans-Regular.ttf */; }; 7F8D602826535F240053CB29 /* IBMPlexSans-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7F8D602726535EEE0053CB29 /* IBMPlexSans-Bold.ttf */; }; 7F8D602926535F2A0053CB29 /* IBMPlexSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7F8D602626535EEE0053CB29 /* IBMPlexSans-Regular.ttf */; }; 8B99BAAC28D50F3000EB5ADB /* libnative_rust_library.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B99BAAB28D50F3000EB5ADB /* libnative_rust_library.a */; }; 8B99BAAE28D511FF00EB5ADB /* lib.rs.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B99BAAD28D511FF00EB5ADB /* lib.rs.cc */; }; 8E43C32C291E5B4A009378F5 /* TerminateApp.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8E43C32B291E5B4A009378F5 /* TerminateApp.mm */; }; B7162ABD28AAD461006588D3 /* CommIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B7162ABC28AAD461006588D3 /* CommIcons.ttf */; }; B71AFF1F265EDD8600B22352 /* IBMPlexSans-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B71AFF1E265EDD8600B22352 /* IBMPlexSans-Medium.ttf */; }; B734D11028ADD55200570D04 /* SWMansionIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B734D10F28ADD55200570D04 /* SWMansionIcons.ttf */; }; CB1648AF27CFBE6A00394D9D /* CryptoModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BF5B7B26BBDA6100EDE27D /* CryptoModule.cpp */; }; CB38B48228771C7A00171182 /* NonBlockingLock.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB38B47B287718A200171182 /* NonBlockingLock.mm */; }; CB38B48328771C8300171182 /* NonBlockingLock.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB38B47B287718A200171182 /* NonBlockingLock.mm */; }; CB38B48428771CAF00171182 /* EncryptedFileUtils.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB38B47D2877194100171182 /* EncryptedFileUtils.mm */; }; CB38B48528771CB800171182 /* EncryptedFileUtils.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB38B47D2877194100171182 /* EncryptedFileUtils.mm */; }; CB38B48628771CDD00171182 /* TemporaryMessageStorage.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB38B47F28771A3B00171182 /* TemporaryMessageStorage.mm */; }; CB38B48728771CE500171182 /* TemporaryMessageStorage.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB38B47F28771A3B00171182 /* TemporaryMessageStorage.mm */; }; CB38F2B1286C6C870010535C /* MessageOperationsUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB38F2AF286C6C870010535C /* MessageOperationsUtilities.cpp */; }; CB38F2C0286C6CDF0010535C /* MessageOperationsUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB38F2AF286C6C870010535C /* MessageOperationsUtilities.cpp */; }; CB3C621127CE4A320054F24C /* Logger.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71CA4A63262DA8E500835C89 /* Logger.mm */; }; CB3C621227CE65030054F24C /* CommSecureStoreIOSWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71142A7626C2650A0039DCBD /* CommSecureStoreIOSWrapper.mm */; }; CB4821A527CF9F38001AB7E1 /* CommSecureStore.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71D4D7CB26C50B1000FCDBCD /* CommSecureStore.mm */; }; CB4821A927CFB153001AB7E1 /* WorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 718DE99C2653D41C00365824 /* WorkerThread.cpp */; }; CB4821AA27CFB153001AB7E1 /* Tools.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71CA4AEB262F236100835C89 /* Tools.mm */; }; CB4821AC27CFB17C001AB7E1 /* Session.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BF5B6F26B3FF0900EDE27D /* Session.cpp */; }; CB4821AE27CFB187001AB7E1 /* Tools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BF5B7326B401D300EDE27D /* Tools.cpp */; }; CB4821AF27CFB19D001AB7E1 /* PlatformSpecificTools.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71762A74270D8AAE00F565ED /* PlatformSpecificTools.mm */; }; CB4821B227CFB20E001AB7E1 /* SQLiteQueryExecutor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BE84412636A944002849D2 /* SQLiteQueryExecutor.cpp */; }; CBDEC69B28ED867000C17588 /* GlobalDBSingleton.mm in Sources */ = {isa = PBXBuildFile; fileRef = CBDEC69A28ED867000C17588 /* GlobalDBSingleton.mm */; }; CBFE58292885852B003B94C9 /* ThreadOperations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CBFE58282885852B003B94C9 /* ThreadOperations.cpp */; }; D7DB6E0F85B2DBE15B01EC21 /* libPods-Comm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 994BEBDD4E4959F69CEA0BC3 /* libPods-Comm.a */; }; F02C296C528B51ADAB5AA19D /* libPods-NotificationService.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3EE4DCB430B05EC9DE7D7B01 /* libPods-NotificationService.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 713EE40B26C6676B003D7C48 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; proxyType = 1; remoteGlobalIDString = 13B07F861A680F5B00A75B9A; remoteInfo = Comm; }; 724995D727B4103A00323FCE /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; proxyType = 1; remoteGlobalIDString = 724995D027B4103A00323FCE; remoteInfo = NotificationService; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 724995DA27B4103A00323FCE /* Embed App Extensions */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 13; files = ( 724995D927B4103A00323FCE /* NotificationService.appex in Embed App Extensions */, ); name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 13B07F961A680F5B00A75B9A /* Comm.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Comm.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Comm/AppDelegate.h; sourceTree = ""; }; 13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = Comm/AppDelegate.mm; sourceTree = ""; }; 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Comm/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.release.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.release.plist; path = Comm/Info.release.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Comm/main.m; sourceTree = ""; }; 2DDA0A22FECC9DAA5C19C35D /* Metadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Metadata.h; sourceTree = ""; }; 3EE4DCB430B05EC9DE7D7B01 /* libPods-NotificationService.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NotificationService.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 3EEB3E70587B0ADAD05237B0 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-Comm/ExpoModulesProvider.swift"; sourceTree = ""; }; 71142A7526C2650A0039DCBD /* CommSecureStoreIOSWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommSecureStoreIOSWrapper.h; path = Comm/CommSecureStoreIOSWrapper.h; sourceTree = ""; }; 71142A7626C2650A0039DCBD /* CommSecureStoreIOSWrapper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CommSecureStoreIOSWrapper.mm; path = Comm/CommSecureStoreIOSWrapper.mm; sourceTree = ""; }; 711CF80E25DC096000A00FBD /* libFolly.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libFolly.a; sourceTree = BUILT_PRODUCTS_DIR; }; 713EE40626C6676B003D7C48 /* CommTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CommTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 713EE40A26C6676B003D7C48 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 713EE41026C66B80003D7C48 /* CryptoTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CryptoTest.mm; sourceTree = ""; }; 71762A74270D8AAE00F565ED /* PlatformSpecificTools.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlatformSpecificTools.mm; path = Comm/PlatformSpecificTools.mm; sourceTree = ""; }; 718DE99C2653D41C00365824 /* WorkerThread.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WorkerThread.cpp; sourceTree = ""; }; 718DE99D2653D41C00365824 /* WorkerThread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WorkerThread.h; sourceTree = ""; }; 71B8CCBD26BD4DEB0040C0A2 /* CommSecureStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommSecureStore.h; sourceTree = ""; }; 71BE84392636A944002849D2 /* Logger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Logger.h; sourceTree = ""; }; 71BE843B2636A944002849D2 /* NativeModules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NativeModules.cpp; sourceTree = ""; }; 71BE843C2636A944002849D2 /* CommCoreModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CommCoreModule.cpp; sourceTree = ""; }; 71BE843D2636A944002849D2 /* NativeModules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeModules.h; sourceTree = ""; }; 71BE843E2636A944002849D2 /* CommCoreModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommCoreModule.h; sourceTree = ""; }; 71BE84402636A944002849D2 /* DatabaseQueryExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DatabaseQueryExecutor.h; sourceTree = ""; }; 71BE84412636A944002849D2 /* SQLiteQueryExecutor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SQLiteQueryExecutor.cpp; sourceTree = ""; }; 71BE84422636A944002849D2 /* SQLiteQueryExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQLiteQueryExecutor.h; sourceTree = ""; }; 71BE84432636A944002849D2 /* DatabaseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DatabaseManager.h; sourceTree = ""; }; 71BE84452636A944002849D2 /* Draft.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Draft.h; sourceTree = ""; }; 71BE84482636A944002849D2 /* sqlite_orm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqlite_orm.h; sourceTree = ""; }; 71BF5B6F26B3FF0900EDE27D /* Session.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Session.cpp; sourceTree = ""; }; 71BF5B7026B3FF0900EDE27D /* Session.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Session.h; sourceTree = ""; }; 71BF5B7226B3FFBC00EDE27D /* Persist.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Persist.h; sourceTree = ""; }; 71BF5B7326B401D300EDE27D /* Tools.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Tools.cpp; sourceTree = ""; }; 71BF5B7426B401D300EDE27D /* Tools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Tools.h; sourceTree = ""; }; 71BF5B7A26BBDA6000EDE27D /* CryptoModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CryptoModule.h; sourceTree = ""; }; 71BF5B7B26BBDA6100EDE27D /* CryptoModule.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoModule.cpp; sourceTree = ""; }; 71CA4A63262DA8E500835C89 /* Logger.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Logger.mm; path = Comm/Logger.mm; sourceTree = ""; }; 71CA4AEA262F230A00835C89 /* Tools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Tools.h; path = Comm/Tools.h; sourceTree = ""; }; 71CA4AEB262F236100835C89 /* Tools.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = Tools.mm; path = Comm/Tools.mm; sourceTree = ""; }; 71D4D7CB26C50B1000FCDBCD /* CommSecureStore.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CommSecureStore.mm; path = Comm/CommSecureStore.mm; sourceTree = ""; }; 71DC160C270C43D300822863 /* PlatformSpecificTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PlatformSpecificTools.h; sourceTree = ""; }; 724995D127B4103A00323FCE /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 724995D327B4103A00323FCE /* NotificationService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NotificationService.h; sourceTree = ""; }; 724995D427B4103A00323FCE /* NotificationService.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = NotificationService.mm; sourceTree = ""; }; 724995D627B4103A00323FCE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 724995FA27BA9E8C00323FCE /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; }; 75291F0228F9A09E00F4C80E /* DeviceID.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DeviceID.h; sourceTree = ""; }; 75291F0328F9A0AE00F4C80E /* DeviceID.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DeviceID.cpp; sourceTree = ""; }; 769A87FB41BCE3FEF97FD59A /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-NotificationService/ExpoModulesProvider.swift"; sourceTree = ""; }; 7F26E81B24440D87004049C6 /* dummy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dummy.swift; sourceTree = ""; }; 7F554F822332D58B007CB9F7 /* Info.debug.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.debug.plist; path = Comm/Info.debug.plist; sourceTree = ""; }; 7F761E292201141E001B6FB7 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; 7F788C2B248AA2130098F071 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = SplashScreen.storyboard; sourceTree = ""; }; 7F8D601E26535E060053CB29 /* OpenSans-Semibold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-Semibold.ttf"; path = "Resources/OpenSans-Semibold.ttf"; sourceTree = ""; }; 7F8D601F26535E060053CB29 /* Anaheim-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "Anaheim-Regular.ttf"; path = "Resources/Anaheim-Regular.ttf"; sourceTree = ""; }; 7F8D602026535E060053CB29 /* OpenSans-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-Regular.ttf"; path = "Resources/OpenSans-Regular.ttf"; sourceTree = ""; }; 7F8D602626535EEE0053CB29 /* IBMPlexSans-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "IBMPlexSans-Regular.ttf"; path = "Resources/IBMPlexSans-Regular.ttf"; sourceTree = ""; }; 7F8D602726535EEE0053CB29 /* IBMPlexSans-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "IBMPlexSans-Bold.ttf"; path = "Resources/IBMPlexSans-Bold.ttf"; sourceTree = ""; }; 7FCEA2DC2444010B004017B1 /* Comm-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Comm-Bridging-Header.h"; sourceTree = ""; }; 7FCFD8BD1E81B8DF00629B0E /* Comm.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = Comm.entitlements; path = Comm/Comm.entitlements; sourceTree = ""; }; 891D1495EE1F375F3AF6C7ED /* Pods-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.debug.xcconfig"; sourceTree = ""; }; 8B99AF6D28D50D4800EB5ADB /* lib.rs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lib.rs.h; sourceTree = ""; }; 8B99B59928D50D4900EB5ADB /* cxx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cxx.h; sourceTree = ""; }; 8B99BAAB28D50F3000EB5ADB /* libnative_rust_library.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libnative_rust_library.a; path = ../native_rust_library/target/universal/release/libnative_rust_library.a; sourceTree = ""; }; 8B99BAAD28D511FF00EB5ADB /* lib.rs.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lib.rs.cc; sourceTree = ""; }; 8E43C32B291E5B4A009378F5 /* TerminateApp.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = TerminateApp.mm; path = Comm/TerminateApp.mm; sourceTree = ""; }; 8E43C32E291E5B9D009378F5 /* TerminateApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TerminateApp.h; path = ../cpp/CommonCpp/Tools/TerminateApp.h; sourceTree = ""; }; 913E5A7BDECB327E3DE11053 /* Pods-NotificationService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.release.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.release.xcconfig"; sourceTree = ""; }; 994BEBDD4E4959F69CEA0BC3 /* libPods-Comm.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Comm.a"; sourceTree = BUILT_PRODUCTS_DIR; }; B7055C6B26E477CF00BE0548 /* MessageStoreOperations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MessageStoreOperations.h; sourceTree = ""; }; B70FBC1226B047050040F480 /* Message.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Message.h; sourceTree = ""; }; B7162ABC28AAD461006588D3 /* CommIcons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = CommIcons.ttf; path = Resources/CommIcons.ttf; sourceTree = ""; }; B71AFF1E265EDD8600B22352 /* IBMPlexSans-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "IBMPlexSans-Medium.ttf"; path = "Resources/IBMPlexSans-Medium.ttf"; sourceTree = ""; }; B734D10F28ADD55200570D04 /* SWMansionIcons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = SWMansionIcons.ttf; path = Resources/SWMansionIcons.ttf; sourceTree = ""; }; B7906F692720905A009BBBF5 /* ThreadStoreOperations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ThreadStoreOperations.h; sourceTree = ""; }; B7906F6A27209091009BBBF5 /* OlmPersistAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OlmPersistAccount.h; sourceTree = ""; }; B7906F6B27209091009BBBF5 /* OlmPersistSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OlmPersistSession.h; sourceTree = ""; }; B7906F6C27209091009BBBF5 /* Thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Thread.h; sourceTree = ""; }; B7E937CA26F448E700022A7C /* Media.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Media.h; sourceTree = ""; }; C562A7004903539402D988CE /* Pods-Comm.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Comm.release.xcconfig"; path = "Target Support Files/Pods-Comm/Pods-Comm.release.xcconfig"; sourceTree = ""; }; CB30C12327D0ACF700FBE8DE /* NotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NotificationService.entitlements; sourceTree = ""; }; CB38B4792877179A00171182 /* NonBlockingLock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NonBlockingLock.h; path = Comm/TemporaryMessageStorage/NonBlockingLock.h; sourceTree = ""; }; CB38B47B287718A200171182 /* NonBlockingLock.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = NonBlockingLock.mm; path = Comm/TemporaryMessageStorage/NonBlockingLock.mm; sourceTree = ""; }; CB38B47C2877190100171182 /* EncryptedFileUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EncryptedFileUtils.h; path = Comm/TemporaryMessageStorage/EncryptedFileUtils.h; sourceTree = ""; }; CB38B47D2877194100171182 /* EncryptedFileUtils.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = EncryptedFileUtils.mm; path = Comm/TemporaryMessageStorage/EncryptedFileUtils.mm; sourceTree = ""; }; CB38B47E287719C500171182 /* TemporaryMessageStorage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TemporaryMessageStorage.h; path = Comm/TemporaryMessageStorage/TemporaryMessageStorage.h; sourceTree = ""; }; CB38B47F28771A3B00171182 /* TemporaryMessageStorage.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = TemporaryMessageStorage.mm; path = Comm/TemporaryMessageStorage/TemporaryMessageStorage.mm; sourceTree = ""; }; CB38F2AE286C6C870010535C /* MessageSpecs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MessageSpecs.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs.h; sourceTree = ""; }; CB38F2AF286C6C870010535C /* MessageOperationsUtilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MessageOperationsUtilities.cpp; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageOperationsUtilities.cpp; sourceTree = ""; }; CB38F2B0286C6C870010535C /* MessageOperationsUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MessageOperationsUtilities.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageOperationsUtilities.h; sourceTree = ""; }; CB38F2B2286C6C970010535C /* CreateThreadMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CreateThreadMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/CreateThreadMessageSpec.h; sourceTree = ""; }; CB38F2B3286C6C970010535C /* TextMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TextMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/TextMessageSpec.h; sourceTree = ""; }; CB38F2B4286C6C970010535C /* CreateSidebarMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CreateSidebarMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/CreateSidebarMessageSpec.h; sourceTree = ""; }; CB38F2B5286C6C970010535C /* ChangeRoleMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ChangeRoleMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/ChangeRoleMessageSpec.h; sourceTree = ""; }; CB38F2B6286C6C970010535C /* RestoreEntryMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RestoreEntryMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/RestoreEntryMessageSpec.h; sourceTree = ""; }; CB38F2B7286C6C970010535C /* MessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/MessageSpec.h; sourceTree = ""; }; CB38F2B8286C6C970010535C /* ChangeSettingsMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ChangeSettingsMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/ChangeSettingsMessageSpec.h; sourceTree = ""; }; CB38F2B9286C6C970010535C /* UnsupportedMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UnsupportedMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/UnsupportedMessageSpec.h; sourceTree = ""; }; CB38F2BA286C6C970010535C /* CreateEntryMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CreateEntryMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/CreateEntryMessageSpec.h; sourceTree = ""; }; CB38F2BB286C6C970010535C /* EditEntryMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EditEntryMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/EditEntryMessageSpec.h; sourceTree = ""; }; CB38F2BC286C6C970010535C /* CreateSubThreadMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CreateSubThreadMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/CreateSubThreadMessageSpec.h; sourceTree = ""; }; CB38F2BD286C6C970010535C /* MultimediaMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MultimediaMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/MultimediaMessageSpec.h; sourceTree = ""; }; CB38F2BE286C6C980010535C /* DeleteEntryMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeleteEntryMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/DeleteEntryMessageSpec.h; sourceTree = ""; }; CB38F2BF286C6C980010535C /* UpdateRelationshipMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UpdateRelationshipMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/UpdateRelationshipMessageSpec.h; sourceTree = ""; }; CB3C621327CE66540054F24C /* libEXSecureStore.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libEXSecureStore.a; sourceTree = BUILT_PRODUCTS_DIR; }; CBDEC69928ED859600C17588 /* GlobalDBSingleton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GlobalDBSingleton.h; sourceTree = ""; }; CBDEC69A28ED867000C17588 /* GlobalDBSingleton.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = GlobalDBSingleton.mm; path = Comm/GlobalDBSingleton.mm; sourceTree = ""; }; CBFE58272885852B003B94C9 /* ThreadOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadOperations.h; path = PersistentStorageUtilities/ThreadOperationsUtilities/ThreadOperations.h; sourceTree = ""; }; CBFE58282885852B003B94C9 /* ThreadOperations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadOperations.cpp; path = PersistentStorageUtilities/ThreadOperationsUtilities/ThreadOperations.cpp; sourceTree = ""; }; F53DA7B3F26C2798DCE74A94 /* Pods-Comm.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Comm.debug.xcconfig"; path = "Target Support Files/Pods-Comm/Pods-Comm.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 8B99BAAC28D50F3000EB5ADB /* libnative_rust_library.a in Frameworks */, 7F761E602201141E001B6FB7 /* JavaScriptCore.framework in Frameworks */, D7DB6E0F85B2DBE15B01EC21 /* libPods-Comm.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 713EE40326C6676B003D7C48 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 724995CE27B4103A00323FCE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 724995FB27BA9E8D00323FCE /* UserNotifications.framework in Frameworks */, F02C296C528B51ADAB5AA19D /* libPods-NotificationService.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 13B07FAE1A68108700A75B9A /* Comm */ = { isa = PBXGroup; children = ( 71B8CCB626BD30EC0040C0A2 /* CommCoreImplementations */, 7F788C2B248AA2130098F071 /* SplashScreen.storyboard */, 7FCFD8BD1E81B8DF00629B0E /* Comm.entitlements */, 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 13B07FB01A68108700A75B9A /* AppDelegate.mm */, 13B07FB51A68108700A75B9A /* Images.xcassets */, 7F554F822332D58B007CB9F7 /* Info.debug.plist */, 13B07FB61A68108700A75B9A /* Info.release.plist */, 13B07FB71A68108700A75B9A /* main.m */, 7FCEA2DC2444010B004017B1 /* Comm-Bridging-Header.h */, 7F26E81B24440D87004049C6 /* dummy.swift */, ); name = Comm; sourceTree = ""; }; 5F5A6FB2C6AD630620BBF58C /* NotificationService */ = { isa = PBXGroup; children = ( 769A87FB41BCE3FEF97FD59A /* ExpoModulesProvider.swift */, ); name = NotificationService; sourceTree = ""; }; 6534411766BE4CA4B0AB0A78 /* Resources */ = { isa = PBXGroup; children = ( B7162ABC28AAD461006588D3 /* CommIcons.ttf */, B734D10F28ADD55200570D04 /* SWMansionIcons.ttf */, 7F8D601F26535E060053CB29 /* Anaheim-Regular.ttf */, 7F8D602026535E060053CB29 /* OpenSans-Regular.ttf */, B71AFF1E265EDD8600B22352 /* IBMPlexSans-Medium.ttf */, 7F8D601E26535E060053CB29 /* OpenSans-Semibold.ttf */, 7F8D602726535EEE0053CB29 /* IBMPlexSans-Bold.ttf */, 7F8D602626535EEE0053CB29 /* IBMPlexSans-Regular.ttf */, ); name = Resources; sourceTree = ""; }; 713EE40726C6676B003D7C48 /* CommTests */ = { isa = PBXGroup; children = ( 713EE41026C66B80003D7C48 /* CryptoTest.mm */, 713EE40A26C6676B003D7C48 /* Info.plist */, ); path = CommTests; sourceTree = ""; }; 71B8CCB626BD30EC0040C0A2 /* CommCoreImplementations */ = { isa = PBXGroup; children = ( 8E43C32E291E5B9D009378F5 /* TerminateApp.h */, 8E43C32B291E5B4A009378F5 /* TerminateApp.mm */, CBDEC69A28ED867000C17588 /* GlobalDBSingleton.mm */, CB38B4782877177B00171182 /* TemporaryMessageStorage */, 71762A74270D8AAE00F565ED /* PlatformSpecificTools.mm */, 71D4D7CB26C50B1000FCDBCD /* CommSecureStore.mm */, 71142A7526C2650A0039DCBD /* CommSecureStoreIOSWrapper.h */, 71142A7626C2650A0039DCBD /* CommSecureStoreIOSWrapper.mm */, 71CA4AEA262F230A00835C89 /* Tools.h */, 71CA4AEB262F236100835C89 /* Tools.mm */, 71CA4A63262DA8E500835C89 /* Logger.mm */, ); name = CommCoreImplementations; sourceTree = ""; }; 71BE84362636A944002849D2 /* cpp */ = { isa = PBXGroup; children = ( 71BE84372636A944002849D2 /* CommonCpp */, 71BE84462636A944002849D2 /* third-party */, ); name = cpp; path = ../cpp; sourceTree = ""; }; 71BE84372636A944002849D2 /* CommonCpp */ = { isa = PBXGroup; children = ( 71F971B4270726C000DDC5BF /* _generated */, 71BF5B6A26B3FCFF00EDE27D /* CryptoTools */, 71BE84382636A944002849D2 /* Tools */, 71BE843A2636A944002849D2 /* NativeModules */, 71BE843F2636A944002849D2 /* DatabaseManagers */, ); path = CommonCpp; sourceTree = ""; }; 71BE84382636A944002849D2 /* Tools */ = { isa = PBXGroup; children = ( 71B8CCBD26BD4DEB0040C0A2 /* CommSecureStore.h */, 718DE99C2653D41C00365824 /* WorkerThread.cpp */, 718DE99D2653D41C00365824 /* WorkerThread.h */, 71BE84392636A944002849D2 /* Logger.h */, 71DC160C270C43D300822863 /* PlatformSpecificTools.h */, ); path = Tools; sourceTree = ""; }; 71BE843A2636A944002849D2 /* NativeModules */ = { isa = PBXGroup; children = ( CBED0E2C284E086100CD3863 /* PersistentStorageUtilities */, 726E5D722731A4240032361D /* InternalModules */, 71BE843C2636A944002849D2 /* CommCoreModule.cpp */, 71BE843E2636A944002849D2 /* CommCoreModule.h */, B7055C6B26E477CF00BE0548 /* MessageStoreOperations.h */, B7906F692720905A009BBBF5 /* ThreadStoreOperations.h */, ); path = NativeModules; sourceTree = ""; }; 71BE843F2636A944002849D2 /* DatabaseManagers */ = { isa = PBXGroup; children = ( 71BE84402636A944002849D2 /* DatabaseQueryExecutor.h */, 71BE84412636A944002849D2 /* SQLiteQueryExecutor.cpp */, 71BE84422636A944002849D2 /* SQLiteQueryExecutor.h */, 71BE84432636A944002849D2 /* DatabaseManager.h */, 71BE84442636A944002849D2 /* entities */, ); path = DatabaseManagers; sourceTree = ""; }; 71BE84442636A944002849D2 /* entities */ = { isa = PBXGroup; children = ( B7906F6A27209091009BBBF5 /* OlmPersistAccount.h */, B7906F6B27209091009BBBF5 /* OlmPersistSession.h */, B7906F6C27209091009BBBF5 /* Thread.h */, 71BE84452636A944002849D2 /* Draft.h */, B70FBC1226B047050040F480 /* Message.h */, B7E937CA26F448E700022A7C /* Media.h */, 2DDA0A22FECC9DAA5C19C35D /* Metadata.h */, ); path = entities; sourceTree = ""; }; 71BE84462636A944002849D2 /* third-party */ = { isa = PBXGroup; children = ( 71BE84472636A944002849D2 /* sqlite_orm */, ); path = "third-party"; sourceTree = ""; }; 71BE84472636A944002849D2 /* sqlite_orm */ = { isa = PBXGroup; children = ( 71BE84482636A944002849D2 /* sqlite_orm.h */, ); path = sqlite_orm; sourceTree = ""; }; 71BF5B6A26B3FCFF00EDE27D /* CryptoTools */ = { isa = PBXGroup; children = ( 75291F0328F9A0AE00F4C80E /* DeviceID.cpp */, 75291F0228F9A09E00F4C80E /* DeviceID.h */, 71BF5B7B26BBDA6100EDE27D /* CryptoModule.cpp */, 71BF5B7A26BBDA6000EDE27D /* CryptoModule.h */, 71BF5B6F26B3FF0900EDE27D /* Session.cpp */, 71BF5B7026B3FF0900EDE27D /* Session.h */, 71BF5B7226B3FFBC00EDE27D /* Persist.h */, 71BF5B7326B401D300EDE27D /* Tools.cpp */, 71BF5B7426B401D300EDE27D /* Tools.h */, ); path = CryptoTools; sourceTree = ""; }; 71F971B4270726C000DDC5BF /* _generated */ = { isa = PBXGroup; children = ( 71BE843D2636A944002849D2 /* NativeModules.h */, 71BE843B2636A944002849D2 /* NativeModules.cpp */, ); path = _generated; sourceTree = ""; }; 724995D227B4103A00323FCE /* NotificationService */ = { isa = PBXGroup; children = ( CB30C12327D0ACF700FBE8DE /* NotificationService.entitlements */, 724995D327B4103A00323FCE /* NotificationService.h */, 724995D427B4103A00323FCE /* NotificationService.mm */, 724995D627B4103A00323FCE /* Info.plist */, ); path = NotificationService; sourceTree = ""; }; 726E5D722731A4240032361D /* InternalModules */ = { isa = PBXGroup; children = ( CBDEC69928ED859600C17588 /* GlobalDBSingleton.h */, ); path = InternalModules; sourceTree = ""; }; 7FF0870B1E833C3F000A1ACF /* Frameworks */ = { isa = PBXGroup; children = ( 8B99BAAB28D50F3000EB5ADB /* libnative_rust_library.a */, CB3C621327CE66540054F24C /* libEXSecureStore.a */, 724995FA27BA9E8C00323FCE /* UserNotifications.framework */, 711CF80E25DC096000A00FBD /* libFolly.a */, 7F761E292201141E001B6FB7 /* JavaScriptCore.framework */, 994BEBDD4E4959F69CEA0BC3 /* libPods-Comm.a */, 3EE4DCB430B05EC9DE7D7B01 /* libPods-NotificationService.a */, ); name = Frameworks; sourceTree = ""; }; 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( 8B99AF6B28D50D4800EB5ADB /* native_rust_library */, 71BE84362636A944002849D2 /* cpp */, 13B07FAE1A68108700A75B9A /* Comm */, 713EE40726C6676B003D7C48 /* CommTests */, 724995D227B4103A00323FCE /* NotificationService */, 83CBBA001A601CBA00E9B192 /* Products */, 6534411766BE4CA4B0AB0A78 /* Resources */, 7FF0870B1E833C3F000A1ACF /* Frameworks */, D533B93718E3B9684B508006 /* Pods */, AFF3F1F76178B42122C79BDE /* ExpoModulesProviders */, ); indentWidth = 2; sourceTree = ""; tabWidth = 2; }; 83CBBA001A601CBA00E9B192 /* Products */ = { isa = PBXGroup; children = ( 13B07F961A680F5B00A75B9A /* Comm.app */, 713EE40626C6676B003D7C48 /* CommTests.xctest */, 724995D127B4103A00323FCE /* NotificationService.appex */, ); name = Products; sourceTree = ""; }; 8B99AF6B28D50D4800EB5ADB /* native_rust_library */ = { isa = PBXGroup; children = ( 8B99BAAD28D511FF00EB5ADB /* lib.rs.cc */, 8B99AF6D28D50D4800EB5ADB /* lib.rs.h */, 8B99B59928D50D4900EB5ADB /* cxx.h */, ); name = native_rust_library; path = ../native_rust_library; sourceTree = ""; }; AFF3F1F76178B42122C79BDE /* ExpoModulesProviders */ = { isa = PBXGroup; children = ( E75E6E4967CE9A8BBA89ED86 /* Comm */, 5F5A6FB2C6AD630620BBF58C /* NotificationService */, ); name = ExpoModulesProviders; sourceTree = ""; }; CB38B4782877177B00171182 /* TemporaryMessageStorage */ = { isa = PBXGroup; children = ( CB38B47F28771A3B00171182 /* TemporaryMessageStorage.mm */, CB38B47E287719C500171182 /* TemporaryMessageStorage.h */, CB38B47D2877194100171182 /* EncryptedFileUtils.mm */, CB38B47C2877190100171182 /* EncryptedFileUtils.h */, CB38B47B287718A200171182 /* NonBlockingLock.mm */, CB38B4792877179A00171182 /* NonBlockingLock.h */, ); name = TemporaryMessageStorage; sourceTree = ""; }; CB38F2AC286C6C010010535C /* MessageOperationsUtilities */ = { isa = PBXGroup; children = ( CB38F2AF286C6C870010535C /* MessageOperationsUtilities.cpp */, CB38F2B0286C6C870010535C /* MessageOperationsUtilities.h */, CB38F2AE286C6C870010535C /* MessageSpecs.h */, CB38F2AD286C6C4B0010535C /* MessageSpecs */, ); name = MessageOperationsUtilities; sourceTree = ""; }; CB38F2AD286C6C4B0010535C /* MessageSpecs */ = { isa = PBXGroup; children = ( CB38F2B5286C6C970010535C /* ChangeRoleMessageSpec.h */, CB38F2B8286C6C970010535C /* ChangeSettingsMessageSpec.h */, CB38F2BA286C6C970010535C /* CreateEntryMessageSpec.h */, CB38F2B4286C6C970010535C /* CreateSidebarMessageSpec.h */, CB38F2BC286C6C970010535C /* CreateSubThreadMessageSpec.h */, CB38F2B2286C6C970010535C /* CreateThreadMessageSpec.h */, CB38F2BE286C6C980010535C /* DeleteEntryMessageSpec.h */, CB38F2BB286C6C970010535C /* EditEntryMessageSpec.h */, CB38F2B7286C6C970010535C /* MessageSpec.h */, CB38F2BD286C6C970010535C /* MultimediaMessageSpec.h */, CB38F2B6286C6C970010535C /* RestoreEntryMessageSpec.h */, CB38F2B3286C6C970010535C /* TextMessageSpec.h */, CB38F2B9286C6C970010535C /* UnsupportedMessageSpec.h */, CB38F2BF286C6C980010535C /* UpdateRelationshipMessageSpec.h */, ); name = MessageSpecs; sourceTree = ""; }; CBED0E2C284E086100CD3863 /* PersistentStorageUtilities */ = { isa = PBXGroup; children = ( CBFE582628858512003B94C9 /* ThreadOperationsUtilities */, CB38F2AC286C6C010010535C /* MessageOperationsUtilities */, ); name = PersistentStorageUtilities; sourceTree = ""; }; CBFE582628858512003B94C9 /* ThreadOperationsUtilities */ = { isa = PBXGroup; children = ( CBFE58282885852B003B94C9 /* ThreadOperations.cpp */, CBFE58272885852B003B94C9 /* ThreadOperations.h */, ); name = ThreadOperationsUtilities; sourceTree = ""; }; D533B93718E3B9684B508006 /* Pods */ = { isa = PBXGroup; children = ( F53DA7B3F26C2798DCE74A94 /* Pods-Comm.debug.xcconfig */, C562A7004903539402D988CE /* Pods-Comm.release.xcconfig */, 891D1495EE1F375F3AF6C7ED /* Pods-NotificationService.debug.xcconfig */, 913E5A7BDECB327E3DE11053 /* Pods-NotificationService.release.xcconfig */, ); path = Pods; sourceTree = ""; }; E75E6E4967CE9A8BBA89ED86 /* Comm */ = { isa = PBXGroup; children = ( 3EEB3E70587B0ADAD05237B0 /* ExpoModulesProvider.swift */, ); name = Comm; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 13B07F861A680F5B00A75B9A /* Comm */ = { isa = PBXNativeTarget; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Comm" */; buildPhases = ( 02DE093B3C1DDF10C1FA3E9C /* [CP] Check Pods Manifest.lock */, 8BF9F24E28B795E200E20C13 /* Build Rust library */, 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, DB38BFA0686C805CE44F051F /* [CP] Copy Pods Resources */, EA2E8897D838D7F3E680EACE /* [CP] Embed Pods Frameworks */, 724995DA27B4103A00323FCE /* Embed App Extensions */, ); buildRules = ( ); dependencies = ( 724995D827B4103A00323FCE /* PBXTargetDependency */, ); name = Comm; productName = "Hello World"; productReference = 13B07F961A680F5B00A75B9A /* Comm.app */; productType = "com.apple.product-type.application"; }; 713EE40526C6676B003D7C48 /* CommTests */ = { isa = PBXNativeTarget; buildConfigurationList = 713EE40F26C6676B003D7C48 /* Build configuration list for PBXNativeTarget "CommTests" */; buildPhases = ( 713EE40226C6676B003D7C48 /* Sources */, 713EE40326C6676B003D7C48 /* Frameworks */, 713EE40426C6676B003D7C48 /* Resources */, ); buildRules = ( ); dependencies = ( 713EE40C26C6676B003D7C48 /* PBXTargetDependency */, ); name = CommTests; productName = CommTests; productReference = 713EE40626C6676B003D7C48 /* CommTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 724995D027B4103A00323FCE /* NotificationService */ = { isa = PBXNativeTarget; buildConfigurationList = 724995DD27B4103A00323FCE /* Build configuration list for PBXNativeTarget "NotificationService" */; buildPhases = ( 6735FA74B2C82E3B27E18258 /* [CP] Check Pods Manifest.lock */, 724995CD27B4103A00323FCE /* Sources */, 724995CE27B4103A00323FCE /* Frameworks */, 724995CF27B4103A00323FCE /* Resources */, E6221695BEF4548AF41DD8EB /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = NotificationService; productName = NotificationService; productReference = 724995D127B4103A00323FCE /* NotificationService.appex */; productType = "com.apple.product-type.app-extension"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 83CBB9F71A601CBA00E9B192 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1150; ORGANIZATIONNAME = "Comm Technologies, Inc."; TargetAttributes = { 13B07F861A680F5B00A75B9A = { DevelopmentTeam = H98Y8MH53M; LastSwiftMigration = 1140; ProvisioningStyle = Automatic; SystemCapabilities = { com.apple.BackgroundModes = { enabled = 1; }; com.apple.GameCenter = { enabled = 0; }; com.apple.InAppPurchase = { enabled = 0; }; com.apple.Keychain = { enabled = 1; }; com.apple.Push = { enabled = 1; }; com.apple.SafariKeychain = { enabled = 1; }; }; }; 713EE40526C6676B003D7C48 = { CreatedOnToolsVersion = 12.5.1; ProvisioningStyle = Automatic; TestTargetID = 13B07F861A680F5B00A75B9A; }; 724995D027B4103A00323FCE = { CreatedOnToolsVersion = 13.0; DevelopmentTeam = H98Y8MH53M; ProvisioningStyle = Automatic; }; }; }; buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Comm" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( English, en, Base, ); mainGroup = 83CBB9F61A601CBA00E9B192; productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 13B07F861A680F5B00A75B9A /* Comm */, 713EE40526C6676B003D7C48 /* CommTests */, 724995D027B4103A00323FCE /* NotificationService */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 13B07F8E1A680F5B00A75B9A /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 7F8D602926535F2A0053CB29 /* IBMPlexSans-Regular.ttf in Resources */, 7F8D602826535F240053CB29 /* IBMPlexSans-Bold.ttf in Resources */, 7F8D602126535E060053CB29 /* OpenSans-Semibold.ttf in Resources */, 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, 7F788C2C248AA2140098F071 /* SplashScreen.storyboard in Resources */, B7162ABD28AAD461006588D3 /* CommIcons.ttf in Resources */, 7F8D602226535E060053CB29 /* Anaheim-Regular.ttf in Resources */, B71AFF1F265EDD8600B22352 /* IBMPlexSans-Medium.ttf in Resources */, 7F8D602326535E060053CB29 /* OpenSans-Regular.ttf in Resources */, B734D11028ADD55200570D04 /* SWMansionIcons.ttf in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 713EE40426C6676B003D7C48 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 724995CF27B4103A00323FCE /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "$(SRCROOT)/.xcode.env.local", "$(SRCROOT)/.xcode.env", ); name = "Bundle React Native code and images"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; }; 02DE093B3C1DDF10C1FA3E9C /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-Comm-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; 6735FA74B2C82E3B27E18258 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-NotificationService-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; 8BF9F24E28B795E200E20C13 /* Build Rust library */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( ); name = "Build Rust library"; outputFileListPaths = ( ); outputPaths = ( "${SRCROOT}/../native_rust_library/lib.rs.cc", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "${SRCROOT}/../../scripts/build-rust-native-library.sh\n"; }; DB38BFA0686C805CE44F051F /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Comm/Pods-Comm-resources.sh", "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Entypo.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Feather.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Brands.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Regular.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Solid.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Fontisto.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Foundation.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Octicons.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Zocial.ttf", "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-launcher/EXDevLauncher.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-menu/EXDevMenu.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Entypo.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EvilIcons.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Feather.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Brands.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Regular.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Solid.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Fontisto.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Foundation.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Ionicons.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialCommunityIcons.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Octicons.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SimpleLineIcons.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Zocial.ttf", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevLauncher.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevMenu.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Comm/Pods-Comm-resources.sh\"\n"; showEnvVarsInLog = 0; }; E6221695BEF4548AF41DD8EB /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-NotificationService/Pods-NotificationService-resources.sh", "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Entypo.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Feather.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Brands.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Regular.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Solid.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Fontisto.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Foundation.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Octicons.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf", - "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Zocial.ttf", "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-launcher/EXDevLauncher.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-menu/EXDevMenu.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Entypo.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EvilIcons.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Feather.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Brands.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Regular.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Solid.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Fontisto.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Foundation.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Ionicons.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialCommunityIcons.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Octicons.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SimpleLineIcons.ttf", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Zocial.ttf", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevLauncher.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevMenu.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NotificationService/Pods-NotificationService-resources.sh\"\n"; showEnvVarsInLog = 0; }; EA2E8897D838D7F3E680EACE /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Comm/Pods-Comm-frameworks.sh", "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/hermes.framework/hermes", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Comm/Pods-Comm-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 13B07F871A680F5B00A75B9A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 7F0C6E31291C4468002AA2D9 /* ExpoModulesProvider.swift in Sources */, 75291F0428F9A0D400F4C80E /* DeviceID.cpp in Sources */, 8E43C32C291E5B4A009378F5 /* TerminateApp.mm in Sources */, CB38B48628771CDD00171182 /* TemporaryMessageStorage.mm in Sources */, CB38B48428771CAF00171182 /* EncryptedFileUtils.mm in Sources */, CBFE58292885852B003B94C9 /* ThreadOperations.cpp in Sources */, CB38B48228771C7A00171182 /* NonBlockingLock.mm in Sources */, 718DE99E2653D41C00365824 /* WorkerThread.cpp in Sources */, 8B99BAAE28D511FF00EB5ADB /* lib.rs.cc in Sources */, 71CA4AEC262F236100835C89 /* Tools.mm in Sources */, 71762A75270D8AAE00F565ED /* PlatformSpecificTools.mm in Sources */, 71BF5B7126B3FF0900EDE27D /* Session.cpp in Sources */, 71BF5B7526B401D300EDE27D /* Tools.cpp in Sources */, 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */, 71142A7726C2650B0039DCBD /* CommSecureStoreIOSWrapper.mm in Sources */, CB38F2B1286C6C870010535C /* MessageOperationsUtilities.cpp in Sources */, 71BE84492636A944002849D2 /* NativeModules.cpp in Sources */, 71CA4A64262DA8E500835C89 /* Logger.mm in Sources */, 71BF5B7F26BBDD7400EDE27D /* CryptoModule.cpp in Sources */, 71BE844A2636A944002849D2 /* CommCoreModule.cpp in Sources */, 71D4D7CC26C50B1000FCDBCD /* CommSecureStore.mm in Sources */, 711B408425DA97F9005F8F06 /* dummy.swift in Sources */, CBDEC69B28ED867000C17588 /* GlobalDBSingleton.mm in Sources */, 13B07FC11A68108700A75B9A /* main.m in Sources */, 71BE844B2636A944002849D2 /* SQLiteQueryExecutor.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 713EE40226C6676B003D7C48 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 713EE41126C66B80003D7C48 /* CryptoTest.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 724995CD27B4103A00323FCE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( CB38B48728771CE500171182 /* TemporaryMessageStorage.mm in Sources */, CB38B48528771CB800171182 /* EncryptedFileUtils.mm in Sources */, CB38B48328771C8300171182 /* NonBlockingLock.mm in Sources */, CB38F2C0286C6CDF0010535C /* MessageOperationsUtilities.cpp in Sources */, CB1648AF27CFBE6A00394D9D /* CryptoModule.cpp in Sources */, CB4821B227CFB20E001AB7E1 /* SQLiteQueryExecutor.cpp in Sources */, CB4821AE27CFB187001AB7E1 /* Tools.cpp in Sources */, CB4821AC27CFB17C001AB7E1 /* Session.cpp in Sources */, CB4821A927CFB153001AB7E1 /* WorkerThread.cpp in Sources */, CB4821AA27CFB153001AB7E1 /* Tools.mm in Sources */, CB4821A527CF9F38001AB7E1 /* CommSecureStore.mm in Sources */, CB3C621227CE65030054F24C /* CommSecureStoreIOSWrapper.mm in Sources */, CB3C621127CE4A320054F24C /* Logger.mm in Sources */, 724995D527B4103A00323FCE /* NotificationService.mm in Sources */, CB4821AF27CFB19D001AB7E1 /* PlatformSpecificTools.mm in Sources */, 1F537ACC7B60DC049C0ECFA7 /* ExpoModulesProvider.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 713EE40C26C6676B003D7C48 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 13B07F861A680F5B00A75B9A /* Comm */; targetProxy = 713EE40B26C6676B003D7C48 /* PBXContainerItemProxy */; }; 724995D827B4103A00323FCE /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 724995D027B4103A00323FCE /* NotificationService */; targetProxy = 724995D727B4103A00323FCE /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 13B07F941A680F5B00A75B9A /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = F53DA7B3F26C2798DCE74A94 /* Pods-Comm.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_ENABLE_MODULES = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES; CODE_SIGN_ENTITLEMENTS = Comm/Comm.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = H98Y8MH53M; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "COCOAPODS=1", "FB_SONARKIT_ENABLED=1", "SD_WEBP=1", ); HEADER_SEARCH_PATHS = ( "$(inherited)", "$(SRCROOT)/../node_modules/react-native/Libraries/LinkingIOS", "$(PODS_ROOT)/boost-for-react-native", "$(SRCROOT)/../native_rust_library", "$(PODS_ROOT)/Headers/Private/React-bridging/react/bridging", ); INFOPLIST_FILE = Comm/Info.debug.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); LIBRARY_SEARCH_PATHS = ( "$(SDKROOT)/usr/lib/swift", "$(inherited)", "\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/CocoaAsyncSocket\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/DVAssetLoaderDelegate\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXApplication\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXFont\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXHaptics\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXImageLoader\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXImageManipulator\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXKeepAwake\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXSecureStore\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/ExpoModulesCore\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/FBReactNativeSpec\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/OLMKit\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/Protobuf-C++\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RCTTypeSafety\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNCClipboard\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNCMaskedView\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNDeviceInfo\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNExitApp\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNFS\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNFastImage\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNGestureHandler\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNKeychain\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNReanimated\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNSVG\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNScreens\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNVectorIcons\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-Core\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-CoreModules\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTAnimation\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTBlob\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTImage\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTLinking\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTNetwork\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTSettings\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTText\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTVibration\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-hermes\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsi\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsiexecutor\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsinspector\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-logger\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-perflogger\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeART\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeDarkMode\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeKeyboardInput\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeKeyboardTrackingView\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/SDWebImageWebPCoder\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/SPTPersistentCache\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/SQLCipher-Amalgamation\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/Yoga\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/YogaKit\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/abseil\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/fmt\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-C++\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-Core\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/glog\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/libevent\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/libwebp\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/lottie-react-native\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-background-upload\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-camera\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-ffmpeg\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-in-app-message\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-netinfo\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-notifications\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-orientation-locker\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-safe-area-context\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-video\"", /usr/lib/swift, "$(SRCROOT)/../native_rust_library/target/universal/release", ); OTHER_CPLUSPLUSFLAGS = ( "-DFOLLY_MOBILE=1", "-DFOLLY_NO_CONFIG", "-DFOLLY_USE_LIBCPP=1", "-DRNVERSION=70", "-fcxx-modules", "-fmodules", ); OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = app.comm; PRODUCT_NAME = Comm; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Comm-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; USE_HEADERMAP = YES; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 13B07F951A680F5B00A75B9A /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = C562A7004903539402D988CE /* Pods-Comm.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_ENABLE_MODULES = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES; CODE_SIGN_ENTITLEMENTS = Comm/Comm.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = H98Y8MH53M; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; HEADER_SEARCH_PATHS = ( "$(inherited)", "$(SRCROOT)/../node_modules/react-native/Libraries/LinkingIOS", "$(PODS_ROOT)/boost-for-react-native", "$(SRCROOT)/../native_rust_library", "$(PODS_ROOT)/Headers/Private/React-bridging/react/bridging", ); INFOPLIST_FILE = Comm/Info.release.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); LIBRARY_SEARCH_PATHS = ( "$(SDKROOT)/usr/lib/swift", "$(inherited)", "\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/CocoaAsyncSocket\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/DVAssetLoaderDelegate\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXApplication\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXFont\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXHaptics\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXImageLoader\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXImageManipulator\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXKeepAwake\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/EXSecureStore\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/ExpoModulesCore\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/FBReactNativeSpec\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/OLMKit\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/Protobuf-C++\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RCTTypeSafety\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNCClipboard\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNCMaskedView\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNDeviceInfo\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNExitApp\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNFS\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNFastImage\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNGestureHandler\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNKeychain\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNReanimated\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNSVG\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNScreens\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/RNVectorIcons\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-Core\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-CoreModules\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTAnimation\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTBlob\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTImage\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTLinking\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTNetwork\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTSettings\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTText\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTVibration\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-hermes\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsi\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsiexecutor\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsinspector\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-logger\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-perflogger\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeART\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeDarkMode\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeKeyboardInput\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeKeyboardTrackingView\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/SDWebImageWebPCoder\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/SPTPersistentCache\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/SQLCipher-Amalgamation\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/Yoga\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/YogaKit\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/abseil\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/fmt\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-C++\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-Core\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/glog\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/libevent\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/libwebp\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/lottie-react-native\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-background-upload\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-camera\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-ffmpeg\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-in-app-message\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-netinfo\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-notifications\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-orientation-locker\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-safe-area-context\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-video\"", /usr/lib/swift, "$(SRCROOT)/../native_rust_library/target/universal/release", ); ONLY_ACTIVE_ARCH = YES; OTHER_CPLUSPLUSFLAGS = ( "-DFOLLY_MOBILE=1", "-DFOLLY_NO_CONFIG", "-DFOLLY_USE_LIBCPP=1", "-DRNVERSION=70", "-fcxx-modules", "-fmodules", ); OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE"; PRODUCT_BUNDLE_IDENTIFIER = app.comm; PRODUCT_NAME = Comm; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Comm-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; USE_HEADERMAP = YES; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; 713EE40D26C6676B003D7C48 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; DEBUG_INFORMATION_FORMAT = dwarf; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64"; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = CommTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.5; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = swm.CommTests; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Comm.app/Comm"; USER_HEADER_SEARCH_PATHS = ( ../../node_modules/olm/include, ../../node_modules/olm/lib, "${PODS_ROOT}/OLMKit/include", "${PODS_ROOT}/OLMKit/lib", ); }; name = Debug; }; 713EE40E26C6676B003D7C48 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64"; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = CommTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.5; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); MTL_FAST_MATH = YES; OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE"; PRODUCT_BUNDLE_IDENTIFIER = swm.CommTests; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Comm.app/Comm"; USER_HEADER_SEARCH_PATHS = ( ../../node_modules/olm/include, ../../node_modules/olm/lib, "${PODS_ROOT}/OLMKit/include", "${PODS_ROOT}/OLMKit/lib", ); }; name = Release; }; 724995DB27B4103A00323FCE /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 891D1495EE1F375F3AF6C7ED /* Pods-NotificationService.debug.xcconfig */; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 166; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = H98Y8MH53M; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = NotificationService/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = NotificationService; INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Comm Technologies, Inc. All rights reserved."; IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); MARKETING_VERSION = 1.0.166; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_CFLAGS = ( "$(inherited)", "-DSQLITE_HAS_CODEC", "-DFOLLY_MOBILE=1", "-DFOLLY_NO_CONFIG", "-DFOLLY_USE_LIBCPP=1", "-DSQLITE_TEMP_STORE=2", "-DSQLCIPHER_CRYPTO_OPENSSL", ); OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = app.comm.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; }; name = Debug; }; 724995DC27B4103A00323FCE /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 913E5A7BDECB327E3DE11053 /* Pods-NotificationService.release.xcconfig */; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 166; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = H98Y8MH53M; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = NotificationService/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = NotificationService; INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Comm Technologies, Inc. All rights reserved."; IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); MARKETING_VERSION = 1.0.166; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = ( "$(inherited)", "-DSQLITE_HAS_CODEC", "-DFOLLY_MOBILE=1", "-DFOLLY_NO_CONFIG", "-DFOLLY_USE_LIBCPP=1", "-DSQLITE_TEMP_STORE=2", "-DSQLCIPHER_CRYPTO_OPENSSL", ); OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE"; PRODUCT_BUNDLE_IDENTIFIER = app.comm.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; }; name = Release; }; 83CBBA201A601CBA00E9B192 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "FB_SONARKIT_ENABLED=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_MOBILE=1", "-DFOLLY_NO_CONFIG", "-DFOLLY_USE_LIBCPP=1", "-fcxx-modules", "-fmodules", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; }; name = Debug; }; 83CBBA211A601CBA00E9B192 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_MOBILE=1", "-DFOLLY_NO_CONFIG", "-DFOLLY_USE_LIBCPP=1", "-fcxx-modules", "-fmodules", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; VALIDATE_PRODUCT = YES; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Comm" */ = { isa = XCConfigurationList; buildConfigurations = ( 13B07F941A680F5B00A75B9A /* Debug */, 13B07F951A680F5B00A75B9A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 713EE40F26C6676B003D7C48 /* Build configuration list for PBXNativeTarget "CommTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 713EE40D26C6676B003D7C48 /* Debug */, 713EE40E26C6676B003D7C48 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 724995DD27B4103A00323FCE /* Build configuration list for PBXNativeTarget "NotificationService" */ = { isa = XCConfigurationList; buildConfigurations = ( 724995DB27B4103A00323FCE /* Debug */, 724995DC27B4103A00323FCE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Comm" */ = { isa = XCConfigurationList; buildConfigurations = ( 83CBBA201A601CBA00E9B192 /* Debug */, 83CBBA211A601CBA00E9B192 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; } diff --git a/native/ios/Podfile.lock b/native/ios/Podfile.lock index 213bb8755..08eea7298 100644 --- a/native/ios/Podfile.lock +++ b/native/ios/Podfile.lock @@ -1,919 +1,913 @@ PODS: - boost (1.76.0) - DoubleConversion (1.1.6) - DVAssetLoaderDelegate (0.3.3) - EXApplication (5.0.1): - ExpoModulesCore - EXConstants (14.0.2): - ExpoModulesCore - EXFileSystem (15.1.1): - ExpoModulesCore - EXFont (11.0.1): - ExpoModulesCore - EXImageLoader (4.0.0): - ExpoModulesCore - React-Core - EXJSONUtils (0.4.0) - EXManifests (0.4.0): - EXJSONUtils - EXMediaLibrary (15.0.0): - ExpoModulesCore - React-Core - Expo (47.0.8): - ExpoModulesCore - expo-dev-client (2.0.1): - EXManifests - expo-dev-launcher - expo-dev-menu - expo-dev-menu-interface - EXUpdatesInterface - expo-dev-launcher (2.0.2): - EXManifests - expo-dev-launcher/Main (= 2.0.2) - expo-dev-menu - expo-dev-menu-interface - ExpoModulesCore - EXUpdatesInterface - React-Core - expo-dev-launcher/Main (2.0.2): - EXManifests - expo-dev-launcher/Unsafe - expo-dev-menu - expo-dev-menu-interface - ExpoModulesCore - EXUpdatesInterface - React-Core - expo-dev-launcher/Unsafe (2.0.2): - EXManifests - expo-dev-menu - expo-dev-menu-interface - ExpoModulesCore - EXUpdatesInterface - React-Core - expo-dev-menu (2.0.2): - expo-dev-menu/Main (= 2.0.2) - expo-dev-menu-interface (1.0.0) - expo-dev-menu/GestureHandler (2.0.2) - expo-dev-menu/Main (2.0.2): - EXManifests - expo-dev-menu-interface - expo-dev-menu/Vendored - ExpoModulesCore - React-Core - expo-dev-menu/Reanimated (2.0.2): - DoubleConversion - FBLazyVector - FBReactNativeSpec - glog - RCT-Folly - RCTRequired - RCTTypeSafety - React-callinvoker - React-Core - React-Core/DevSupport - React-Core/RCTWebSocket - React-CoreModules - React-cxxreact - React-jsi - React-jsiexecutor - React-jsinspector - React-RCTActionSheet - React-RCTAnimation - React-RCTBlob - React-RCTImage - React-RCTLinking - React-RCTNetwork - React-RCTSettings - React-RCTText - React-RCTVibration - ReactCommon/turbomodule/core - Yoga - expo-dev-menu/SafeAreaView (2.0.2) - expo-dev-menu/Vendored (2.0.2): - expo-dev-menu/GestureHandler - expo-dev-menu/Reanimated - expo-dev-menu/SafeAreaView - ExpoHaptics (12.0.1): - ExpoModulesCore - ExpoImageManipulator (11.0.0): - EXImageLoader - ExpoModulesCore - ExpoKeepAwake (11.0.1): - ExpoModulesCore - ExpoModulesCore (1.0.3): - React-Core - ReactCommon/turbomodule/core - EXSecureStore (12.0.0): - ExpoModulesCore - EXSplashScreen (0.17.5): - ExpoModulesCore - React-Core - EXUpdatesInterface (0.8.1) - FBLazyVector (0.70.6) - FBReactNativeSpec (0.70.6): - RCT-Folly (= 2021.07.22.00) - RCTRequired (= 0.70.6) - RCTTypeSafety (= 0.70.6) - React-Core (= 0.70.6) - React-jsi (= 0.70.6) - ReactCommon/turbomodule/core (= 0.70.6) - fmt (6.2.1) - glog (0.3.5) - hermes-engine (0.70.6) - libevent (2.1.12) - libwebp (1.2.3): - libwebp/demux (= 1.2.3) - libwebp/mux (= 1.2.3) - libwebp/webp (= 1.2.3) - libwebp/demux (1.2.3): - libwebp/webp - libwebp/mux (1.2.3): - libwebp/demux - libwebp/webp (1.2.3) - lottie-ios (3.1.8) - lottie-react-native (4.0.2): - lottie-ios (~> 3.1.8) - React-Core - mobile-ffmpeg-min (4.3.1.LTS) - OLMKit (3.2.4): - OLMKit/olmc (= 3.2.4) - OLMKit/olmcpp (= 3.2.4) - OLMKit/olmc (3.2.4) - OLMKit/olmcpp (3.2.4) - OpenSSL-Universal (1.1.1900) - RCT-Folly (2021.07.22.00): - boost - DoubleConversion - fmt (~> 6.2.1) - glog - RCT-Folly/Default (= 2021.07.22.00) - RCT-Folly/Default (2021.07.22.00): - boost - DoubleConversion - fmt (~> 6.2.1) - glog - RCT-Folly/Futures (2021.07.22.00): - boost - DoubleConversion - fmt (~> 6.2.1) - glog - libevent - RCTRequired (0.70.6) - RCTTypeSafety (0.70.6): - FBLazyVector (= 0.70.6) - RCTRequired (= 0.70.6) - React-Core (= 0.70.6) - React (0.70.6): - React-Core (= 0.70.6) - React-Core/DevSupport (= 0.70.6) - React-Core/RCTWebSocket (= 0.70.6) - React-RCTActionSheet (= 0.70.6) - React-RCTAnimation (= 0.70.6) - React-RCTBlob (= 0.70.6) - React-RCTImage (= 0.70.6) - React-RCTLinking (= 0.70.6) - React-RCTNetwork (= 0.70.6) - React-RCTSettings (= 0.70.6) - React-RCTText (= 0.70.6) - React-RCTVibration (= 0.70.6) - React-bridging (0.70.6): - RCT-Folly (= 2021.07.22.00) - React-jsi (= 0.70.6) - React-callinvoker (0.70.6) - React-Codegen (0.70.6): - FBReactNativeSpec (= 0.70.6) - RCT-Folly (= 2021.07.22.00) - RCTRequired (= 0.70.6) - RCTTypeSafety (= 0.70.6) - React-Core (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - ReactCommon/turbomodule/core (= 0.70.6) - React-Core (0.70.6): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default (= 0.70.6) - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - React-perflogger (= 0.70.6) - Yoga - React-Core/CoreModulesHeaders (0.70.6): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - React-perflogger (= 0.70.6) - Yoga - React-Core/Default (0.70.6): - glog - RCT-Folly (= 2021.07.22.00) - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - React-perflogger (= 0.70.6) - Yoga - React-Core/DevSupport (0.70.6): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default (= 0.70.6) - React-Core/RCTWebSocket (= 0.70.6) - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - React-jsinspector (= 0.70.6) - React-perflogger (= 0.70.6) - Yoga - React-Core/RCTActionSheetHeaders (0.70.6): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - React-perflogger (= 0.70.6) - Yoga - React-Core/RCTAnimationHeaders (0.70.6): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - React-perflogger (= 0.70.6) - Yoga - React-Core/RCTBlobHeaders (0.70.6): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - React-perflogger (= 0.70.6) - Yoga - React-Core/RCTImageHeaders (0.70.6): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - React-perflogger (= 0.70.6) - Yoga - React-Core/RCTLinkingHeaders (0.70.6): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - React-perflogger (= 0.70.6) - Yoga - React-Core/RCTNetworkHeaders (0.70.6): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - React-perflogger (= 0.70.6) - Yoga - React-Core/RCTSettingsHeaders (0.70.6): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - React-perflogger (= 0.70.6) - Yoga - React-Core/RCTTextHeaders (0.70.6): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - React-perflogger (= 0.70.6) - Yoga - React-Core/RCTVibrationHeaders (0.70.6): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - React-perflogger (= 0.70.6) - Yoga - React-Core/RCTWebSocket (0.70.6): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default (= 0.70.6) - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - React-perflogger (= 0.70.6) - Yoga - React-CoreModules (0.70.6): - RCT-Folly (= 2021.07.22.00) - RCTTypeSafety (= 0.70.6) - React-Codegen (= 0.70.6) - React-Core/CoreModulesHeaders (= 0.70.6) - React-jsi (= 0.70.6) - React-RCTImage (= 0.70.6) - ReactCommon/turbomodule/core (= 0.70.6) - React-cxxreact (0.70.6): - boost (= 1.76.0) - DoubleConversion - glog - RCT-Folly (= 2021.07.22.00) - React-callinvoker (= 0.70.6) - React-jsi (= 0.70.6) - React-jsinspector (= 0.70.6) - React-logger (= 0.70.6) - React-perflogger (= 0.70.6) - React-runtimeexecutor (= 0.70.6) - React-hermes (0.70.6): - DoubleConversion - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) - RCT-Folly/Futures (= 2021.07.22.00) - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-jsiexecutor (= 0.70.6) - React-jsinspector (= 0.70.6) - React-perflogger (= 0.70.6) - React-jsi (0.70.6): - boost (= 1.76.0) - DoubleConversion - glog - RCT-Folly (= 2021.07.22.00) - React-jsi/Default (= 0.70.6) - React-jsi/Default (0.70.6): - boost (= 1.76.0) - DoubleConversion - glog - RCT-Folly (= 2021.07.22.00) - React-jsiexecutor (0.70.6): - DoubleConversion - glog - RCT-Folly (= 2021.07.22.00) - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-perflogger (= 0.70.6) - React-jsinspector (0.70.6) - React-logger (0.70.6): - glog - react-native-background-upload (6.5.1): - React - react-native-camera (3.31.0): - React - react-native-camera/RCT (= 3.31.0) - react-native-camera/RN (= 3.31.0) - react-native-camera/RCT (3.31.0): - React - react-native-camera/RN (3.31.0): - React - react-native-ffmpeg/min-lts (0.4.4): - mobile-ffmpeg-min (= 4.3.1.LTS) - React - react-native-in-app-message (1.0.2): - React - react-native-netinfo (6.0.0): - React-Core - react-native-notifications (1.1.19): - React - react-native-orientation-locker (1.1.6): - React - react-native-pager-view (6.0.1): - React-Core - react-native-safe-area-context (3.1.9): - React-Core - react-native-video/Video (5.2.1): - React-Core - react-native-video/VideoCaching (5.2.1): - DVAssetLoaderDelegate (~> 0.3.1) - React-Core - react-native-video/Video - SPTPersistentCache (~> 1.1.0) - react-native-webview (11.23.0): - React-Core - React-perflogger (0.70.6) - React-RCTActionSheet (0.70.6): - React-Core/RCTActionSheetHeaders (= 0.70.6) - React-RCTAnimation (0.70.6): - RCT-Folly (= 2021.07.22.00) - RCTTypeSafety (= 0.70.6) - React-Codegen (= 0.70.6) - React-Core/RCTAnimationHeaders (= 0.70.6) - React-jsi (= 0.70.6) - ReactCommon/turbomodule/core (= 0.70.6) - React-RCTBlob (0.70.6): - RCT-Folly (= 2021.07.22.00) - React-Codegen (= 0.70.6) - React-Core/RCTBlobHeaders (= 0.70.6) - React-Core/RCTWebSocket (= 0.70.6) - React-jsi (= 0.70.6) - React-RCTNetwork (= 0.70.6) - ReactCommon/turbomodule/core (= 0.70.6) - React-RCTImage (0.70.6): - RCT-Folly (= 2021.07.22.00) - RCTTypeSafety (= 0.70.6) - React-Codegen (= 0.70.6) - React-Core/RCTImageHeaders (= 0.70.6) - React-jsi (= 0.70.6) - React-RCTNetwork (= 0.70.6) - ReactCommon/turbomodule/core (= 0.70.6) - React-RCTLinking (0.70.6): - React-Codegen (= 0.70.6) - React-Core/RCTLinkingHeaders (= 0.70.6) - React-jsi (= 0.70.6) - ReactCommon/turbomodule/core (= 0.70.6) - React-RCTNetwork (0.70.6): - RCT-Folly (= 2021.07.22.00) - RCTTypeSafety (= 0.70.6) - React-Codegen (= 0.70.6) - React-Core/RCTNetworkHeaders (= 0.70.6) - React-jsi (= 0.70.6) - ReactCommon/turbomodule/core (= 0.70.6) - React-RCTSettings (0.70.6): - RCT-Folly (= 2021.07.22.00) - RCTTypeSafety (= 0.70.6) - React-Codegen (= 0.70.6) - React-Core/RCTSettingsHeaders (= 0.70.6) - React-jsi (= 0.70.6) - ReactCommon/turbomodule/core (= 0.70.6) - React-RCTText (0.70.6): - React-Core/RCTTextHeaders (= 0.70.6) - React-RCTVibration (0.70.6): - RCT-Folly (= 2021.07.22.00) - React-Codegen (= 0.70.6) - React-Core/RCTVibrationHeaders (= 0.70.6) - React-jsi (= 0.70.6) - ReactCommon/turbomodule/core (= 0.70.6) - React-runtimeexecutor (0.70.6): - React-jsi (= 0.70.6) - ReactCommon/turbomodule/core (0.70.6): - DoubleConversion - glog - RCT-Folly (= 2021.07.22.00) - React-bridging (= 0.70.6) - React-callinvoker (= 0.70.6) - React-Core (= 0.70.6) - React-cxxreact (= 0.70.6) - React-jsi (= 0.70.6) - React-logger (= 0.70.6) - React-perflogger (= 0.70.6) - ReactNativeART (1.2.0): - React - ReactNativeKeyboardInput (6.0.1): - React - ReactNativeKeyboardTrackingView (5.7.0): - React - RNCAsyncStorage (1.17.10): - React-Core - RNCClipboard (1.11.1): - React-Core - SDWebImage (~> 5.8) - RNCMaskedView (0.2.8): - React-Core - RNDeviceInfo (8.0.7): - React-Core - RNExitApp (1.1.0): - React - RNFastImage (8.3.0): - React - SDWebImage (~> 5.8) - SDWebImageWebPCoder (~> 0.6.1) - RNFS (2.15.2): - React - RNGestureHandler (1.10.3): - React-Core - RNKeychain (8.0.0): - React-Core - RNReanimated (2.10.0): - DoubleConversion - FBLazyVector - FBReactNativeSpec - glog - RCT-Folly - RCTRequired - RCTTypeSafety - React-callinvoker - React-Core - React-Core/DevSupport - React-Core/RCTWebSocket - React-CoreModules - React-cxxreact - React-jsi - React-jsiexecutor - React-jsinspector - React-RCTActionSheet - React-RCTAnimation - React-RCTBlob - React-RCTImage - React-RCTLinking - React-RCTNetwork - React-RCTSettings - React-RCTText - ReactCommon/turbomodule/core - Yoga - RNScreens (3.8.0): - React-Core - React-RCTImage - RNSVG (12.3.0): - React-Core - - RNVectorIcons (6.6.0): - - React - SDWebImage (5.13.5): - SDWebImage/Core (= 5.13.5) - SDWebImage/Core (5.13.5) - SDWebImageWebPCoder (0.6.1): - libwebp (~> 1.0) - SDWebImage/Core (~> 5.7) - SPTPersistentCache (1.1.0) - SQLCipher-Amalgamation (4.4.3): - OpenSSL-Universal - SQLCipher-Amalgamation/standard (= 4.4.3) - SQLCipher-Amalgamation/common (4.4.3): - OpenSSL-Universal - SQLCipher-Amalgamation/standard (4.4.3): - OpenSSL-Universal - SQLCipher-Amalgamation/common - Yoga (1.14.0) DEPENDENCIES: - boost (from `../../node_modules/react-native/third-party-podspecs/boost.podspec`) - DoubleConversion (from `../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - EXApplication (from `../../node_modules/expo-application/ios`) - EXConstants (from `../../node_modules/expo-constants/ios`) - EXFileSystem (from `../../node_modules/expo-file-system/ios`) - EXFont (from `../../node_modules/expo-font/ios`) - EXImageLoader (from `../../node_modules/expo-image-loader/ios`) - EXJSONUtils (from `../../node_modules/expo-json-utils/ios`) - EXManifests (from `../../node_modules/expo-manifests/ios`) - EXMediaLibrary (from `../../node_modules/expo-media-library/ios`) - Expo (from `../../node_modules/expo`) - expo-dev-client (from `../../node_modules/expo-dev-client/ios`) - expo-dev-launcher (from `../../node_modules/expo-dev-launcher`) - expo-dev-menu (from `../../node_modules/expo-dev-menu`) - expo-dev-menu-interface (from `../../node_modules/expo-dev-menu-interface/ios`) - ExpoHaptics (from `../../node_modules/expo-haptics/ios`) - ExpoImageManipulator (from `../../node_modules/expo-image-manipulator/ios`) - ExpoKeepAwake (from `../../node_modules/expo-keep-awake/ios`) - ExpoModulesCore (from `../../node_modules/expo-modules-core`) - EXSecureStore (from `../../node_modules/expo-secure-store/ios`) - EXSplashScreen (from `../../node_modules/expo-splash-screen/ios`) - EXUpdatesInterface (from `../../node_modules/expo-updates-interface/ios`) - FBLazyVector (from `../../node_modules/react-native/Libraries/FBLazyVector`) - FBReactNativeSpec (from `../../node_modules/react-native/React/FBReactNativeSpec`) - glog (from `../../node_modules/react-native/third-party-podspecs/glog.podspec`) - hermes-engine (from `../../node_modules/react-native/sdks/hermes/hermes-engine.podspec`) - libevent (~> 2.1.12) - lottie-ios (from `../node_modules/lottie-ios`) - lottie-react-native (from `../node_modules/lottie-react-native`) - OLMKit (from `../node_modules/olm`) - RCT-Folly (from `../../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCTRequired (from `../../node_modules/react-native/Libraries/RCTRequired`) - RCTTypeSafety (from `../../node_modules/react-native/Libraries/TypeSafety`) - React (from `../../node_modules/react-native/`) - React-bridging (from `../../node_modules/react-native/ReactCommon`) - React-callinvoker (from `../../node_modules/react-native/ReactCommon/callinvoker`) - React-Codegen (from `build/generated/ios`) - React-Core (from `../../node_modules/react-native/`) - React-Core/RCTWebSocket (from `../../node_modules/react-native/`) - React-CoreModules (from `../../node_modules/react-native/React/CoreModules`) - React-cxxreact (from `../../node_modules/react-native/ReactCommon/cxxreact`) - React-hermes (from `../../node_modules/react-native/ReactCommon/hermes`) - React-jsi (from `../../node_modules/react-native/ReactCommon/jsi`) - React-jsiexecutor (from `../../node_modules/react-native/ReactCommon/jsiexecutor`) - React-jsinspector (from `../../node_modules/react-native/ReactCommon/jsinspector`) - React-logger (from `../../node_modules/react-native/ReactCommon/logger`) - react-native-background-upload (from `../node_modules/react-native-background-upload`) - react-native-camera (from `../node_modules/react-native-camera`) - react-native-ffmpeg/min-lts (from `../node_modules/react-native-ffmpeg`) - react-native-in-app-message (from `../node_modules/react-native-in-app-message`) - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" - react-native-notifications (from `../node_modules/react-native-notifications`) - react-native-orientation-locker (from `../node_modules/react-native-orientation-locker`) - react-native-pager-view (from `../node_modules/react-native-pager-view`) - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) - react-native-video/VideoCaching (from `../node_modules/react-native-video`) - react-native-webview (from `../node_modules/react-native-webview`) - React-perflogger (from `../../node_modules/react-native/ReactCommon/reactperflogger`) - React-RCTActionSheet (from `../../node_modules/react-native/Libraries/ActionSheetIOS`) - React-RCTAnimation (from `../../node_modules/react-native/Libraries/NativeAnimation`) - React-RCTBlob (from `../../node_modules/react-native/Libraries/Blob`) - React-RCTImage (from `../../node_modules/react-native/Libraries/Image`) - React-RCTLinking (from `../../node_modules/react-native/Libraries/LinkingIOS`) - React-RCTNetwork (from `../../node_modules/react-native/Libraries/Network`) - React-RCTSettings (from `../../node_modules/react-native/Libraries/Settings`) - React-RCTText (from `../../node_modules/react-native/Libraries/Text`) - React-RCTVibration (from `../../node_modules/react-native/Libraries/Vibration`) - React-runtimeexecutor (from `../../node_modules/react-native/ReactCommon/runtimeexecutor`) - ReactCommon/turbomodule/core (from `../../node_modules/react-native/ReactCommon`) - "ReactNativeART (from `../node_modules/@react-native-community/art`)" - ReactNativeKeyboardInput (from `../node_modules/react-native-keyboard-input`) - ReactNativeKeyboardTrackingView (from `../../node_modules/react-native-keyboard-tracking-view`) - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" - "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)" - "RNCMaskedView (from `../node_modules/@react-native-masked-view/masked-view`)" - RNDeviceInfo (from `../node_modules/react-native-device-info`) - RNExitApp (from `../node_modules/react-native-exit-app`) - RNFastImage (from `../node_modules/react-native-fast-image`) - RNFS (from `../node_modules/react-native-fs`) - RNGestureHandler (from `../node_modules/react-native-gesture-handler`) - RNKeychain (from `../node_modules/react-native-keychain`) - RNReanimated (from `../node_modules/react-native-reanimated`) - RNScreens (from `../node_modules/react-native-screens`) - RNSVG (from `../node_modules/react-native-svg`) - - RNVectorIcons (from `../node_modules/react-native-vector-icons`) - "SQLCipher-Amalgamation (from `../../node_modules/@commapp/sqlcipher-amalgamation`)" - Yoga (from `../../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: trunk: - DVAssetLoaderDelegate - fmt - libevent - libwebp - mobile-ffmpeg-min - OpenSSL-Universal - SDWebImage - SDWebImageWebPCoder - SPTPersistentCache EXTERNAL SOURCES: boost: :podspec: "../../node_modules/react-native/third-party-podspecs/boost.podspec" DoubleConversion: :podspec: "../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" EXApplication: :path: "../../node_modules/expo-application/ios" EXConstants: :path: "../../node_modules/expo-constants/ios" EXFileSystem: :path: "../../node_modules/expo-file-system/ios" EXFont: :path: "../../node_modules/expo-font/ios" EXImageLoader: :path: "../../node_modules/expo-image-loader/ios" EXJSONUtils: :path: "../../node_modules/expo-json-utils/ios" EXManifests: :path: "../../node_modules/expo-manifests/ios" EXMediaLibrary: :path: "../../node_modules/expo-media-library/ios" Expo: :path: "../../node_modules/expo" expo-dev-client: :path: "../../node_modules/expo-dev-client/ios" expo-dev-launcher: :path: "../../node_modules/expo-dev-launcher" expo-dev-menu: :path: "../../node_modules/expo-dev-menu" expo-dev-menu-interface: :path: "../../node_modules/expo-dev-menu-interface/ios" ExpoHaptics: :path: "../../node_modules/expo-haptics/ios" ExpoImageManipulator: :path: "../../node_modules/expo-image-manipulator/ios" ExpoKeepAwake: :path: "../../node_modules/expo-keep-awake/ios" ExpoModulesCore: :path: "../../node_modules/expo-modules-core" EXSecureStore: :path: "../../node_modules/expo-secure-store/ios" EXSplashScreen: :path: "../../node_modules/expo-splash-screen/ios" EXUpdatesInterface: :path: "../../node_modules/expo-updates-interface/ios" FBLazyVector: :path: "../../node_modules/react-native/Libraries/FBLazyVector" FBReactNativeSpec: :path: "../../node_modules/react-native/React/FBReactNativeSpec" glog: :podspec: "../../node_modules/react-native/third-party-podspecs/glog.podspec" hermes-engine: :podspec: "../../node_modules/react-native/sdks/hermes/hermes-engine.podspec" lottie-ios: :path: "../node_modules/lottie-ios" lottie-react-native: :path: "../node_modules/lottie-react-native" OLMKit: :path: "../node_modules/olm" RCT-Folly: :podspec: "../../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" RCTRequired: :path: "../../node_modules/react-native/Libraries/RCTRequired" RCTTypeSafety: :path: "../../node_modules/react-native/Libraries/TypeSafety" React: :path: "../../node_modules/react-native/" React-bridging: :path: "../../node_modules/react-native/ReactCommon" React-callinvoker: :path: "../../node_modules/react-native/ReactCommon/callinvoker" React-Codegen: :path: build/generated/ios React-Core: :path: "../../node_modules/react-native/" React-CoreModules: :path: "../../node_modules/react-native/React/CoreModules" React-cxxreact: :path: "../../node_modules/react-native/ReactCommon/cxxreact" React-hermes: :path: "../../node_modules/react-native/ReactCommon/hermes" React-jsi: :path: "../../node_modules/react-native/ReactCommon/jsi" React-jsiexecutor: :path: "../../node_modules/react-native/ReactCommon/jsiexecutor" React-jsinspector: :path: "../../node_modules/react-native/ReactCommon/jsinspector" React-logger: :path: "../../node_modules/react-native/ReactCommon/logger" react-native-background-upload: :path: "../node_modules/react-native-background-upload" react-native-camera: :path: "../node_modules/react-native-camera" react-native-ffmpeg: :podspec: "../node_modules/react-native-ffmpeg" react-native-in-app-message: :path: "../node_modules/react-native-in-app-message" react-native-netinfo: :path: "../node_modules/@react-native-community/netinfo" react-native-notifications: :path: "../node_modules/react-native-notifications" react-native-orientation-locker: :path: "../node_modules/react-native-orientation-locker" react-native-pager-view: :path: "../node_modules/react-native-pager-view" react-native-safe-area-context: :path: "../node_modules/react-native-safe-area-context" react-native-video: :podspec: "../node_modules/react-native-video" react-native-webview: :path: "../node_modules/react-native-webview" React-perflogger: :path: "../../node_modules/react-native/ReactCommon/reactperflogger" React-RCTActionSheet: :path: "../../node_modules/react-native/Libraries/ActionSheetIOS" React-RCTAnimation: :path: "../../node_modules/react-native/Libraries/NativeAnimation" React-RCTBlob: :path: "../../node_modules/react-native/Libraries/Blob" React-RCTImage: :path: "../../node_modules/react-native/Libraries/Image" React-RCTLinking: :path: "../../node_modules/react-native/Libraries/LinkingIOS" React-RCTNetwork: :path: "../../node_modules/react-native/Libraries/Network" React-RCTSettings: :path: "../../node_modules/react-native/Libraries/Settings" React-RCTText: :path: "../../node_modules/react-native/Libraries/Text" React-RCTVibration: :path: "../../node_modules/react-native/Libraries/Vibration" React-runtimeexecutor: :path: "../../node_modules/react-native/ReactCommon/runtimeexecutor" ReactCommon: :path: "../../node_modules/react-native/ReactCommon" ReactNativeART: :path: "../node_modules/@react-native-community/art" ReactNativeKeyboardInput: :path: "../node_modules/react-native-keyboard-input" ReactNativeKeyboardTrackingView: :path: "../../node_modules/react-native-keyboard-tracking-view" RNCAsyncStorage: :path: "../node_modules/@react-native-async-storage/async-storage" RNCClipboard: :path: "../node_modules/@react-native-clipboard/clipboard" RNCMaskedView: :path: "../node_modules/@react-native-masked-view/masked-view" RNDeviceInfo: :path: "../node_modules/react-native-device-info" RNExitApp: :path: "../node_modules/react-native-exit-app" RNFastImage: :path: "../node_modules/react-native-fast-image" RNFS: :path: "../node_modules/react-native-fs" RNGestureHandler: :path: "../node_modules/react-native-gesture-handler" RNKeychain: :path: "../node_modules/react-native-keychain" RNReanimated: :path: "../node_modules/react-native-reanimated" RNScreens: :path: "../node_modules/react-native-screens" RNSVG: :path: "../node_modules/react-native-svg" - RNVectorIcons: - :path: "../node_modules/react-native-vector-icons" SQLCipher-Amalgamation: :path: "../../node_modules/@commapp/sqlcipher-amalgamation" Yoga: :path: "../../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: boost: a7c83b31436843459a1961bfd74b96033dc77234 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 DVAssetLoaderDelegate: 0caec20e4e08b8560b691131539e9180024d4bce EXApplication: 034b1c40a8e9fe1bff76a1e511ee90dff64ad834 EXConstants: 3c86653c422dd77e40d10cbbabb3025003977415 EXFileSystem: 60602b6eefa6873f97172c684b7537c9760b50d6 EXFont: 319606bfe48c33b5b5063fb0994afdc496befe80 EXImageLoader: 84b65e6bd9d3345d6fbb3ab936a546c54496a64d EXJSONUtils: 09aef2c1fba1a116ca8c73a2c8299aac00d96b43 EXManifests: 347f49430b63444579aa013f0ad057d16b8d1cc8 EXMediaLibrary: b1c4f78878e45f6a359aff3a059e1660c41b73ab Expo: 36b5f625d36728adbdd1934d4d57182f319ab832 expo-dev-client: d723d52ccfbe2eb47ee24d1ac0cf5b39001589c2 expo-dev-launcher: 953f564f7d006f1af50b119cacb48cafcad40c73 expo-dev-menu: 3d25298c15e2179c9f71b92f2273c83bdd71c435 expo-dev-menu-interface: 45581093393dacd51ce5e7f641cf9ed5064a2e3f ExpoHaptics: 5a56d30a87ea213dd00b09566dc4b441a4dff97f ExpoImageManipulator: 5f3c1ab8dd81de11491b5051bb925abc91fe57e4 ExpoKeepAwake: 69b59d0a8d2b24de9f82759c39b3821fec030318 ExpoModulesCore: b5d21c8880afda6fb6ee95469f9ac2ec9b98e995 EXSecureStore: daec0117c922a67c658cb229152a9e252e5c1750 EXSplashScreen: 3e989924f61a8dd07ee4ea584c6ba14be9b51949 EXUpdatesInterface: bffd1ead18f0bab04fa784ca159c115607b8a23c FBLazyVector: 48289402952f4f7a4e235de70a9a590aa0b79ef4 FBReactNativeSpec: c8856286d1e15e74b57b892c68d7d1d05b79c7de fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b hermes-engine: 2af7b7a59128f250adfd86f15aa1d5a2ecd39995 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 libwebp: 60305b2e989864154bd9be3d772730f08fc6a59c lottie-ios: 48fac6be217c76937e36e340e2d09cf7b10b7f5f lottie-react-native: 4dff8fe8d10ddef9e7880e770080f4a56121397e mobile-ffmpeg-min: d5d22dcef5c8ec56f771258f1f5be245d914f193 OLMKit: a15f216aa14ba199b4fd827b3d7ef04629b56636 OpenSSL-Universal: 84efb8a29841f2764ac5403e0c4119a28b713346 RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda RCTRequired: e1866f61af7049eb3d8e08e8b133abd38bc1ca7a RCTTypeSafety: 27c2ac1b00609a432ced1ae701247593f07f901e React: bb3e06418d2cc48a84f9666a576c7b38e89cd7db React-bridging: 572502ec59c9de30309afdc4932e278214288913 React-callinvoker: 6b708b79c69f3359d42f1abb4663f620dbd4dadf React-Codegen: 74e1cd7cee692a8b983c18df3274b5e749de07c8 React-Core: b587d0a624f9611b0e032505f3d6f25e8daa2bee React-CoreModules: c6ff48b985e7aa622e82ca51c2c353c7803eb04e React-cxxreact: ade3d9e63c599afdead3c35f8a8bd12b3da6730b React-hermes: ed09ae33512bbb8d31b2411778f3af1a2eb681a1 React-jsi: 5a3952e0c6d57460ad9ee2c905025b4c28f71087 React-jsiexecutor: b4a65947391c658450151275aa406f2b8263178f React-jsinspector: 60769e5a0a6d4b32294a2456077f59d0266f9a8b React-logger: 1623c216abaa88974afce404dc8f479406bbc3a0 react-native-background-upload: c62f25610ffd49b1781fbdf1135b3b17f2f914b9 react-native-camera: b5c8c7a71feecfdd5b39f0dbbf6b64b957ed55f2 react-native-ffmpeg: f9a60452aaa5d478aac205b248224994f3bde416 react-native-in-app-message: f91de5009620af01456531118264c93e249b83ec react-native-netinfo: e849fc21ca2f4128a5726c801a82fc6f4a6db50d react-native-notifications: bb042206ac7eab9323d528c780b3d6fe796c1f5e react-native-orientation-locker: 23918c400376a7043e752c639c122fcf6bce8f1c react-native-pager-view: 3051346698a0ba0c4e13e40097cc11b00ee03cca react-native-safe-area-context: b6e0e284002381d2ff29fa4fff42b4d8282e3c94 react-native-video: 10f689069cb894d75030190a9bc62d9393e1f997 react-native-webview: e771bc375f789ebfa02a26939a57dbc6fa897336 React-perflogger: 8c79399b0500a30ee8152d0f9f11beae7fc36595 React-RCTActionSheet: 7316773acabb374642b926c19aef1c115df5c466 React-RCTAnimation: 5341e288375451297057391227f691d9b2326c3d React-RCTBlob: b0615fc2daf2b5684ade8fadcab659f16f6f0efa React-RCTImage: 6487b9600f268ecedcaa86114d97954d31ad4750 React-RCTLinking: c8018ae9ebfefcec3839d690d4725f8d15e4e4b3 React-RCTNetwork: 8aa63578741e0fe1205c28d7d4b40dbfdabce8a8 React-RCTSettings: d00c15ad369cd62242a4dfcc6f277912b4a84ed3 React-RCTText: f532e5ca52681ecaecea452b3ad7a5b630f50d75 React-RCTVibration: c75ceef7aa60a33b2d5731ebe5800ddde40cefc4 React-runtimeexecutor: 15437b576139df27635400de0599d9844f1ab817 ReactCommon: 349be31adeecffc7986a0de875d7fb0dcf4e251c ReactNativeART: 78edc68dd4a1e675338cd0cd113319cf3a65f2ab ReactNativeKeyboardInput: 266ba27a2e9921f5bdc0b4cc30289b2a2f46b157 ReactNativeKeyboardTrackingView: 02137fac3b2ebd330d74fa54ead48b14750a2306 RNCAsyncStorage: 0c357f3156fcb16c8589ede67cc036330b6698ca RNCClipboard: f66930407a30948ffdecf43a2459bcf05aa59804 RNCMaskedView: bc0170f389056201c82a55e242e5d90070e18e5a RNDeviceInfo: 55463fa6e252ca3f0e2ba6001a7b82f879914338 RNExitApp: c4e052df2568b43bec8a37c7cd61194d4cfee2c3 RNFastImage: 2ed80661d5ef384fb1b539f1f3c81a1733f92bc9 RNFS: 54da03c2b7d862c42ea3ca8c7f86f892760a535a RNGestureHandler: a479ebd5ed4221a810967000735517df0d2db211 RNKeychain: 4f63aada75ebafd26f4bc2c670199461eab85d94 RNReanimated: 60e291d42c77752a0f6d6f358387bdf225a87c6e RNScreens: 6e1ea5787989f92b0671049b808aef64fa1ef98c RNSVG: 302bfc9905bd8122f08966dc2ce2d07b7b52b9f8 - RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4 SDWebImage: 23d714cd599354ee7906dbae26dff89b421c4370 SDWebImageWebPCoder: d0dac55073088d24b2ac1b191a71a8f8d0adac21 SPTPersistentCache: df36ea46762d7cf026502bbb86a8b79d0080dff4 SQLCipher-Amalgamation: cbd36045fe7b458b8a442958a01aefdbc44c20f8 Yoga: 99caf8d5ab45e9d637ee6e0174ec16fbbb01bcfc PODFILE CHECKSUM: 60ed9de6b14a66c6022cd82cafcb04594edd7eaf COCOAPODS: 1.11.3 diff --git a/native/media/camera-modal.react.js b/native/media/camera-modal.react.js index ee3f48016..72d6c564b 100644 --- a/native/media/camera-modal.react.js +++ b/native/media/camera-modal.react.js @@ -1,1211 +1,1211 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; import { View, Text, StyleSheet, TouchableOpacity, Platform, Image, Animated, Easing, } from 'react-native'; import { RNCamera } from 'react-native-camera'; import filesystem from 'react-native-fs'; import { PinchGestureHandler, TapGestureHandler, State as GestureState, } 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, } from 'react-native-reanimated'; -import Icon from 'react-native-vector-icons/Ionicons'; +import Icon from '@expo/vector-icons/Ionicons'; import { useDispatch } from 'react-redux'; import { pathFromURI, filenameFromPathOrURI } from 'lib/media/file-utils'; import { useIsAppForegrounded } from 'lib/shared/lifecycle-utils'; import type { PhotoCapture } from 'lib/types/media-types'; import type { Dispatch } from 'lib/types/redux-types'; import type { ThreadInfo } from 'lib/types/thread-types'; import ContentLoading from '../components/content-loading.react'; import ConnectedStatusBar from '../connected-status-bar.react'; import { type InputState, InputStateContext } from '../input/input-state'; import type { AppNavigationProp } from '../navigation/app-navigator.react'; import { OverlayContext, type OverlayContextType, } from '../navigation/overlay-context'; import type { NavigationRoute } from '../navigation/route-names'; import { updateDeviceCameraInfoActionType } from '../redux/action-types'; import { type DimensionsInfo } from '../redux/dimensions-updater.react'; import { useSelector } from '../redux/redux-utils'; import { colors } from '../themes/colors'; import { type DeviceCameraInfo } from '../types/camera'; import type { NativeMethods } from '../types/react-native'; import { AnimatedView, type ViewStyle, type AnimatedViewStyle, } from '../types/styles'; import { clamp, gestureJustEnded } from '../utils/animation-utils'; import SendMediaButton from './send-media-button.react'; /* eslint-disable import/no-named-as-default-member */ const { Value, Node, Clock, event, Extrapolate, block, set, call, cond, not, and, or, eq, greaterThan, lessThan, add, sub, multiply, divide, abs, interpolateNode, startClock, stopClock, clockRunning, timing, spring, SpringUtils, } = Reanimated; /* eslint-enable import/no-named-as-default-member */ const maxZoom = 16; const zoomUpdateFactor = (() => { if (Platform.OS === 'ios') { return 0.002; } if (Platform.OS === 'android' && Platform.Version > 26) { return 0.005; } if (Platform.OS === 'android' && Platform.Version > 23) { return 0.01; } return 0.03; })(); const stagingModeAnimationConfig = { duration: 150, easing: ReanimatedEasing.inOut(ReanimatedEasing.ease), }; const sendButtonAnimationConfig = { duration: 150, easing: Easing.inOut(Easing.ease), useNativeDriver: true, }; const indicatorSpringConfig = { ...SpringUtils.makeDefaultConfig(), damping: 0, mass: 0.6, toValue: 1, }; const indicatorTimingConfig = { duration: 500, easing: ReanimatedEasing.out(ReanimatedEasing.ease), toValue: 0, }; function runIndicatorAnimation( // Inputs springClock: Clock, delayClock: Clock, timingClock: Clock, animationRunning: Node, // Outputs scale: Value, opacity: Value, ): Node { const delayStart = new Value(0); const springScale = new Value(0.75); const delayScale = new Value(0); const timingScale = new Value(0.75); const animatedScale = cond( clockRunning(springClock), springScale, cond(clockRunning(delayClock), delayScale, timingScale), ); const lastAnimatedScale = new Value(0.75); const numScaleLoops = new Value(0); const springState = { finished: new Value(1), velocity: new Value(0), time: new Value(0), position: springScale, }; const timingState = { finished: new Value(1), frameTime: new Value(0), time: new Value(0), position: timingScale, }; return block([ cond(not(animationRunning), [ set(springState.finished, 0), set(springState.velocity, 0), set(springState.time, 0), set(springScale, 0.75), set(lastAnimatedScale, 0.75), set(numScaleLoops, 0), set(opacity, 1), startClock(springClock), ]), [ cond( clockRunning(springClock), spring(springClock, springState, indicatorSpringConfig), ), timing(timingClock, timingState, indicatorTimingConfig), ], [ cond( and( greaterThan(animatedScale, 1.2), not(greaterThan(lastAnimatedScale, 1.2)), ), [ set(numScaleLoops, add(numScaleLoops, 1)), cond(greaterThan(numScaleLoops, 1), [ set(springState.finished, 1), stopClock(springClock), set(delayScale, springScale), set(delayStart, delayClock), startClock(delayClock), ]), ], ), set(lastAnimatedScale, animatedScale), ], cond( and( clockRunning(delayClock), greaterThan(delayClock, add(delayStart, 400)), ), [ stopClock(delayClock), set(timingState.finished, 0), set(timingState.frameTime, 0), set(timingState.time, 0), set(timingScale, delayScale), startClock(timingClock), ], ), cond( and(springState.finished, timingState.finished), stopClock(timingClock), ), set(scale, animatedScale), cond(clockRunning(timingClock), set(opacity, clamp(animatedScale, 0, 1))), ]); } export type CameraModalParams = { +presentedFrom: string, +thread: ThreadInfo, }; type TouchableOpacityInstance = React.AbstractComponent< React.ElementConfig, NativeMethods, >; type BaseProps = { +navigation: AppNavigationProp<'CameraModal'>, +route: NavigationRoute<'CameraModal'>, }; type Props = { ...BaseProps, // Redux state +dimensions: DimensionsInfo, +deviceCameraInfo: DeviceCameraInfo, +deviceOrientation: Orientations, +foreground: boolean, // Redux dispatch functions +dispatch: Dispatch, // withInputState +inputState: ?InputState, // withOverlayContext +overlayContext: ?OverlayContextType, }; type State = { +zoom: number, +useFrontCamera: boolean, +hasCamerasOnBothSides: boolean, +flashMode: number, +autoFocusPointOfInterest: ?{ x: number, y: number, autoExposure?: boolean, }, +stagingMode: boolean, +pendingPhotoCapture: ?PhotoCapture, }; class CameraModal extends React.PureComponent { camera: ?RNCamera; pinchEvent; pinchHandler = React.createRef(); tapEvent; tapHandler = React.createRef(); animationCode: Node; closeButton: ?React.ElementRef; closeButtonX = new Value(-1); closeButtonY = new Value(-1); closeButtonWidth = new Value(0); closeButtonHeight = new Value(0); photoButton: ?React.ElementRef; photoButtonX = new Value(-1); photoButtonY = new Value(-1); photoButtonWidth = new Value(0); photoButtonHeight = new Value(0); switchCameraButton: ?React.ElementRef; switchCameraButtonX = new Value(-1); switchCameraButtonY = new Value(-1); switchCameraButtonWidth = new Value(0); switchCameraButtonHeight = new Value(0); flashButton: ?React.ElementRef; flashButtonX = new Value(-1); flashButtonY = new Value(-1); flashButtonWidth = new Value(0); flashButtonHeight = new Value(0); focusIndicatorX = new Value(-1); focusIndicatorY = new Value(-1); focusIndicatorScale = new Value(0); focusIndicatorOpacity = new Value(0); cancelIndicatorAnimation = new Value(0); cameraIDsFetched = false; stagingModeProgress = new Value(0); sendButtonProgress = new Animated.Value(0); sendButtonStyle: ViewStyle; overlayStyle: AnimatedViewStyle; constructor(props: Props) { super(props); this.state = { zoom: 0, useFrontCamera: props.deviceCameraInfo.defaultUseFrontCamera, hasCamerasOnBothSides: props.deviceCameraInfo.hasCamerasOnBothSides, flashMode: RNCamera.Constants.FlashMode.off, autoFocusPointOfInterest: undefined, stagingMode: false, pendingPhotoCapture: undefined, }; const sendButtonScale = this.sendButtonProgress.interpolate({ inputRange: [0, 1], outputRange: ([1.1, 1]: number[]), // Flow... }); this.sendButtonStyle = { opacity: this.sendButtonProgress, transform: [{ scale: sendButtonScale }], }; const overlayOpacity = interpolateNode(this.stagingModeProgress, { inputRange: [0, 0.01, 1], outputRange: [0, 0.5, 0], extrapolate: Extrapolate.CLAMP, }); this.overlayStyle = { ...styles.overlay, opacity: overlayOpacity, }; const pinchState = new Value(-1); const pinchScale = new Value(1); this.pinchEvent = event([ { nativeEvent: { state: pinchState, scale: pinchScale, }, }, ]); const tapState = new Value(-1); const tapX = new Value(0); const tapY = new Value(0); this.tapEvent = event([ { nativeEvent: { state: tapState, x: tapX, y: tapY, }, }, ]); this.animationCode = block([ this.zoomAnimationCode(pinchState, pinchScale), this.focusAnimationCode(tapState, tapX, tapY), ]); } zoomAnimationCode(pinchState: Node, pinchScale: Node): Node { const pinchJustEnded = gestureJustEnded(pinchState); const zoomBase = new Value(1); const zoomReported = new Value(1); const currentZoom = interpolateNode(multiply(zoomBase, pinchScale), { inputRange: [1, 8], outputRange: [1, 8], extrapolate: Extrapolate.CLAMP, }); const cameraZoomFactor = interpolateNode(zoomReported, { inputRange: [1, 8], outputRange: [0, 1], extrapolate: Extrapolate.CLAMP, }); const resolvedZoom = cond( eq(pinchState, GestureState.ACTIVE), currentZoom, zoomBase, ); return block([ cond(pinchJustEnded, set(zoomBase, currentZoom)), cond( or( pinchJustEnded, greaterThan( abs(sub(divide(resolvedZoom, zoomReported), 1)), zoomUpdateFactor, ), ), [ set(zoomReported, resolvedZoom), call([cameraZoomFactor], this.updateZoom), ], ), ]); } focusAnimationCode(tapState: Node, tapX: Node, tapY: Node): Node { const lastTapX = new Value(0); const lastTapY = new Value(0); const fingerJustReleased = and( gestureJustEnded(tapState), this.outsideButtons(lastTapX, lastTapY), ); const indicatorSpringClock = new Clock(); const indicatorDelayClock = new Clock(); const indicatorTimingClock = new Clock(); const indicatorAnimationRunning = or( clockRunning(indicatorSpringClock), clockRunning(indicatorDelayClock), clockRunning(indicatorTimingClock), ); return block([ cond(fingerJustReleased, [ call([tapX, tapY], this.focusOnPoint), set(this.focusIndicatorX, tapX), set(this.focusIndicatorY, tapY), stopClock(indicatorSpringClock), stopClock(indicatorDelayClock), stopClock(indicatorTimingClock), ]), cond(this.cancelIndicatorAnimation, [ set(this.cancelIndicatorAnimation, 0), stopClock(indicatorSpringClock), stopClock(indicatorDelayClock), stopClock(indicatorTimingClock), set(this.focusIndicatorOpacity, 0), ]), cond( or(fingerJustReleased, indicatorAnimationRunning), runIndicatorAnimation( indicatorSpringClock, indicatorDelayClock, indicatorTimingClock, indicatorAnimationRunning, this.focusIndicatorScale, this.focusIndicatorOpacity, ), ), set(lastTapX, tapX), set(lastTapY, tapY), ]); } outsideButtons(x: Node, y: Node): Node { const { closeButtonX, closeButtonY, closeButtonWidth, closeButtonHeight, photoButtonX, photoButtonY, photoButtonWidth, photoButtonHeight, switchCameraButtonX, switchCameraButtonY, switchCameraButtonWidth, switchCameraButtonHeight, flashButtonX, flashButtonY, flashButtonWidth, flashButtonHeight, } = this; return and( or( lessThan(x, closeButtonX), greaterThan(x, add(closeButtonX, closeButtonWidth)), lessThan(y, closeButtonY), greaterThan(y, add(closeButtonY, closeButtonHeight)), ), or( lessThan(x, photoButtonX), greaterThan(x, add(photoButtonX, photoButtonWidth)), lessThan(y, photoButtonY), greaterThan(y, add(photoButtonY, photoButtonHeight)), ), or( lessThan(x, switchCameraButtonX), greaterThan(x, add(switchCameraButtonX, switchCameraButtonWidth)), lessThan(y, switchCameraButtonY), greaterThan(y, add(switchCameraButtonY, switchCameraButtonHeight)), ), or( lessThan(x, flashButtonX), greaterThan(x, add(flashButtonX, flashButtonWidth)), lessThan(y, flashButtonY), greaterThan(y, add(flashButtonY, flashButtonHeight)), ), ); } static isActive(props) { const { overlayContext } = props; invariant(overlayContext, 'CameraModal should have OverlayContext'); return !overlayContext.isDismissing; } componentDidMount() { if (CameraModal.isActive(this.props)) { Orientation.unlockAllOrientations(); } } componentWillUnmount() { if (CameraModal.isActive(this.props)) { Orientation.lockToPortrait(); } } componentDidUpdate(prevProps: Props, prevState: State) { const isActive = CameraModal.isActive(this.props); const wasActive = CameraModal.isActive(prevProps); if (isActive && !wasActive) { Orientation.unlockAllOrientations(); } else if (!isActive && wasActive) { Orientation.lockToPortrait(); } if (!this.state.hasCamerasOnBothSides && prevState.hasCamerasOnBothSides) { this.switchCameraButtonX.setValue(-1); this.switchCameraButtonY.setValue(-1); this.switchCameraButtonWidth.setValue(0); this.switchCameraButtonHeight.setValue(0); } if (this.props.deviceOrientation !== prevProps.deviceOrientation) { this.setState({ autoFocusPointOfInterest: null }); this.cancelIndicatorAnimation.setValue(1); } if (this.props.foreground && !prevProps.foreground && this.camera) { this.camera.refreshAuthorizationStatus(); } if (this.state.stagingMode && !prevState.stagingMode) { this.cancelIndicatorAnimation.setValue(1); this.focusIndicatorOpacity.setValue(0); timing(this.stagingModeProgress, { ...stagingModeAnimationConfig, toValue: 1, }).start(); } else if (!this.state.stagingMode && prevState.stagingMode) { this.stagingModeProgress.setValue(0); } if (this.state.pendingPhotoCapture && !prevState.pendingPhotoCapture) { Animated.timing(this.sendButtonProgress, { ...sendButtonAnimationConfig, toValue: 1, }).start(); } else if ( !this.state.pendingPhotoCapture && prevState.pendingPhotoCapture ) { CameraModal.cleanUpPendingPhotoCapture(prevState.pendingPhotoCapture); this.sendButtonProgress.setValue(0); } } static async cleanUpPendingPhotoCapture(pendingPhotoCapture: PhotoCapture) { const path = pathFromURI(pendingPhotoCapture.uri); if (!path) { return; } try { await filesystem.unlink(path); } catch (e) {} } get containerStyle() { const { overlayContext } = this.props; invariant(overlayContext, 'CameraModal should have OverlayContext'); return { ...styles.container, opacity: overlayContext.position, }; } get focusIndicatorStyle() { return { ...styles.focusIndicator, opacity: this.focusIndicatorOpacity, transform: [ { translateX: this.focusIndicatorX }, { translateY: this.focusIndicatorY }, { scale: this.focusIndicatorScale }, ], }; } renderCamera = ({ camera, status }) => { if (camera && camera._cameraHandle) { this.fetchCameraIDs(camera); } if (this.state.stagingMode) { return this.renderStagingView(); } const topButtonStyle = { top: Math.max(this.props.dimensions.topInset, 6), }; return ( <> {this.renderCameraContent(status)} × ); }; renderStagingView() { let image = null; const { pendingPhotoCapture } = this.state; if (pendingPhotoCapture) { const imageSource = { uri: pendingPhotoCapture.uri }; image = ; } else { image = ; } const topButtonStyle = { top: Math.max(this.props.dimensions.topInset - 3, 3), }; const sendButtonContainerStyle = { bottom: this.props.dimensions.bottomInset + 22, }; return ( <> {image} ); } renderCameraContent(status) { if (status === 'PENDING_AUTHORIZATION') { return ; } else if (status === 'NOT_AUTHORIZED') { return ( {'don’t have permission :('} ); } let switchCameraButton = null; if (this.state.hasCamerasOnBothSides) { switchCameraButton = ( ); } let flashIcon; if (this.state.flashMode === RNCamera.Constants.FlashMode.on) { flashIcon = ; } else if (this.state.flashMode === RNCamera.Constants.FlashMode.off) { flashIcon = ; } else { flashIcon = ( <> A ); } const topButtonStyle = { top: Math.max(this.props.dimensions.topInset - 3, 3), }; const bottomButtonsContainerStyle = { bottom: this.props.dimensions.bottomInset + 20, }; return ( {flashIcon} {switchCameraButton} ); } render() { const statusBar = CameraModal.isActive(this.props) ? (