Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
143 changes: 75 additions & 68 deletions src/components/AvatarCropModal/AvatarCropModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import HeaderGap from '../HeaderGap';
import * as StyleUtils from '../../styles/StyleUtils';
import Tooltip from '../Tooltip';
import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
import ScreenWrapper from '../ScreenWrapper';

const propTypes = {
/** Link to image for cropping */
Expand Down Expand Up @@ -361,79 +362,85 @@ function AvatarCropModal(props) {
type={CONST.MODAL.MODAL_TYPE.RIGHT_DOCKED}
onModalHide={resetState}
>
{props.isSmallScreenWidth && <HeaderGap />}
<HeaderWithBackButton
title={props.translate('avatarCropModal.title')}
onBackButtonPress={props.onClose}
/>
<Text style={[styles.mh5]}>{props.translate('avatarCropModal.description')}</Text>
<GestureHandlerRootView
onLayout={initializeImageContainer}
style={[styles.alignSelfStretch, styles.m5, styles.flex1, styles.alignItemsCenter]}
<ScreenWrapper

@eVoloshchak eVoloshchak Aug 7, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hungvu193, can we just wrap BaseModal with the screen wrapper? That would add offline indicator to all the modals

@hungvu193 hungvu193 Aug 8, 2023

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eVoloshchak I don't think we should, BaseModal is also being used for ConfirmModal as well, that's being said, if we wrapped it with ScreenWrapper, we can also see the OfflineIndicator at the bottom of it.
The best way to do that is wrapping ScreenWrapper with any modal that's full screen modal.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The best way to do that is wrapping ScreenWrapper with any modal that's full screen modal

Is there a way we could detect that? The current approach is also fine, but I'm wondering if we could have a more universal solution

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can update the document, every time we create a new full screen modal, we should wrap their content inside ScreenWrapper like we're doing that with our normal screens. There are only few full screen modals in our app, so I think the current approach is just fine.

style={[styles.pb0]}
includePaddingTop={false}
includeSafeAreaPaddingBottom={false}
>
{/* To avoid layout shift we should hide this component until the image container & image is initialized */}
{!isImageInitialized || !isImageContainerInitialized ? (
<ActivityIndicator
color={themeColors.spinner}
style={[styles.flex1]}
size="large"
/>
) : (
<>
<ImageCropView
imageUri={props.imageUri}
containerSize={imageContainerSize}
panGestureEventHandler={panGestureEventHandler}
originalImageHeight={originalImageHeight}
originalImageWidth={originalImageWidth}
scale={scale}
translateY={translateY}
translateX={translateX}
rotation={rotation}
maskImage={props.maskImage}
{props.isSmallScreenWidth && <HeaderGap />}
<HeaderWithBackButton
title={props.translate('avatarCropModal.title')}
onBackButtonPress={props.onClose}
/>
<Text style={[styles.mh5]}>{props.translate('avatarCropModal.description')}</Text>
<GestureHandlerRootView
onLayout={initializeImageContainer}
style={[styles.alignSelfStretch, styles.m5, styles.flex1, styles.alignItemsCenter]}
>
{/* To avoid layout shift we should hide this component until the image container & image is initialized */}
{!isImageInitialized || !isImageContainerInitialized ? (
<ActivityIndicator
color={themeColors.spinner}
style={[styles.flex1]}
size="large"
/>
<View style={[styles.mt5, styles.justifyContentBetween, styles.alignItemsCenter, styles.flexRow, StyleUtils.getWidthStyle(imageContainerSize)]}>
<Icon
src={Expensicons.Zoom}
fill={themeColors.icons}
) : (
<>
<ImageCropView
imageUri={props.imageUri}
containerSize={imageContainerSize}
panGestureEventHandler={panGestureEventHandler}
originalImageHeight={originalImageHeight}
originalImageWidth={originalImageWidth}
scale={scale}
translateY={translateY}
translateX={translateX}
rotation={rotation}
maskImage={props.maskImage}
/>
<PressableWithoutFeedback
style={[styles.mh5, styles.flex1]}
onLayout={initializeSliderContainer}
onPressIn={(e) => runOnUI(sliderOnPress)(e.nativeEvent.locationX)}
accessibilityLabel="slider"
accessibilityRole={CONST.ACCESSIBILITY_ROLE.ADJUSTABLE}
>
<Slider
sliderValue={translateSlider}
onGesture={panSliderGestureEventHandler}
<View style={[styles.mt5, styles.justifyContentBetween, styles.alignItemsCenter, styles.flexRow, StyleUtils.getWidthStyle(imageContainerSize)]}>
<Icon
src={Expensicons.Zoom}
fill={themeColors.icons}
/>
</PressableWithoutFeedback>
<Tooltip
text={props.translate('common.rotate')}
shiftVertical={-2}
>
<View>
<Button
medium
icon={Expensicons.Rotate}
iconFill={themeColors.inverse}
iconStyles={[styles.mr0]}
onPress={rotateImage}
<PressableWithoutFeedback
style={[styles.mh5, styles.flex1]}
onLayout={initializeSliderContainer}
onPressIn={(e) => runOnUI(sliderOnPress)(e.nativeEvent.locationX)}
accessibilityLabel="slider"
accessibilityRole={CONST.ACCESSIBILITY_ROLE.ADJUSTABLE}
>
<Slider
sliderValue={translateSlider}
onGesture={panSliderGestureEventHandler}
/>
</View>
</Tooltip>
</View>
</>
)}
</GestureHandlerRootView>
<Button
success
style={[styles.m5]}
onPress={cropAndSaveImage}
pressOnEnter
text={props.translate('common.save')}
/>
</PressableWithoutFeedback>
<Tooltip
text={props.translate('common.rotate')}
shiftVertical={-2}
>
<View>
<Button
medium
icon={Expensicons.Rotate}
iconFill={themeColors.inverse}
iconStyles={[styles.mr0]}
onPress={rotateImage}
/>
</View>
</Tooltip>
</View>
</>
)}
</GestureHandlerRootView>
<Button
success
style={[styles.m5]}
onPress={cropAndSaveImage}
pressOnEnter
text={props.translate('common.save')}
/>
</ScreenWrapper>
</Modal>
);
}
Expand Down
42 changes: 25 additions & 17 deletions src/components/CountryPicker/CountrySelectorModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import useLocalize from '../../hooks/useLocalize';
import HeaderWithBackButton from '../HeaderWithBackButton';
import SelectionListRadio from '../SelectionListRadio';
import Modal from '../Modal';
import ScreenWrapper from '../ScreenWrapper';
import styles from '../../styles/styles';
import searchCountryOptions from '../../libs/searchCountryOptions';

