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:
parent
d213565ebb
commit
08df256c1d
10 changed files with 66 additions and 13 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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`,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ export default {
|
|||
getCachedConfig: () => {
|
||||
return cachedConfig;
|
||||
},
|
||||
hasSafeAreaInsets: MattermostManaged.hasSafeAreaInsets,
|
||||
isDeviceSecure: async () => {
|
||||
try {
|
||||
return await LocalAuth.isDeviceSecure();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTEventEmitter.h>
|
||||
#import <React/RCTUtils.h>
|
||||
|
||||
@interface MattermostManaged : RCTEventEmitter <RCTBridgeModule>
|
||||
- (NSUserDefaults *)bucketByName:(NSString*)name;
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ jest.mock('react-native-device-info', () => {
|
|||
getVersion: () => '0.0.0',
|
||||
getBuildNumber: () => '0',
|
||||
getModel: () => 'iPhone X',
|
||||
isTablet: () => false,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue