MM-14921 Fix iPad layout including safeAreaInsets (#2748)

* MM-14780 and MM-14921 Fix iPad layout including safeAreaInsets

* Fix unit tests
This commit is contained in:
Elias Nahum 2019-05-03 17:42:32 -04:00 committed by Harrison Healey
parent d213565ebb
commit 08df256c1d
10 changed files with 66 additions and 13 deletions

View file

@ -19,6 +19,7 @@ import IonIcon from 'react-native-vector-icons/Ionicons';
import FormattedText from 'app/components/formatted_text';
import {DeviceTypes, ViewTypes} from 'app/constants';
import mattermostBucket from 'app/mattermost_bucket';
import mattermostManaged from 'app/mattermost_managed';
import PushNotifications from 'app/push_notifications';
import networkConnectionListener, {checkConnection} from 'app/utils/network';
import {t} from 'app/utils/i18n';
@ -35,6 +36,7 @@ const {
IOS_TOP_LANDSCAPE,
IOS_TOP_PORTRAIT,
IOSX_TOP_PORTRAIT,
STATUS_BAR_HEIGHT,
} = ViewTypes;
export default class NetworkIndicator extends PureComponent {
@ -202,6 +204,8 @@ export default class NetworkIndicator extends PureComponent {
return IOS_TOP_LANDSCAPE;
} else if (isX) {
return IOSX_TOP_PORTRAIT;
} else if (isLandscape && DeviceTypes.IS_TABLET && mattermostManaged.hasSafeAreaInsets) {
return IOS_TOP_LANDSCAPE + STATUS_BAR_HEIGHT;
} else if (isLandscape) {
return IOS_TOP_LANDSCAPE;
}

View file

@ -153,7 +153,7 @@ export default class PostListBase extends PureComponent {
navigator: this.props.navigator,
onHashtagPress: this.props.onHashtagPress,
onPermalinkPress: this.handlePermalinkPress,
onPostPress: this.props.onPostPress,
onPress: this.props.onPostPress,
renderReplies: this.props.renderReplies,
shouldRenderReplyButton: this.props.shouldRenderReplyButton,
};

View file

@ -7,6 +7,7 @@ import {Dimensions, Keyboard, NativeModules, View} from 'react-native';
import SafeArea from 'react-native-safe-area';
import {DeviceTypes} from 'app/constants';
import mattermostManaged from 'app/mattermost_managed';
const {StatusBarManager} = NativeModules;
@ -41,7 +42,7 @@ export default class SafeAreaIos extends PureComponent {
safeAreaInsets: {
top: DeviceTypes.IS_IPHONE_X ? 44 : 20,
left: 0,
bottom: DeviceTypes.IS_IPHONE_X ? 34 : 15,
bottom: DeviceTypes.IS_IPHONE_X || mattermostManaged.hasSafeAreaInsets ? 20 : 0,
right: 0,
},
statusBarHeight: 20,
@ -86,7 +87,7 @@ export default class SafeAreaIos extends PureComponent {
getSafeAreaInsets = () => {
this.getStatusBarHeight();
if (DeviceTypes.IS_IPHONE_X) {
if (DeviceTypes.IS_IPHONE_X || mattermostManaged.hasSafeAreaInsets) {
SafeArea.getSafeAreaInsetsForRootView().then((result) => {
const {safeAreaInsets} = result;
@ -173,7 +174,7 @@ export default class SafeAreaIos extends PureComponent {
}
let offset = 0;
if (keyboardOffset && DeviceTypes.IS_IPHONE_X) {
if (keyboardOffset && mattermostManaged.hasSafeAreaInsets) {
offset = keyboardOffset;
}
@ -186,7 +187,7 @@ export default class SafeAreaIos extends PureComponent {
>
{this.renderTopBar()}
{children}
<View style={{height: keyboard ? offset : safeAreaInsets.bottom - 15, backgroundColor: bottomColor}}>
<View style={{height: keyboard ? offset : safeAreaInsets.bottom, backgroundColor: bottomColor}}>
{footerComponent}
</View>
</View>

View file

@ -12,10 +12,11 @@ import {
} from 'react-native-gesture-handler';
import {DeviceTypes} from 'app/constants';
import mattermostManaged from 'app/mattermost_managed';
import SlideUpPanelIndicator from './slide_up_panel_indicator';
export const BOTTOM_MARGIN = DeviceTypes.IS_IPHONE_X ? 24 : 0;
export const BOTTOM_MARGIN = mattermostManaged.hasSafeAreaInsets ? 24 : 0;
const TOP_IOS_MARGIN = DeviceTypes.IS_IPHONE_X ? 84 : 64;
const TOP_ANDROID_MARGIN = 44;
const TOP_MARGIN = Platform.OS === 'ios' ? TOP_IOS_MARGIN : TOP_ANDROID_MARGIN;

View file

@ -18,5 +18,6 @@ export default {
DOCUMENTS_PATH: `${RNFetchBlobFS.dirs.CacheDir}/Documents`,
IMAGES_PATH: `${RNFetchBlobFS.dirs.CacheDir}/Images`,
IS_IPHONE_X: DeviceInfo.getModel().includes('iPhone X'),
IS_TABLET: DeviceInfo.isTablet(),
VIDEOS_PATH: `${RNFetchBlobFS.dirs.CacheDir}/Videos`,
};

View file

@ -48,6 +48,7 @@ export default {
getCachedConfig: () => {
return cachedConfig;
},
hasSafeAreaInsets: MattermostManaged.hasSafeAreaInsets,
isDeviceSecure: async () => {
try {
return await LocalAuth.isDeviceSecure();

View file

@ -10,8 +10,8 @@ exports[`PostOptions should match snapshot, no option for system message to user
>
<Connect(SlideUpPanel)
allowStayMiddle={false}
initialPosition={274}
marginFromTop={326}
initialPosition={250}
marginFromTop={350}
onRequestClose={[Function]}
>
<PostOption
@ -48,8 +48,8 @@ exports[`PostOptions should match snapshot, showing Delete option only for syste
>
<Connect(SlideUpPanel)
allowStayMiddle={false}
initialPosition={324}
marginFromTop={276}
initialPosition={300}
marginFromTop={300}
onRequestClose={[Function]}
>
<PostOption
@ -92,8 +92,8 @@ exports[`PostOptions should match snapshot, showing all possible options 1`] = `
>
<Connect(SlideUpPanel)
allowStayMiddle={false}
initialPosition={324}
marginFromTop={276}
initialPosition={300}
marginFromTop={300}
onRequestClose={[Function]}
>
<PostOption

View file

@ -8,6 +8,7 @@
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#import <React/RCTUtils.h>
@interface MattermostManaged : RCTEventEmitter <RCTBridgeModule>
- (NSUserDefaults *)bucketByName:(NSString*)name;

View file

@ -28,6 +28,49 @@ RCT_EXPORT_MODULE();
hasListeners = NO;
}
- (BOOL)hasSafeAreaInsets {
UIView *rootView = nil;
UIApplication *sharedApplication = RCTSharedApplication();
if (sharedApplication) {
UIWindow *window = RCTSharedApplication().keyWindow;
if (window) {
UIViewController *rootViewController = window.rootViewController;
if (rootViewController) {
rootView = rootViewController.view;
}
}
}
UIEdgeInsets safeAreaInsets = [self safeAreaInsetsForView:rootView];
return safeAreaInsets.bottom > 0;
}
- (UIEdgeInsets)safeAreaInsetsForView:(UIView *)view {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
if (@available(iOS 11.0, *)) {
if (view) {
return view.safeAreaInsets;
}
}
#endif
UIEdgeInsets safeAreaInsets = UIEdgeInsetsMake(0, 0, 0, 0);
if (view) {
return safeAreaInsets;
}
return safeAreaInsets;
}
- (NSDictionary *)constantsToExport {
return @{
@"hasSafeAreaInsets": @([self hasSafeAreaInsets]),
};
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
@ -115,7 +158,7 @@ RCT_EXPORT_METHOD(quitApp)
return NO;
}
}
return [super canPerformAction:action withSender:sender];
}

View file

@ -38,6 +38,7 @@ jest.mock('react-native-device-info', () => {
getVersion: () => '0.0.0',
getBuildNumber: () => '0',
getModel: () => 'iPhone X',
isTablet: () => false,
};
});