const propTypes = {
Expand Down Expand Up @@ -61,23 +63,29 @@ function CountrySelectorModal({currentCountry, isVisible, onClose, onCountrySele
hideModalContentWhileAnimating
useNativeDriver
>
<HeaderWithBackButton
title={translate('common.country')}
onBackButtonPress={onClose}
/>
<SelectionListRadio
headerMessage={headerMessage}
textInputLabel={translate('common.country')}
textInputPlaceholder={translate('countrySelectorModal.placeholderText')}
textInputValue={searchValue}
sections={[{data: searchResults, indexOffset: 0}]}
onSelectRow={onCountrySelected}
onChangeText={setSearchValue}
shouldFocusOnSelectRow
shouldHaveOptionSeparator
shouldDelayFocus
initiallyFocusedOptionKey={currentCountry}
/>
<ScreenWrapper
style={[styles.pb0]}
includePaddingTop={false}
includeSafeAreaPaddingBottom={false}
>
<HeaderWithBackButton
title={translate('common.country')}
onBackButtonPress={onClose}
/>
<SelectionListRadio
headerMessage={headerMessage}
textInputLabel={translate('common.country')}
textInputPlaceholder={translate('countrySelectorModal.placeholderText')}
textInputValue={searchValue}
sections={[{data: searchResults, indexOffset: 0}]}
onSelectRow={onCountrySelected}
onChangeText={setSearchValue}
shouldFocusOnSelectRow
shouldHaveOptionSeparator
shouldDelayFocus
initiallyFocusedOptionKey={currentCountry}
/>
</ScreenWrapper>
</Modal>
);
}
Expand Down
40 changes: 24 additions & 16 deletions src/components/NewDatePicker/CalendarPicker/YearPickerModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import SelectionListRadio from '../../SelectionListRadio';
import Modal from '../../Modal';
import {radioListItemPropTypes} from '../../SelectionListRadio/selectionListRadioPropTypes';
import useLocalize from '../../../hooks/useLocalize';
import ScreenWrapper from '../../ScreenWrapper';
import styles from '../../../styles/styles';

const propTypes = {
/** Whether the modal is visible */
Expand Down Expand Up @@ -58,22 +60,28 @@ function YearPickerModal(props) {
hideModalContentWhileAnimating
useNativeDriver
>
<HeaderWithBackButton
title={translate('yearPickerPage.year')}
onBackButtonPress={props.onClose}
/>
<SelectionListRadio
shouldDelayFocus
textInputLabel={translate('yearPickerPage.selectYear')}
textInputValue={searchText}
textInputMaxLength={4}
onChangeText={(text) => setSearchText(text.replace(CONST.REGEX.NON_NUMERIC, '').trim())}
keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD}
headerMessage={headerMessage}
sections={sections}
onSelectRow={(option) => props.onYearChange(option.value)}
initiallyFocusedOptionKey={props.currentYear.toString()}
/>
<ScreenWrapper
style={[styles.pb0]}
includePaddingTop={false}
includeSafeAreaPaddingBottom={false}
>
<HeaderWithBackButton
title={translate('yearPickerPage.year')}
onBackButtonPress={props.onClose}
/>
<SelectionListRadio
shouldDelayFocus
textInputLabel={translate('yearPickerPage.selectYear')}
textInputValue={searchText}
textInputMaxLength={4}
onChangeText={(text) => setSearchText(text.replace(CONST.REGEX.NON_NUMERIC, '').trim())}
keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD}
headerMessage={headerMessage}
sections={sections}
onSelectRow={(option) => props.onYearChange(option.value)}
initiallyFocusedOptionKey={props.currentYear.toString()}
/>
</ScreenWrapper>
</Modal>
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/ScreenWrapper/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class ScreenWrapper extends React.Component {
{...(this.props.environment === CONST.ENVIRONMENT.DEV ? this.panResponder.panHandlers : {})}
>
<View
style={[...this.props.style, styles.flex1, paddingStyle]}
style={[styles.flex1, paddingStyle, ...this.props.style]}
// eslint-disable-next-line react/jsx-props-no-spreading
{...this.keyboardDissmissPanResponder.panHandlers}
>
Expand Down
44 changes: 26 additions & 18 deletions src/components/StatePicker/StateSelectorModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import Modal from '../Modal';
import HeaderWithBackButton from '../HeaderWithBackButton';
import SelectionListRadio from '../SelectionListRadio';
import useLocalize from '../../hooks/useLocalize';
import ScreenWrapper from '../ScreenWrapper';
import styles from '../../styles/styles';
import searchCountryOptions from '../../libs/searchCountryOptions';

const propTypes = {
Expand Down Expand Up @@ -65,24 +67,30 @@ function StateSelectorModal({currentState, isVisible, onClose, onStateSelected,
hideModalContentWhileAnimating
useNativeDriver
>
<HeaderWithBackButton
title={label || translate('common.state')}
shouldShowBackButton
onBackButtonPress={onClose}
/>
<SelectionListRadio
headerMessage={headerMessage}
textInputLabel={label || translate('common.state')}
textInputPlaceholder={translate('stateSelectorModal.placeholderText')}
textInputValue={searchValue}
sections={[{data: searchResults, indexOffset: 0}]}
onSelectRow={onStateSelected}
onChangeText={setSearchValue}
shouldFocusOnSelectRow
shouldHaveOptionSeparator
shouldDelayFocus
initiallyFocusedOptionKey={currentState}
/>
<ScreenWrapper
style={[styles.pb0]}
includePaddingTop={false}
includeSafeAreaPaddingBottom={false}
>
<HeaderWithBackButton
title={label || translate('common.state')}
shouldShowBackButton
onBackButtonPress={onClose}
/>
<SelectionListRadio
headerMessage={headerMessage}
textInputLabel={label || translate('common.state')}
textInputPlaceholder={translate('stateSelectorModal.placeholderText')}
textInputValue={searchValue}
sections={[{data: searchResults, indexOffset: 0}]}
onSelectRow={onStateSelected}
onChangeText={setSearchValue}
shouldFocusOnSelectRow
shouldHaveOptionSeparator
shouldDelayFocus
initiallyFocusedOptionKey={currentState}
/>
</ScreenWrapper>
</Modal>
);
}
Expand Down