diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index e3d966fce..4fff02aa5 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -44,7 +44,8 @@
android:exported="false" />
+ android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
+ android:resizeableActivity="true"/>
{
@@ -124,6 +133,15 @@ export default class ChannelSidebar extends Component {
return false;
};
+ handleDimensions = () => {
+ if (DeviceTypes.IS_TABLET && this.mounted) {
+ mattermostManaged.isRunningInSplitView().then((result) => {
+ const isSplitView = Boolean(result.isSplitView);
+ this.setState({isSplitView});
+ });
+ }
+ };
+
handleShowDrawerContent = () => {
this.setState({show: true});
};
@@ -380,6 +398,7 @@ export default class ChannelSidebar extends Component {
render() {
const {children, deviceWidth} = this.props;
const {openDrawerOffset} = this.state;
+ const isTablet = DeviceTypes.IS_TABLET && !this.state.isSplitView;
const drawerWidth = DeviceTypes.IS_TABLET ? TABLET_WIDTH : (deviceWidth - openDrawerOffset);
return (
@@ -390,7 +409,7 @@ export default class ChannelSidebar extends Component {
onDrawerOpen={this.handleDrawerOpen}
drawerWidth={drawerWidth}
useNativeAnimations={true}
- isTablet={DeviceTypes.IS_TABLET}
+ isTablet={isTablet}
>
{children}
diff --git a/app/mattermost.js b/app/mattermost.js
index 0d11b7154..5f82d5d70 100644
--- a/app/mattermost.js
+++ b/app/mattermost.js
@@ -405,7 +405,7 @@ const launchSelectServer = () => {
});
};
-const launchChannel = () => {
+const launchChannel = (skipMetrics = false) => {
Navigation.startSingleScreenApp({
screen: {
screen: 'Channel',
@@ -415,6 +415,9 @@ const launchChannel = () => {
statusBarHideWithNavBar: false,
screenBackgroundColor: 'transparent',
},
+ passProps: {
+ skipMetrics,
+ },
},
appStyle: {
orientation: 'auto',
@@ -513,14 +516,19 @@ const fromPushNotification = Platform.OS === 'android' && Initialization.replyFr
if (startedSharedExtension || fromPushNotification) {
// Hold on launching Entry screen
app.setAppStarted(true);
-
- // Listen for when the user opens the app
- new NativeEventsReceiver().appLaunched(() => {
- app.setAppStarted(false);
- launchEntry();
- });
}
if (!app.appStarted) {
launchEntry();
}
+
+new NativeEventsReceiver().appLaunched(() => {
+ if (startedSharedExtension || fromPushNotification) {
+ app.setAppStarted(false);
+ launchEntry();
+ } else if (app.token && app.url) {
+ launchChannel(true);
+ } else {
+ launchSelectServer();
+ }
+});
diff --git a/app/mattermost_managed/mattermost-managed.android.js b/app/mattermost_managed/mattermost-managed.android.js
index da192cb58..3cdd00095 100644
--- a/app/mattermost_managed/mattermost-managed.android.js
+++ b/app/mattermost_managed/mattermost-managed.android.js
@@ -36,6 +36,7 @@ export default {
},
authenticate: LocalAuth.auth,
blurAppScreen: MattermostManaged.blurAppScreen,
+ isRunningInSplitView: MattermostManaged.isRunningInSplitView,
getConfig: async () => {
try {
cachedConfig = await MattermostManaged.getConfig();
diff --git a/app/mattermost_managed/mattermost-managed.ios.js b/app/mattermost_managed/mattermost-managed.ios.js
index 7b6d81525..9c2415da2 100644
--- a/app/mattermost_managed/mattermost-managed.ios.js
+++ b/app/mattermost_managed/mattermost-managed.ios.js
@@ -52,6 +52,7 @@ export default {
return cachedConfig;
},
hasSafeAreaInsets: MattermostManaged.hasSafeAreaInsets,
+ isRunningInSplitView: MattermostManaged.isRunningInSplitView,
isDeviceSecure: async () => {
try {
return await LocalAuth.isDeviceSecure();
diff --git a/app/screens/channel/channel_base.js b/app/screens/channel/channel_base.js
index da40eacda..7dd030714 100644
--- a/app/screens/channel/channel_base.js
+++ b/app/screens/channel/channel_base.js
@@ -48,6 +48,7 @@ export default class ChannelBase extends PureComponent {
theme: PropTypes.object.isRequired,
showTermsOfService: PropTypes.bool,
disableTermsModal: PropTypes.bool,
+ skipMetrics: PropTypes.bool,
};
static contextTypes = {
@@ -88,7 +89,7 @@ export default class ChannelBase extends PureComponent {
}
componentDidMount() {
- if (tracker.initialLoad) {
+ if (tracker.initialLoad && !this.props.skipMetrics) {
this.props.actions.recordLoadTime('Start time', 'initialLoad');
}
@@ -98,7 +99,9 @@ export default class ChannelBase extends PureComponent {
EventEmitter.emit('renderDrawer');
- telemetry.end(['start:channel_screen']);
+ if (!this.props.skipMetrics) {
+ telemetry.end(['start:channel_screen']);
+ }
}
componentWillReceiveProps(nextProps) {
diff --git a/app/screens/channel/channel_nav_bar/channel_nav_bar.js b/app/screens/channel/channel_nav_bar/channel_nav_bar.js
index d84a2cd6f..6e0a84f40 100644
--- a/app/screens/channel/channel_nav_bar/channel_nav_bar.js
+++ b/app/screens/channel/channel_nav_bar/channel_nav_bar.js
@@ -3,9 +3,10 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
-import {Platform, View} from 'react-native';
+import {Dimensions, Platform, View} from 'react-native';
import {DeviceTypes, ViewTypes} from 'app/constants';
+import mattermostManaged from 'app/mattermost_managed';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
import ChannelDrawerButton from './channel_drawer_button';
@@ -31,6 +32,30 @@ export default class ChannelNavBar extends PureComponent {
theme: PropTypes.object.isRequired,
};
+ state = {
+ isSplitView: false,
+ };
+
+ componentDidMount() {
+ this.mounted = true;
+ this.handleDimensions();
+ Dimensions.addEventListener('change', this.handleDimensions);
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ Dimensions.removeEventListener('change', this.handleDimensions);
+ }
+
+ handleDimensions = () => {
+ if (DeviceTypes.IS_TABLET && this.mounted) {
+ mattermostManaged.isRunningInSplitView().then((result) => {
+ const isSplitView = Boolean(result.isSplitView);
+ this.setState({isSplitView});
+ });
+ }
+ };
+
render() {
const {isLandscape, navigator, onPress, theme} = this.props;
const {openChannelDrawer, openSettingsDrawer} = this.props;
@@ -60,7 +85,7 @@ export default class ChannelNavBar extends PureComponent {
}
let drawerButtonVisible = false;
- if (!DeviceTypes.IS_TABLET) {
+ if (!DeviceTypes.IS_TABLET || this.state.isSplitView) {
drawerButtonVisible = true;
}
diff --git a/ios/Mattermost.xcodeproj/project.pbxproj b/ios/Mattermost.xcodeproj/project.pbxproj
index 33de3701c..78b742f59 100644
--- a/ios/Mattermost.xcodeproj/project.pbxproj
+++ b/ios/Mattermost.xcodeproj/project.pbxproj
@@ -80,6 +80,7 @@
7F581D35221ED5C60099E66B /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F581D34221ED5C60099E66B /* NotificationService.swift */; };
7F581D39221ED5C60099E66B /* NotificationService.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 7F581D32221ED5C60099E66B /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
7F581F78221EEA7C0099E66B /* libUploadAttachments.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FABE04522137F2A00D0F595 /* libUploadAttachments.a */; };
+ 7F5BA34722B99B7B005B05D3 /* Mattermost+RCTUITextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F5BA34622B99B7B005B05D3 /* Mattermost+RCTUITextView.m */; };
7F5CA9A0208FE3B9004F91CE /* libRNDocumentPicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F5CA991208FE38F004F91CE /* libRNDocumentPicker.a */; };
7F642DF02093533300F3165E /* libRNDeviceInfo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F642DED2093530B00F3165E /* libRNDeviceInfo.a */; };
7F72F2EE2211220500F98FFF /* GenericPreview.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7F72F2ED2211220500F98FFF /* GenericPreview.xib */; };
@@ -819,6 +820,8 @@
7F581D34221ED5C60099E66B /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; };
7F581D36221ED5C60099E66B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
7F581F77221EEA5A0099E66B /* NotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NotificationService.entitlements; sourceTree = ""; };
+ 7F5BA34522B99B7B005B05D3 /* Mattermost+RCTUITextView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "Mattermost+RCTUITextView.h"; path = "Mattermost/Mattermost+RCTUITextView.h"; sourceTree = ""; };
+ 7F5BA34622B99B7B005B05D3 /* Mattermost+RCTUITextView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "Mattermost+RCTUITextView.m"; path = "Mattermost/Mattermost+RCTUITextView.m"; sourceTree = ""; };
7F5CA956208FE38F004F91CE /* RNDocumentPicker.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNDocumentPicker.xcodeproj; path = "../node_modules/react-native-document-picker/ios/RNDocumentPicker.xcodeproj"; sourceTree = ""; };
7F63D27B1E6C957C001FAE12 /* RCTPushNotification.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTPushNotification.xcodeproj; path = "../node_modules/react-native/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj"; sourceTree = ""; };
7F63D2C21E6DD98A001FAE12 /* Mattermost.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = Mattermost.entitlements; path = Mattermost/Mattermost.entitlements; sourceTree = ""; };
@@ -1112,6 +1115,8 @@
7FEB109C1F61019C0039A015 /* UIImage+ImageEffects.m */,
7F151D40221B069200FAD8F3 /* 0155-keys.png */,
7F292AA51E8ABB1100A450A3 /* splash.png */,
+ 7F5BA34522B99B7B005B05D3 /* Mattermost+RCTUITextView.h */,
+ 7F5BA34622B99B7B005B05D3 /* Mattermost+RCTUITextView.m */,
);
name = Mattermost;
sourceTree = "";
@@ -2618,6 +2623,7 @@
7FEB10981F6101710039A015 /* BlurAppScreen.m in Sources */,
7FEB109D1F61019C0039A015 /* MattermostManaged.m in Sources */,
7F240ACD220D460300637665 /* MattermostBucketModule.m in Sources */,
+ 7F5BA34722B99B7B005B05D3 /* Mattermost+RCTUITextView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/ios/Mattermost/Mattermost+RCTUITextView.h b/ios/Mattermost/Mattermost+RCTUITextView.h
new file mode 100644
index 000000000..67057d05e
--- /dev/null
+++ b/ios/Mattermost/Mattermost+RCTUITextView.h
@@ -0,0 +1,17 @@
+//
+// Mattermost+RCTUITextView.h
+// Mattermost
+//
+// Created by Elias Nahum on 6/18/19.
+// Copyright © 2019 Facebook. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface Mattermost_RCTUITextView : NSObject
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/ios/Mattermost/Mattermost+RCTUITextView.m b/ios/Mattermost/Mattermost+RCTUITextView.m
new file mode 100644
index 000000000..505798bbc
--- /dev/null
+++ b/ios/Mattermost/Mattermost+RCTUITextView.m
@@ -0,0 +1,36 @@
+//
+// Mattermost+RCTUITextView.m
+// Mattermost
+//
+// Created by Elias Nahum on 6/18/19.
+// Copyright © 2019 Facebook. All rights reserved.
+//
+
+#import "Mattermost+RCTUITextView.h"
+#import "RCTUITextView.h"
+
+@implementation Mattermost_RCTUITextView
+
+@end
+
+@implementation RCTUITextView (DisableCopyPaste)
+
+- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
+{
+ NSDictionary *response = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"com.apple.configuration.managed"];
+ if(response) {
+ NSString *copyPasteProtection = response[@"copyAndPasteProtection"];
+ BOOL prevent = action == @selector(paste:) ||
+ action == @selector(copy:) ||
+ action == @selector(cut:) ||
+ action == @selector(_share:);
+
+ if ([copyPasteProtection isEqual: @"true"] && prevent) {
+ return NO;
+ }
+ }
+
+ return [super canPerformAction:action withSender:sender];
+}
+
+@end
diff --git a/ios/Mattermost/MattermostManaged.m b/ios/Mattermost/MattermostManaged.m
index 4000f5902..b2f5c5ce1 100644
--- a/ios/Mattermost/MattermostManaged.m
+++ b/ios/Mattermost/MattermostManaged.m
@@ -6,7 +6,6 @@
// See License.txt for license information.
//
-#import "RCTUITextView.h"
#import "MattermostManaged.h"
#import
@@ -152,31 +151,19 @@ RCT_EXPORT_METHOD(getConfig:(RCTPromiseResolveBlock)resolve
}
}
+RCT_EXPORT_METHOD(isRunningInSplitView:(RCTPromiseResolveBlock)resolve
+ rejecter:(RCTPromiseRejectBlock)reject) {
+ BOOL isRunningInFullScreen = CGRectEqualToRect(
+ [UIApplication sharedApplication].delegate.window.frame,
+ [UIApplication sharedApplication].delegate.window.screen.bounds);
+ resolve(@{
+ @"isSplitView": @(!isRunningInFullScreen)
+ });
+}
+
RCT_EXPORT_METHOD(quitApp)
{
exit(0);
}
@end
-
-@implementation RCTUITextView (DisableCopyPaste)
-
-- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
-{
- NSDictionary *response = [[NSUserDefaults standardUserDefaults] dictionaryForKey:configurationKey];
- if(response) {
- NSString *copyPasteProtection = response[@"copyAndPasteProtection"];
- BOOL prevent = action == @selector(paste:) ||
- action == @selector(copy:) ||
- action == @selector(cut:) ||
- action == @selector(_share:);
-
- if ([copyPasteProtection isEqual: @"true"] && prevent) {
- return NO;
- }
- }
-
- return [super canPerformAction:action withSender:sender];
-}
-
-@end