Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added transition handling between the side drawer and chats #2221

Merged
merged 48 commits into from
Apr 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
3e91a32
refactor: convert ReportScreen to class component
kidroca Apr 2, 2021
455a707
refactor: ReportScreen added drawer state
kidroca Apr 2, 2021
53b65f9
feat: Loading components
kidroca Apr 2, 2021
3395593
feat: ReportScreen add loading animation for content
kidroca Apr 2, 2021
0c30b06
refactor: ReportScreen move loading animation to ReportView
kidroca Apr 2, 2021
8252997
refactor: ReportActionsView remove extra calls to initial fetch
kidroca Apr 2, 2021
0dd170b
refactor: ReportScreen extract withDrawerState HOC
kidroca Apr 2, 2021
8a6df1b
refactor: withDrawerState implement with useIsDrawerOpen for simplicity
kidroca Apr 2, 2021
8d89162
refactor: ReportView improve transition using drawer state
kidroca Apr 2, 2021
283e6c0
refactor: ReportActionCompose remove drawer check
kidroca Apr 2, 2021
4cf35fd
refactor: ReportScreen handle initial state
kidroca Apr 3, 2021
7fa89be
refactor: update copy pasted display name
kidroca Apr 5, 2021
96ff600
refactor: ReportScreen use reportID from route params
kidroca Apr 5, 2021
b2177a6
refactor: ReportScreen expand the drawer on back navigation
kidroca Apr 5, 2021
2f4a7ea
feat: ReportActionCompose allow autoFocus to be configurable from par…
kidroca Apr 5, 2021
073249e
refactor: ReportView optimizations
kidroca Apr 5, 2021
f3fea9b
refactor: ReportActionsView remove unnecessary logic around report sw…
kidroca Apr 5, 2021
5d2f079
refactor: ReportActionsView remove `needsLayoutCalculation`
kidroca Apr 5, 2021
199fb11
refactor: ReportActionCompose remove `withWindowDimensions` - unused
kidroca Apr 5, 2021
7003ad8
feat: ReportScreen loading view layout transitions
kidroca Apr 5, 2021
3396074
refactor: ReportScreen clean up comments and console.logs
kidroca Apr 5, 2021
fc371c0
refactor: ReportScreen restore reportID as number
kidroca Apr 5, 2021
b3414b6
Remove todo note, already addressed elsewhere and could cause confusion
kidroca Apr 7, 2021
5ce7b33
refactor: ReportScreen remove error state
kidroca Apr 7, 2021
a3df62a
refactor: ReportScreen replace computed getters with methods
kidroca Apr 7, 2021
809d041
Revert "feat: ReportActionCompose allow autoFocus to be configurable …
kidroca Apr 7, 2021
0d50195
refactor: Address autoFocus usage and add documentation
kidroca Apr 7, 2021
a03f8ba
refactor: extract FullscreenLoading styles
kidroca Apr 7, 2021
8184e0f
Drop: custom LoadingIndicator and use the built in ActivityIndicator
kidroca Apr 7, 2021
a3f92f5
drop: Remove layout animations
kidroca Apr 7, 2021
0a96fa8
feat: ReportScreen don't wait for fetch just show a brief loading
kidroca Apr 7, 2021
3b4a2c3
refactor: ReportActionsView remove `reset` method - no longer needed
kidroca Apr 7, 2021
f0d7bb5
refactor: ReportScreen move `fetchActions` call back to ReportActions…
kidroca Apr 7, 2021
c08d14e
refactor: ReportScreen replace comment with self explanatory code
kidroca Apr 7, 2021
7847ffa
refactor: TextInputFocusable add isDisabled prop to the native compon…
kidroca Apr 7, 2021
a9ed45b
refactor: ReportActionCompose disable while app focus is away from th…
kidroca Apr 7, 2021
c5dacac
refactor: rename FullscreenLoadingIndicator
kidroca Apr 8, 2021
4646f1c
refactor: ReportScreen move the full screen loader to this screen
kidroca Apr 8, 2021
74eb008
refactor: add `visible` prop to loader
kidroca Apr 8, 2021
7072ed6
refactor: ReportView cleanup unused styles
kidroca Apr 8, 2021
9234aa8
refactor: ReportScreen restore Navigation usage
kidroca Apr 8, 2021
f762e41
refactor: ReportScreen remove unneeded check
kidroca Apr 8, 2021
328f1ba
refactor: ReportActionsView setup unread indicator during mount
kidroca Apr 8, 2021
3e5b599
refactor: ReportScreen remove navigation prop - unused
kidroca Apr 8, 2021
a89877c
refactor: ReportActionCompose move logic related to disabling the inp…
kidroca Apr 8, 2021
2944644
Merge remote-tracking branch 'e.cash/master' into kidroca/report-view…
kidroca Apr 8, 2021
64c048f
refactor: ReportScreen restore original navigation handling
kidroca Apr 8, 2021
db7b937
Merge remote-tracking branch 'e.cash/master' into kidroca/report-view…
kidroca Apr 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/components/FullscreenLoadingIndicator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import PropTypes from 'prop-types';
import {ActivityIndicator, StyleSheet, View} from 'react-native';
import styles from '../styles/styles';
import themeColors from '../styles/themes/default';

const propTypes = {
/* Controls whether the loader is mounted and displayed */
visible: PropTypes.bool.isRequired,
};

/**
* Loading indication component intended to cover the whole page, while the page prepares for initial render
*
* @returns {JSX.Element}
*/
const FullScreenLoadingIndicator = ({visible}) => visible && (
<View style={[StyleSheet.absoluteFillObject, styles.fullScreenLoading]}>
<ActivityIndicator color={themeColors.spinner} size="large" />
</View>
);

FullScreenLoadingIndicator.propTypes = propTypes;

export default FullScreenLoadingIndicator;
5 changes: 5 additions & 0 deletions src/components/TextInputFocusable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ const propTypes = {

// Whether or not this TextInput is disabled.
isDisabled: PropTypes.bool,

/* Set focus to this component the first time it renders. Override this in case you need to set focus on one
* field out of many, or when you want to disable autoFocus */
autoFocus: PropTypes.bool,
};

const defaultProps = {
Expand All @@ -49,6 +53,7 @@ const defaultProps = {
onDragLeave: () => {},
onDrop: () => {},
isDisabled: false,
autoFocus: false,
};

const IMAGE_EXTENSIONS = {
Expand Down
10 changes: 10 additions & 0 deletions src/components/TextInputFocusable/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,20 @@ const propTypes = {

// When the input has cleared whoever owns this input should know about it
onClear: PropTypes.func,

/* Set focus to this component the first time it renders. Override this in case you need to set focus on one
* field out of many, or when you want to disable autoFocus */
autoFocus: PropTypes.bool,

/* Prevent edits and interactions like focus for this input. */
isDisabled: PropTypes.bool,
};

const defaultProps = {
shouldClear: false,
onClear: () => {},
autoFocus: false,
isDisabled: false,
};

class TextInputFocusable extends React.Component {
Expand All @@ -48,6 +57,7 @@ class TextInputFocusable extends React.Component {
ref={el => this.textInput = el}
maxHeight={116}
rejectResponderTermination={false}
editable={!this.props.isDisabled}
kidroca marked this conversation as resolved.
Show resolved Hide resolved
/* eslint-disable-next-line react/jsx-props-no-spreading */
{...this.props}
/>
Expand Down
25 changes: 25 additions & 0 deletions src/components/withDrawerState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import PropTypes from 'prop-types';
import {useIsDrawerOpen} from '@react-navigation/drawer';
import getComponentDisplayName from '../libs/getComponentDisplayName';

export const withDrawerPropTypes = {
isDrawerOpen: PropTypes.bool.isRequired,
};

export default function withDrawerState(WrappedComponent) {
const HOC_Wrapper = (props) => {
const isDrawerOpen = useIsDrawerOpen();
kidroca marked this conversation as resolved.
Show resolved Hide resolved

return (
<WrappedComponent
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
isDrawerOpen={isDrawerOpen}
/>
);
};

HOC_Wrapper.displayName = `withDrawerState(${getComponentDisplayName(WrappedComponent)})`;
return HOC_Wrapper;
}
117 changes: 78 additions & 39 deletions src/pages/home/ReportScreen.js
Original file line number Diff line number Diff line change
@@ -1,54 +1,93 @@
import React from 'react';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import {View} from 'react-native';
import styles from '../../styles/styles';
import ReportView from './report/ReportView';
import ScreenWrapper from '../../components/ScreenWrapper';
import HeaderView from './HeaderView';
import Navigation from '../../libs/Navigation/Navigation';
import ROUTES from '../../ROUTES';
import ONYXKEYS from '../../ONYXKEYS';
import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator';

const propTypes = {
// id of the most recently viewed report
currentlyViewedReportID: PropTypes.string,
/* Navigation route context info provided by react navigation */
route: PropTypes.shape({
/* Route specific parameters used on this screen */
params: PropTypes.shape({
/* The ID of the report this screen should display */
reportID: PropTypes.string,
}).isRequired,
}).isRequired,
};

const defaultProps = {
currentlyViewedReportID: '0',
};
class ReportScreen extends React.Component {
constructor(props) {
super(props);

const ReportScreen = (props) => {
const activeReportID = parseInt(props.currentlyViewedReportID, 10);
if (!activeReportID) {
return null;
}

return (
<ScreenWrapper
style={[
styles.appContent,
styles.flex1,
styles.flexColumn,
]}
>
<HeaderView
reportID={activeReportID}
onNavigationMenuButtonClicked={() => Navigation.navigate(ROUTES.HOME)}
/>
<View style={[styles.dFlex, styles.flex1]}>
<ReportView reportID={activeReportID} />
</View>
</ScreenWrapper>
);
};
this.state = {
isLoading: true,
};
}

componentDidMount() {
this.prepareTransition();
}

componentDidUpdate(prevProps) {
const reportChanged = this.props.route.params.reportID !== prevProps.route.params.reportID;

if (reportChanged) {
this.prepareTransition();
}
}

componentWillUnmount() {
clearTimeout(this.loadingTimerId);
}

/**
* Get the currently viewed report ID as number
*
* @returns {Number}
*/
getReportID() {
const params = this.props.route.params;
return Number.parseInt(params.reportID, 10);
}

/**
* When reports change there's a brief time content is not ready to be displayed
*
* @returns {Boolean}
*/
shouldShowLoader() {
return this.state.isLoading || !this.getReportID();
}

/**
* Configures a small loading transition of fixed time and proceeds with rendering available data
*/
prepareTransition() {
this.setState({isLoading: true});

clearTimeout(this.loadingTimerId);
this.loadingTimerId = setTimeout(() => this.setState({isLoading: false}), 300);
}

render() {
return (
<ScreenWrapper style={[styles.appContent, styles.flex1]}>
<HeaderView
reportID={this.getReportID()}
onNavigationMenuButtonClicked={() => Navigation.navigate(ROUTES.HOME)}
/>

<FullScreenLoadingIndicator visible={this.shouldShowLoader()} />

<ReportView reportID={this.getReportID()} />
</ScreenWrapper>
);
}
}

ReportScreen.displayName = 'ReportScreen';
ReportScreen.propTypes = propTypes;
ReportScreen.defaultProps = defaultProps;
export default withOnyx({
currentlyViewedReportID: {
key: ONYXKEYS.CURRENTLY_VIEWED_REPORTID,
},
})(ReportScreen);
export default ReportScreen;
22 changes: 13 additions & 9 deletions src/pages/home/report/ReportActionCompose.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import AttachmentPicker from '../../../components/AttachmentPicker';
import {addAction, saveReportComment, broadcastUserIsTyping} from '../../../libs/actions/Report';
import ReportTypingIndicator from './ReportTypingIndicator';
import AttachmentModal from '../../../components/AttachmentModal';
import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
import compose from '../../../libs/compose';
import CreateMenu from '../../../components/CreateMenu';
import Navigation from '../../../libs/Navigation/Navigation';
import withWindowDimensions from '../../../components/withWindowDimensions';
import withDrawerState from '../../../components/withDrawerState';

const propTypes = {
// A method to call when the form is submitted
Expand All @@ -42,7 +42,11 @@ const propTypes = {
participants: PropTypes.arrayOf(PropTypes.string),
}).isRequired,

...windowDimensionsPropTypes,
/* Is the report view covered by the drawer */
isDrawerOpen: PropTypes.bool.isRequired,

/* Is the window width narrow, like on a mobile device */
isSmallScreenWidth: PropTypes.bool.isRequired,
};

const defaultProps = {
Expand Down Expand Up @@ -182,13 +186,12 @@ class ReportActionCompose extends React.Component {
}

render() {
// We want to make sure to disable on small screens because in iOS safari the keyboard up/down buttons will
// focus this from the chat switcher.
// https://github.com/Expensify/Expensify.cash/issues/1228
const inputDisable = this.props.isSmallScreenWidth && Navigation.isDrawerOpen();
kidroca marked this conversation as resolved.
Show resolved Hide resolved
// eslint-disable-next-line no-unused-vars
const hasMultipleParticipants = lodashGet(this.props.report, 'participants.length') > 1;

// Prevents focusing and showing the keyboard while the drawer is covering the chat.
const isComposeDisabled = this.props.isDrawerOpen && this.props.isSmallScreenWidth;

return (
<View style={[styles.chatItemCompose]}>
<View style={[
Expand Down Expand Up @@ -288,7 +291,7 @@ class ReportActionCompose extends React.Component {
onPasteFile={file => displayFileInModal({file})}
shouldClear={this.state.textInputShouldClear}
onClear={() => this.setTextInputShouldClear(false)}
isDisabled={inputDisable}
isDisabled={isComposeDisabled}
/>

</>
Expand All @@ -315,6 +318,8 @@ ReportActionCompose.propTypes = propTypes;
ReportActionCompose.defaultProps = defaultProps;

export default compose(
withWindowDimensions,
withDrawerState,
withOnyx({
comment: {
key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`,
Expand All @@ -326,5 +331,4 @@ export default compose(
key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
},
}),
withWindowDimensions,
)(ReportActionCompose);
Loading