forked from Ivasoft/mattermost-mobile
Compare commits
9 Commits
release-1.
...
release-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e08d69b10 | ||
|
|
a8a95a98e7 | ||
|
|
b4b23d4d46 | ||
|
|
99cff03193 | ||
|
|
b9864bf26f | ||
|
|
e73b9017fc | ||
|
|
f65820dd0c | ||
|
|
7564ac023c | ||
|
|
5ef83639e9 |
1
Makefile
1
Makefile
@@ -76,6 +76,7 @@ post-install:
|
|||||||
@sed -i'' -e 's|"./locale-data/complete.js": false|"./locale-data/complete.js": "./locale-data/complete.js"|g' node_modules/intl/package.json
|
@sed -i'' -e 's|"./locale-data/complete.js": false|"./locale-data/complete.js": "./locale-data/complete.js"|g' node_modules/intl/package.json
|
||||||
@sed -i'' -e 's|auto("auto", Configuration.ORIENTATION_UNDEFINED, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);|auto("auto", Configuration.ORIENTATION_UNDEFINED, ActivityInfo.SCREEN_ORIENTATION_FULL_USER);|g' node_modules/react-native-navigation/android/app/src/main/java/com/reactnativenavigation/params/Orientation.java
|
@sed -i'' -e 's|auto("auto", Configuration.ORIENTATION_UNDEFINED, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);|auto("auto", Configuration.ORIENTATION_UNDEFINED, ActivityInfo.SCREEN_ORIENTATION_FULL_USER);|g' node_modules/react-native-navigation/android/app/src/main/java/com/reactnativenavigation/params/Orientation.java
|
||||||
@sed -i'' -e "s|var AndroidTextInput = requireNativeComponent('AndroidTextInput', null);|var AndroidTextInput = requireNativeComponent('CustomTextInput', null);|g" node_modules/react-native/Libraries/Components/TextInput/TextInput.js
|
@sed -i'' -e "s|var AndroidTextInput = requireNativeComponent('AndroidTextInput', null);|var AndroidTextInput = requireNativeComponent('CustomTextInput', null);|g" node_modules/react-native/Libraries/Components/TextInput/TextInput.js
|
||||||
|
@sed -i'' -e "s|super.onBackPressed();|this.moveTaskToBack(true);|g" node_modules/react-native-navigation/android/app/src/main/java/com/reactnativenavigation/controllers/NavigationActivity.java
|
||||||
@if [ $(shell grep "const Platform" node_modules/react-native/Libraries/Lists/VirtualizedList.js | grep -civ grep) -eq 0 ]; then \
|
@if [ $(shell grep "const Platform" node_modules/react-native/Libraries/Lists/VirtualizedList.js | grep -civ grep) -eq 0 ]; then \
|
||||||
sed $ -i'' -e "s|const ReactNative = require('ReactNative');|const ReactNative = require('ReactNative');`echo $\\\\\\r;`const Platform = require('Platform');|g" node_modules/react-native/Libraries/Lists/VirtualizedList.js; \
|
sed $ -i'' -e "s|const ReactNative = require('ReactNative');|const ReactNative = require('ReactNative');`echo $\\\\\\r;`const Platform = require('Platform');|g" node_modules/react-native/Libraries/Lists/VirtualizedList.js; \
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -106,8 +106,8 @@ android {
|
|||||||
applicationId "com.mattermost.rnbeta"
|
applicationId "com.mattermost.rnbeta"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 23
|
targetSdkVersion 23
|
||||||
versionCode 84
|
versionCode 86
|
||||||
versionName "1.6.0"
|
versionName "1.6.1"
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters "armeabi-v7a", "x86"
|
abiFilters "armeabi-v7a", "x86"
|
||||||
|
|||||||
@@ -1,10 +1,31 @@
|
|||||||
package com.mattermost.rnbeta;
|
package com.mattermost.rnbeta;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import com.reactnativenavigation.controllers.SplashActivity;
|
import com.reactnativenavigation.controllers.SplashActivity;
|
||||||
|
|
||||||
public class MainActivity extends SplashActivity {
|
public class MainActivity extends SplashActivity {
|
||||||
@Override
|
@Override
|
||||||
public int getSplashLayout() {
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
return R.layout.launch_screen;
|
super.onCreate(savedInstanceState);
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Reference: https://stackoverflow.com/questions/7944338/resume-last-activity-when-launcher-icon-is-clicked
|
||||||
|
* 1. Open app from launcher/appDrawer
|
||||||
|
* 2. Go home
|
||||||
|
* 3. Send notification and open
|
||||||
|
* 4. It creates a new Activity and Destroys the old
|
||||||
|
* 5. Causing an unnecessary app restart
|
||||||
|
* 6. This solution short-circuits the restart
|
||||||
|
*/
|
||||||
|
if (!isTaskRoot()) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSplashLayout() {
|
||||||
|
return R.layout.launch_screen;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,6 +93,13 @@ public class MainApplication extends NavigationApplication implements INotificat
|
|||||||
SoLoader.init(this, /* native exopackage */ false);
|
SoLoader.init(this, /* native exopackage */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean clearHostOnActivityDestroy() {
|
||||||
|
// This solves the issue where the splash screen does not go away
|
||||||
|
// after the app is killed by the OS cause of memory or a long time in the background
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IPushNotification getPushNotification(Context context, Bundle bundle, AppLifecycleFacade defaultFacade, AppLaunchHelper defaultAppLaunchHelper) {
|
public IPushNotification getPushNotification(Context context, Bundle bundle, AppLifecycleFacade defaultFacade, AppLaunchHelper defaultAppLaunchHelper) {
|
||||||
return new CustomPushNotification(
|
return new CustomPushNotification(
|
||||||
|
|||||||
@@ -39,12 +39,11 @@ public class NotificationsLifecycleFacade extends ActivityCallbacks implements A
|
|||||||
|
|
||||||
private final BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
|
||||||
@Override public void onReceive(Context context, Intent intent) {
|
@Override public void onReceive(Context context, Intent intent) {
|
||||||
|
if (context != null) {
|
||||||
if (mVisibleActivity != null) {
|
|
||||||
// Get the current configuration bundle
|
// Get the current configuration bundle
|
||||||
RestrictionsManager myRestrictionsMgr =
|
RestrictionsManager myRestrictionsMgr =
|
||||||
(RestrictionsManager) mVisibleActivity
|
(RestrictionsManager) context
|
||||||
.getSystemService(Context.RESTRICTIONS_SERVICE);
|
.getSystemService(Context.RESTRICTIONS_SERVICE);
|
||||||
managedConfig = myRestrictionsMgr.getApplicationRestrictions();
|
managedConfig = myRestrictionsMgr.getApplicationRestrictions();
|
||||||
|
|
||||||
// Check current configuration settings, change your app's UI and
|
// Check current configuration settings, change your app's UI and
|
||||||
@@ -66,11 +65,11 @@ public class NotificationsLifecycleFacade extends ActivityCallbacks implements A
|
|||||||
@Override
|
@Override
|
||||||
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
||||||
MattermostManagedModule managedModule = MattermostManagedModule.getInstance();
|
MattermostManagedModule managedModule = MattermostManagedModule.getInstance();
|
||||||
if (managedModule != null && managedModule.isBlurAppScreenEnabled()) {
|
if (managedModule != null && managedModule.isBlurAppScreenEnabled() && activity != null) {
|
||||||
activity.getWindow().setFlags(LayoutParams.FLAG_SECURE,
|
activity.getWindow().setFlags(LayoutParams.FLAG_SECURE,
|
||||||
LayoutParams.FLAG_SECURE);
|
LayoutParams.FLAG_SECURE);
|
||||||
}
|
}
|
||||||
if (managedConfig!= null && managedConfig.size() > 0) {
|
if (managedConfig!= null && managedConfig.size() > 0 && activity != null) {
|
||||||
activity.registerReceiver(restrictionsReceiver, restrictionsFilter);
|
activity.registerReceiver(restrictionsReceiver, restrictionsFilter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,9 +78,11 @@ public class NotificationsLifecycleFacade extends ActivityCallbacks implements A
|
|||||||
public void onActivityResumed(Activity activity) {
|
public void onActivityResumed(Activity activity) {
|
||||||
switchToVisible(activity);
|
switchToVisible(activity);
|
||||||
|
|
||||||
if (managedConfig != null && managedConfig.size() > 0) {
|
ReactContext ctx = getRunningReactContext();
|
||||||
|
if (managedConfig != null && managedConfig.size() > 0 && ctx != null) {
|
||||||
|
|
||||||
RestrictionsManager myRestrictionsMgr =
|
RestrictionsManager myRestrictionsMgr =
|
||||||
(RestrictionsManager) activity
|
(RestrictionsManager) ctx
|
||||||
.getSystemService(Context.RESTRICTIONS_SERVICE);
|
.getSystemService(Context.RESTRICTIONS_SERVICE);
|
||||||
|
|
||||||
Bundle newConfig = myRestrictionsMgr.getApplicationRestrictions();
|
Bundle newConfig = myRestrictionsMgr.getApplicationRestrictions();
|
||||||
@@ -174,13 +175,15 @@ public class NotificationsLifecycleFacade extends ActivityCallbacks implements A
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void LoadManagedConfig(Activity activity) {
|
public synchronized void LoadManagedConfig(ReactContext ctx) {
|
||||||
RestrictionsManager myRestrictionsMgr =
|
if (ctx != null) {
|
||||||
(RestrictionsManager) activity
|
RestrictionsManager myRestrictionsMgr =
|
||||||
.getSystemService(Context.RESTRICTIONS_SERVICE);
|
(RestrictionsManager) ctx
|
||||||
|
.getSystemService(Context.RESTRICTIONS_SERVICE);
|
||||||
|
|
||||||
managedConfig = myRestrictionsMgr.getApplicationRestrictions();
|
managedConfig = myRestrictionsMgr.getApplicationRestrictions();
|
||||||
myRestrictionsMgr = null;
|
myRestrictionsMgr = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Bundle getManagedConfig() {
|
public synchronized Bundle getManagedConfig() {
|
||||||
@@ -188,8 +191,10 @@ public class NotificationsLifecycleFacade extends ActivityCallbacks implements A
|
|||||||
return managedConfig;
|
return managedConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mVisibleActivity != null) {
|
ReactContext ctx = getRunningReactContext();
|
||||||
LoadManagedConfig(mVisibleActivity);
|
|
||||||
|
if (ctx != null) {
|
||||||
|
LoadManagedConfig(ctx);
|
||||||
return managedConfig;
|
return managedConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,9 +203,11 @@ public class NotificationsLifecycleFacade extends ActivityCallbacks implements A
|
|||||||
|
|
||||||
public void sendConfigChanged(Bundle config) {
|
public void sendConfigChanged(Bundle config) {
|
||||||
Object result = Arguments.fromBundle(config);
|
Object result = Arguments.fromBundle(config);
|
||||||
getRunningReactContext().
|
ReactContext ctx = getRunningReactContext();
|
||||||
getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).
|
if (ctx != null) {
|
||||||
emit("managedConfigDidChange", result);
|
ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).
|
||||||
|
emit("managedConfigDidChange", result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean equalBundles(Bundle one, Bundle two) {
|
private boolean equalBundles(Bundle one, Bundle two) {
|
||||||
|
|||||||
@@ -460,7 +460,8 @@ export function increasePostVisibility(channelId, focusedPostId) {
|
|||||||
|
|
||||||
// Check if we already have the posts that we want to show
|
// Check if we already have the posts that we want to show
|
||||||
if (!focusedPostId) {
|
if (!focusedPostId) {
|
||||||
const loadedPostCount = state.entities.posts.postsInChannel[channelId].length;
|
const postsInChannel = state.entities.posts.postsInChannel[channelId] || [];
|
||||||
|
const loadedPostCount = postsInChannel.length;
|
||||||
const desiredPostVisibility = currentPostVisibility + ViewTypes.POST_VISIBILITY_CHUNK_SIZE;
|
const desiredPostVisibility = currentPostVisibility + ViewTypes.POST_VISIBILITY_CHUNK_SIZE;
|
||||||
|
|
||||||
if (loadedPostCount >= desiredPostVisibility) {
|
if (loadedPostCount >= desiredPostVisibility) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import {getDataRetentionPolicy} from 'mattermost-redux/actions/general';
|
import {getDataRetentionPolicy} from 'mattermost-redux/actions/general';
|
||||||
import {GeneralTypes} from 'mattermost-redux/action_types';
|
import {GeneralTypes} from 'mattermost-redux/action_types';
|
||||||
import {Client, Client4} from 'mattermost-redux/client';
|
import {Client4} from 'mattermost-redux/client';
|
||||||
|
|
||||||
import {ViewTypes} from 'app/constants';
|
import {ViewTypes} from 'app/constants';
|
||||||
|
|
||||||
@@ -39,9 +39,6 @@ export function handleSuccessfulLogin() {
|
|||||||
}
|
}
|
||||||
}, getState);
|
}, getState);
|
||||||
|
|
||||||
Client.setToken(token);
|
|
||||||
Client.setUrl(url);
|
|
||||||
|
|
||||||
if (config.DataRetentionEnableMessageDeletion && config.DataRetentionEnableMessageDeletion === 'true' &&
|
if (config.DataRetentionEnableMessageDeletion && config.DataRetentionEnableMessageDeletion === 'true' &&
|
||||||
license.IsLicensed === 'true' && license.DataRetention === 'true') {
|
license.IsLicensed === 'true' && license.DataRetention === 'true') {
|
||||||
getDataRetentionPolicy()(dispatch, getState);
|
getDataRetentionPolicy()(dispatch, getState);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import {connect} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
|
|
||||||
import {Client, Client4} from 'mattermost-redux/client';
|
import {Client4} from 'mattermost-redux/client';
|
||||||
import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels';
|
import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels';
|
||||||
import {getCurrentUrl} from 'mattermost-redux/selectors/entities/general';
|
import {getCurrentUrl} from 'mattermost-redux/selectors/entities/general';
|
||||||
|
|
||||||
@@ -15,7 +15,6 @@ import Root from './root';
|
|||||||
|
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state) {
|
||||||
const locale = getCurrentLocale(state);
|
const locale = getCurrentLocale(state);
|
||||||
Client.setLocale(locale);
|
|
||||||
Client4.setAcceptLanguage(locale);
|
Client4.setAcceptLanguage(locale);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -66,9 +66,15 @@ export default class SearchBarAndroid extends PureComponent {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
|
value: props.value,
|
||||||
isFocused: false
|
isFocused: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
if (this.state.value !== nextProps.value) {
|
||||||
|
this.setState({value: nextProps.value});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cancel = () => {
|
cancel = () => {
|
||||||
this.onCancelButtonPress();
|
this.onCancelButtonPress();
|
||||||
@@ -102,7 +108,9 @@ export default class SearchBarAndroid extends PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onChangeText = (value) => {
|
onChangeText = (value) => {
|
||||||
this.props.onChangeText(value);
|
this.setState({value}, () => {
|
||||||
|
this.props.onChangeText(value);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onSelectionChange = (event) => {
|
onSelectionChange = (event) => {
|
||||||
@@ -196,7 +204,7 @@ export default class SearchBarAndroid extends PureComponent {
|
|||||||
<TextInput
|
<TextInput
|
||||||
ref='input'
|
ref='input'
|
||||||
blurOnSubmit={blurOnSubmit}
|
blurOnSubmit={blurOnSubmit}
|
||||||
value={value}
|
value={this.state.value}
|
||||||
autoCapitalize={autoCapitalize}
|
autoCapitalize={autoCapitalize}
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
returnKeyType={returnKeyType || 'search'}
|
returnKeyType={returnKeyType || 'search'}
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ import {General} from 'mattermost-redux/constants';
|
|||||||
import {setAppState, setDeviceToken, setServerVersion} from 'mattermost-redux/actions/general';
|
import {setAppState, setDeviceToken, setServerVersion} from 'mattermost-redux/actions/general';
|
||||||
import {markChannelAsRead} from 'mattermost-redux/actions/channels';
|
import {markChannelAsRead} from 'mattermost-redux/actions/channels';
|
||||||
import {logError} from 'mattermost-redux/actions/errors';
|
import {logError} from 'mattermost-redux/actions/errors';
|
||||||
import {logout} from 'mattermost-redux/actions/users';
|
import {loadMe, logout} from 'mattermost-redux/actions/users';
|
||||||
import {close as closeWebSocket} from 'mattermost-redux/actions/websocket';
|
import {close as closeWebSocket} from 'mattermost-redux/actions/websocket';
|
||||||
import {Client, Client4} from 'mattermost-redux/client';
|
import {Client4} from 'mattermost-redux/client';
|
||||||
import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -49,62 +49,44 @@ import initialState from 'app/initial_state';
|
|||||||
import PushNotifications from 'app/push_notifications';
|
import PushNotifications from 'app/push_notifications';
|
||||||
import {registerScreens} from 'app/screens';
|
import {registerScreens} from 'app/screens';
|
||||||
import configureStore from 'app/store';
|
import configureStore from 'app/store';
|
||||||
import mattermostBucket from 'app/mattermost_bucket';
|
|
||||||
import mattermostManaged from 'app/mattermost_managed';
|
import mattermostManaged from 'app/mattermost_managed';
|
||||||
import {deleteFileCache} from 'app/utils/file';
|
import {deleteFileCache} from 'app/utils/file';
|
||||||
import {init as initAnalytics} from 'app/utils/segment';
|
import {init as initAnalytics} from 'app/utils/segment';
|
||||||
import {
|
import {captureException, initializeSentry, LOGGER_JAVASCRIPT, LOGGER_NATIVE} from 'app/utils/sentry';
|
||||||
captureException,
|
import tracker from 'app/utils/time_tracker';
|
||||||
initializeSentry,
|
|
||||||
LOGGER_JAVASCRIPT,
|
|
||||||
LOGGER_NATIVE
|
|
||||||
} from 'app/utils/sentry';
|
|
||||||
import {stripTrailingSlashes} from 'app/utils/url';
|
import {stripTrailingSlashes} from 'app/utils/url';
|
||||||
|
|
||||||
import Config from 'assets/config';
|
import LocalConfig from 'assets/config';
|
||||||
|
|
||||||
const {StatusBarManager} = NativeModules;
|
const {StatusBarManager} = NativeModules;
|
||||||
const AUTHENTICATION_TIMEOUT = 5 * 60 * 1000;
|
const AUTHENTICATION_TIMEOUT = 5 * 60 * 1000;
|
||||||
|
|
||||||
export default class Mattermost {
|
export default class Mattermost {
|
||||||
constructor() {
|
constructor() {
|
||||||
if (Platform.OS === 'android') {
|
|
||||||
// This is to remove the warnings for the scaleY property used in android.
|
|
||||||
// The property is necessary because some Android devices won't render the posts
|
|
||||||
// properly if we use transform: {scaleY: -1} in the stylesheet.
|
|
||||||
console.ignoredYellowBox = ['`scaleY`']; //eslint-disable-line
|
|
||||||
}
|
|
||||||
this.isConfigured = false;
|
this.isConfigured = false;
|
||||||
this.allowOtherServers = true;
|
this.allowOtherServers = true;
|
||||||
|
this.startAppFromPushNotification = false;
|
||||||
|
this.emmEnabled = false;
|
||||||
|
|
||||||
|
Client4.setUserAgent(DeviceInfo.getUserAgent());
|
||||||
Orientation.unlockAllOrientations();
|
Orientation.unlockAllOrientations();
|
||||||
|
|
||||||
initializeSentry();
|
initializeSentry();
|
||||||
|
|
||||||
this.store = configureStore(initialState);
|
this.store = configureStore(initialState);
|
||||||
|
registerScreens(this.store, Provider);
|
||||||
|
|
||||||
this.unsubscribeFromStore = this.store.subscribe(this.listenForHydration);
|
this.unsubscribeFromStore = this.store.subscribe(this.listenForHydration);
|
||||||
AppState.addEventListener('change', this.handleAppStateChange);
|
AppState.addEventListener('change', this.handleAppStateChange);
|
||||||
EventEmitter.on(General.CONFIG_CHANGED, this.handleConfigChanged);
|
EventEmitter.on(General.CONFIG_CHANGED, this.handleServerConfigChanged);
|
||||||
EventEmitter.on(NavigationTypes.NAVIGATION_RESET, this.handleReset);
|
EventEmitter.on(NavigationTypes.NAVIGATION_RESET, this.handleLogout);
|
||||||
EventEmitter.on(General.DEFAULT_CHANNEL, this.handleResetDisplayName);
|
EventEmitter.on(General.DEFAULT_CHANNEL, this.handleResetChannelDisplayName);
|
||||||
EventEmitter.on(NavigationTypes.RESTART_APP, this.restartApp);
|
EventEmitter.on(NavigationTypes.RESTART_APP, this.restartApp);
|
||||||
Orientation.addOrientationListener(this.orientationDidChange);
|
Orientation.addOrientationListener(this.orientationDidChange);
|
||||||
mattermostManaged.addEventListener('managedConfigDidChange', this.handleManagedConfig);
|
mattermostManaged.addEventListener('managedConfigDidChange', this.handleManagedConfig);
|
||||||
|
|
||||||
this.handleAppStateChange(AppState.currentState);
|
|
||||||
Client4.setUserAgent(DeviceInfo.getUserAgent());
|
|
||||||
|
|
||||||
if (Platform.OS === 'ios') {
|
if (Platform.OS === 'ios') {
|
||||||
StatusBarSizeIOS.addEventListener('willChange', this.handleStatusBarHeightChange);
|
StatusBarSizeIOS.addEventListener('willChange', this.handleStatusBarHeightChange);
|
||||||
StatusBarManager.getHeight(
|
|
||||||
(data) => {
|
|
||||||
this.handleStatusBarHeightChange(data.height);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerScreens(this.store, Provider);
|
|
||||||
|
|
||||||
setJSExceptionHandler(this.errorHandler, false);
|
setJSExceptionHandler(this.errorHandler, false);
|
||||||
setNativeExceptionHandler(this.nativeErrorHandler, false);
|
setNativeExceptionHandler(this.nativeErrorHandler, false);
|
||||||
}
|
}
|
||||||
@@ -115,7 +97,10 @@ export default class Mattermost {
|
|||||||
|
|
||||||
const intl = this.getIntl();
|
const intl = this.getIntl();
|
||||||
closeWebSocket()(this.store.dispatch, this.store.getState);
|
closeWebSocket()(this.store.dispatch, this.store.getState);
|
||||||
logError(e)(this.store.dispatch);
|
|
||||||
|
if (Client4.getUrl()) {
|
||||||
|
logError(e)(this.store.dispatch);
|
||||||
|
}
|
||||||
|
|
||||||
if (isFatal) {
|
if (isFatal) {
|
||||||
Alert.alert(
|
Alert.alert(
|
||||||
@@ -151,7 +136,7 @@ export default class Mattermost {
|
|||||||
};
|
};
|
||||||
|
|
||||||
configureAnalytics = (config) => {
|
configureAnalytics = (config) => {
|
||||||
if (config && config.DiagnosticsEnabled === 'true' && config.DiagnosticId && Config.SegmentApiKey) {
|
if (config && config.DiagnosticsEnabled === 'true' && config.DiagnosticId && LocalConfig.SegmentApiKey) {
|
||||||
initAnalytics(config);
|
initAnalytics(config);
|
||||||
} else {
|
} else {
|
||||||
global.analytics = null;
|
global.analytics = null;
|
||||||
@@ -172,37 +157,39 @@ export default class Mattermost {
|
|||||||
handleAppStateChange = async (appState) => {
|
handleAppStateChange = async (appState) => {
|
||||||
const {dispatch, getState} = this.store;
|
const {dispatch, getState} = this.store;
|
||||||
const isActive = appState === 'active';
|
const isActive = appState === 'active';
|
||||||
|
|
||||||
setAppState(isActive)(dispatch, getState);
|
setAppState(isActive)(dispatch, getState);
|
||||||
|
|
||||||
if (isActive && this.shouldRelaunchonActive) {
|
if (isActive && this.shouldRelaunchWhenActive) {
|
||||||
|
// This handles when the app was started in the background
|
||||||
|
// cause of an iOS push notification reply
|
||||||
this.launchApp();
|
this.launchApp();
|
||||||
this.shouldRelaunchonActive = false;
|
this.shouldRelaunchWhenActive = false;
|
||||||
} else {
|
} else if (!isActive && !this.inBackgroundSince) {
|
||||||
|
// When the app is sent to the background we set the time when that happens
|
||||||
|
// and perform a data clean up to improve on performance
|
||||||
|
this.inBackgroundSince = Date.now();
|
||||||
|
dispatch({type: ViewTypes.DATA_CLEANUP, payload: getState()});
|
||||||
|
} else if (isActive && this.inBackgroundSince && (Date.now() - this.inBackgroundSince) >= AUTHENTICATION_TIMEOUT && this.emmEnabled) {
|
||||||
|
// Once the app becomes active after more than 5 minutes in the background and is controlled by an EMM
|
||||||
try {
|
try {
|
||||||
if (!isActive && !this.inBackgroundSince) {
|
const config = await mattermostManaged.getConfig();
|
||||||
this.inBackgroundSince = Date.now();
|
const authNeeded = config.inAppPinCode && config.inAppPinCode === 'true';
|
||||||
dispatch({type: ViewTypes.DATA_CLEANUP, payload: getState()});
|
if (authNeeded) {
|
||||||
} else if (isActive && this.inBackgroundSince && (Date.now() - this.inBackgroundSince) >= AUTHENTICATION_TIMEOUT) {
|
const authenticated = await this.handleAuthentication(config.vendor);
|
||||||
this.inBackgroundSince = null;
|
if (!authenticated) {
|
||||||
|
mattermostManaged.quitApp();
|
||||||
if (this.mdmEnabled) {
|
|
||||||
const config = await mattermostManaged.getConfig();
|
|
||||||
const authNeeded = config.inAppPinCode && config.inAppPinCode === 'true';
|
|
||||||
if (authNeeded) {
|
|
||||||
const authenticated = await this.handleAuthentication(config.vendor);
|
|
||||||
if (!authenticated) {
|
|
||||||
mattermostManaged.quitApp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (isActive) {
|
|
||||||
this.inBackgroundSince = null;
|
|
||||||
Keyboard.dismiss();
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isActive) {
|
||||||
|
this.inBackgroundSince = null;
|
||||||
|
Keyboard.dismiss();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleAuthentication = async (vendor) => {
|
handleAuthentication = async (vendor) => {
|
||||||
@@ -211,7 +198,6 @@ export default class Mattermost {
|
|||||||
const intl = this.getIntl();
|
const intl = this.getIntl();
|
||||||
if (isSecured) {
|
if (isSecured) {
|
||||||
try {
|
try {
|
||||||
mattermostBucket.setPreference('emm', vendor, Config.AppGroupId);
|
|
||||||
await mattermostManaged.authenticate({
|
await mattermostManaged.authenticate({
|
||||||
reason: intl.formatMessage({
|
reason: intl.formatMessage({
|
||||||
id: 'mobile.managed.secured_by',
|
id: 'mobile.managed.secured_by',
|
||||||
@@ -229,20 +215,20 @@ export default class Mattermost {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
handleConfigChanged = async (serverVersion) => {
|
handleServerConfigChanged = async (serverVersion) => {
|
||||||
const {dispatch, getState} = this.store;
|
const {dispatch, getState} = this.store;
|
||||||
const version = serverVersion.match(/^[0-9]*.[0-9]*.[0-9]*(-[a-zA-Z0-9.-]*)?/g)[0];
|
const version = serverVersion.match(/^[0-9]*.[0-9]*.[0-9]*(-[a-zA-Z0-9.-]*)?/g)[0];
|
||||||
const intl = this.getIntl();
|
const intl = this.getIntl();
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
if (serverVersion) {
|
if (serverVersion) {
|
||||||
if (semver.valid(version) && semver.lt(version, Config.MinServerVersion)) {
|
if (semver.valid(version) && semver.lt(version, LocalConfig.MinServerVersion)) {
|
||||||
Alert.alert(
|
Alert.alert(
|
||||||
intl.formatMessage({id: 'mobile.server_upgrade.title', defaultMessage: 'Server upgrade required'}),
|
intl.formatMessage({id: 'mobile.server_upgrade.title', defaultMessage: 'Server upgrade required'}),
|
||||||
intl.formatMessage({id: 'mobile.server_upgrade.description', defaultMessage: '\nA server upgrade is required to use the Mattermost app. Please ask your System Administrator for details.\n'}),
|
intl.formatMessage({id: 'mobile.server_upgrade.description', defaultMessage: '\nA server upgrade is required to use the Mattermost app. Please ask your System Administrator for details.\n'}),
|
||||||
[{
|
[{
|
||||||
text: intl.formatMessage({id: 'mobile.server_upgrade.button', defaultMessage: 'OK'}),
|
text: intl.formatMessage({id: 'mobile.server_upgrade.button', defaultMessage: 'OK'}),
|
||||||
onPress: this.handleVersionUpgrade
|
onPress: this.handleServerVersionUpgradeNeeded
|
||||||
}],
|
}],
|
||||||
{cancelable: false}
|
{cancelable: false}
|
||||||
);
|
);
|
||||||
@@ -265,15 +251,15 @@ export default class Mattermost {
|
|||||||
let serverUrl = null;
|
let serverUrl = null;
|
||||||
let username = null;
|
let username = null;
|
||||||
|
|
||||||
if (Config.AutoSelectServerUrl) {
|
if (LocalConfig.AutoSelectServerUrl) {
|
||||||
handleServerUrlChanged(Config.DefaultServerUrl)(dispatch, getState);
|
handleServerUrlChanged(LocalConfig.DefaultServerUrl)(dispatch, getState);
|
||||||
this.allowOtherServers = false;
|
this.allowOtherServers = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const config = await mattermostManaged.getConfig();
|
const config = await mattermostManaged.getConfig();
|
||||||
if (config) {
|
if (config && Object.keys(config).length) {
|
||||||
this.mdmEnabled = true;
|
this.emmEnabled = true;
|
||||||
authNeeded = config.inAppPinCode && config.inAppPinCode === 'true';
|
authNeeded = config.inAppPinCode && config.inAppPinCode === 'true';
|
||||||
blurApplicationScreen = config.blurApplicationScreen && config.blurApplicationScreen === 'true';
|
blurApplicationScreen = config.blurApplicationScreen && config.blurApplicationScreen === 'true';
|
||||||
jailbreakProtection = config.jailbreakProtection && config.jailbreakProtection === 'true';
|
jailbreakProtection = config.jailbreakProtection && config.jailbreakProtection === 'true';
|
||||||
@@ -287,74 +273,72 @@ export default class Mattermost {
|
|||||||
this.allowOtherServers = false;
|
this.allowOtherServers = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (jailbreakProtection) {
|
||||||
|
const isTrusted = mattermostManaged.isTrustedDevice();
|
||||||
|
|
||||||
|
if (!isTrusted) {
|
||||||
|
const intl = this.getIntl();
|
||||||
|
Alert.alert(
|
||||||
|
intl.formatMessage({
|
||||||
|
id: 'mobile.managed.blocked_by',
|
||||||
|
defaultMessage: 'Blocked by {vendor}'
|
||||||
|
}, {vendor}),
|
||||||
|
intl.formatMessage({
|
||||||
|
id: 'mobile.managed.jailbreak',
|
||||||
|
defaultMessage: 'Jailbroken devices are not trusted by {vendor}, please exit the app.'
|
||||||
|
}, {vendor}),
|
||||||
|
[{
|
||||||
|
text: intl.formatMessage({id: 'mobile.managed.exit', defaultMessage: 'Exit'}),
|
||||||
|
style: 'destructive',
|
||||||
|
onPress: () => {
|
||||||
|
mattermostManaged.quitApp();
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
{cancelable: false}
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authNeeded && !serverConfig) {
|
||||||
|
if (Platform.OS === 'android') {
|
||||||
|
//Start a fake app as we need at least one activity for android
|
||||||
|
await this.startFakeApp();
|
||||||
|
}
|
||||||
|
const authenticated = await this.handleAuthentication(vendor);
|
||||||
|
if (!authenticated) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blurApplicationScreen) {
|
||||||
|
mattermostManaged.blurAppScreen(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverUrl) {
|
||||||
|
handleServerUrlChanged(serverUrl)(dispatch, getState);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (username) {
|
||||||
|
handleLoginIdChanged(username)(dispatch, getState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.mdmEnabled) {
|
|
||||||
if (jailbreakProtection) {
|
|
||||||
const isTrusted = mattermostManaged.isTrustedDevice();
|
|
||||||
|
|
||||||
if (!isTrusted) {
|
|
||||||
const intl = this.getIntl();
|
|
||||||
Alert.alert(
|
|
||||||
intl.formatMessage({
|
|
||||||
id: 'mobile.managed.blocked_by',
|
|
||||||
defaultMessage: 'Blocked by {vendor}'
|
|
||||||
}, {vendor}),
|
|
||||||
intl.formatMessage({
|
|
||||||
id: 'mobile.managed.jailbreak',
|
|
||||||
defaultMessage: 'Jailbroken devices are not trusted by {vendor}, please exit the app.'
|
|
||||||
}, {vendor}),
|
|
||||||
[{
|
|
||||||
text: intl.formatMessage({id: 'mobile.managed.exit', defaultMessage: 'Exit'}),
|
|
||||||
style: 'destructive',
|
|
||||||
onPress: () => {
|
|
||||||
mattermostManaged.quitApp();
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
{cancelable: false}
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (authNeeded && !serverConfig) {
|
|
||||||
if (Platform.OS === 'android') {
|
|
||||||
//Start a fake app as we need at least one activity for android
|
|
||||||
await this.startFakeApp();
|
|
||||||
}
|
|
||||||
const authenticated = await this.handleAuthentication(vendor);
|
|
||||||
if (!authenticated) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blurApplicationScreen) {
|
|
||||||
mattermostManaged.blurAppScreen(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serverUrl) {
|
|
||||||
handleServerUrlChanged(serverUrl)(dispatch, getState);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (username) {
|
|
||||||
handleLoginIdChanged(username)(dispatch, getState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
handleReset = () => {
|
handleLogout = () => {
|
||||||
this.appStarted = false;
|
this.appStarted = false;
|
||||||
deleteFileCache();
|
deleteFileCache();
|
||||||
this.resetBadgeAndVersion();
|
this.resetBadgeAndVersion();
|
||||||
this.startApp('fade');
|
this.startApp('fade');
|
||||||
};
|
};
|
||||||
|
|
||||||
handleResetDisplayName = (displayName) => {
|
handleResetChannelDisplayName = (displayName) => {
|
||||||
this.store.dispatch(setChannelDisplayName(displayName));
|
this.store.dispatch(setChannelDisplayName(displayName));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -362,48 +346,65 @@ export default class Mattermost {
|
|||||||
this.store.dispatch(setStatusBarHeight(nextStatusBarHeight));
|
this.store.dispatch(setStatusBarHeight(nextStatusBarHeight));
|
||||||
};
|
};
|
||||||
|
|
||||||
handleVersionUpgrade = async () => {
|
handleServerVersionUpgradeNeeded = async () => {
|
||||||
const {dispatch, getState} = this.store;
|
const {dispatch, getState} = this.store;
|
||||||
|
|
||||||
Client4.serverVersion = '';
|
this.resetBadgeAndVersion();
|
||||||
PushNotifications.setApplicationIconBadgeNumber(0);
|
|
||||||
|
|
||||||
if (getState().entities.general.credentials.token) {
|
if (getState().entities.general.credentials.token) {
|
||||||
InteractionManager.runAfterInteractions(() => {
|
InteractionManager.runAfterInteractions(() => {
|
||||||
logout()(dispatch, getState);
|
logout()(dispatch, getState);
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
this.resetBadgeAndVersion();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// We need to wait for hydration to occur before load the router.
|
// We need to wait for hydration to occur before load the router.
|
||||||
listenForHydration = () => {
|
listenForHydration = () => {
|
||||||
const state = this.store.getState();
|
const {dispatch, getState} = this.store;
|
||||||
|
const state = getState();
|
||||||
if (!this.isConfigured) {
|
if (!this.isConfigured) {
|
||||||
this.configurePushNotifications();
|
this.configurePushNotifications();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.views.root.hydrationComplete) {
|
if (state.views.root.hydrationComplete) {
|
||||||
|
const orientation = Orientation.getInitialOrientation();
|
||||||
|
const {credentials, config} = state.entities.general;
|
||||||
|
const {currentUserId} = state.entities.users;
|
||||||
|
const isNotActive = AppState.currentState !== 'active';
|
||||||
|
const notification = PushNotifications.getNotification();
|
||||||
|
|
||||||
this.unsubscribeFromStore();
|
this.unsubscribeFromStore();
|
||||||
|
|
||||||
const orientation = Orientation.getInitialOrientation();
|
if (this.deviceToken) {
|
||||||
|
// If the deviceToken is set we need to dispatch it to the redux store
|
||||||
|
setDeviceToken(this.deviceToken)(dispatch, getState);
|
||||||
|
}
|
||||||
|
|
||||||
if (orientation) {
|
if (orientation) {
|
||||||
this.orientationDidChange(orientation);
|
this.orientationDidChange(orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {config} = state.entities.general;
|
|
||||||
if (config) {
|
if (config) {
|
||||||
this.configureAnalytics(config);
|
this.configureAnalytics(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {currentUserId} = state.entities.users;
|
if (credentials.token && credentials.url) {
|
||||||
|
Client4.setToken(credentials.token);
|
||||||
|
Client4.setUrl(stripTrailingSlashes(credentials.url));
|
||||||
|
}
|
||||||
|
|
||||||
if (currentUserId) {
|
if (currentUserId) {
|
||||||
Client4.setUserId(currentUserId);
|
Client4.setUserId(currentUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const isNotActive = AppState.currentState !== 'active';
|
if (Platform.OS === 'ios') {
|
||||||
const notification = PushNotifications.getNotification();
|
StatusBarManager.getHeight(
|
||||||
|
(data) => {
|
||||||
|
this.handleStatusBarHeightChange(data.height);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (notification || this.replyNotificationData) {
|
if (notification || this.replyNotificationData) {
|
||||||
// If we have a notification means that the app was started cause of a reply
|
// If we have a notification means that the app was started cause of a reply
|
||||||
// and the app was not sitting in the background nor opened
|
// and the app was not sitting in the background nor opened
|
||||||
@@ -416,6 +417,10 @@ export default class Mattermost {
|
|||||||
if (Platform.OS === 'android') {
|
if (Platform.OS === 'android') {
|
||||||
// In case of Android we need to handle the bridge being initialized by HeadlessJS
|
// In case of Android we need to handle the bridge being initialized by HeadlessJS
|
||||||
Promise.resolve(Navigation.isAppLaunched()).then((appLaunched) => {
|
Promise.resolve(Navigation.isAppLaunched()).then((appLaunched) => {
|
||||||
|
if (this.startAppFromPushNotification) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (appLaunched) {
|
if (appLaunched) {
|
||||||
this.launchApp(); // App is launched -> show UI
|
this.launchApp(); // App is launched -> show UI
|
||||||
} else {
|
} else {
|
||||||
@@ -424,7 +429,7 @@ export default class Mattermost {
|
|||||||
});
|
});
|
||||||
} else if (isNotActive) {
|
} else if (isNotActive) {
|
||||||
// for IOS replying from push notification starts the app in the background
|
// for IOS replying from push notification starts the app in the background
|
||||||
this.shouldRelaunchonActive = true;
|
this.shouldRelaunchWhenActive = true;
|
||||||
this.startFakeApp();
|
this.startFakeApp();
|
||||||
} else {
|
} else {
|
||||||
this.launchApp();
|
this.launchApp();
|
||||||
@@ -445,19 +450,23 @@ export default class Mattermost {
|
|||||||
prefix = General.PUSH_NOTIFY_ANDROID_REACT_NATIVE;
|
prefix = General.PUSH_NOTIFY_ANDROID_REACT_NATIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
setDeviceToken(`${prefix}:${data.token}`)(dispatch, getState);
|
const state = getState();
|
||||||
|
const token = `${prefix}:${data.token}`;
|
||||||
|
if (state.views.root.hydrationComplete) {
|
||||||
|
setDeviceToken(token)(dispatch, getState);
|
||||||
|
} else {
|
||||||
|
this.deviceToken = token;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onPushNotification = (deviceNotification) => {
|
onPushNotification = (deviceNotification) => {
|
||||||
const {dispatch, getState} = this.store;
|
const {dispatch, getState} = this.store;
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const {token, url} = state.entities.general.credentials;
|
const {token, url} = state.entities.general.credentials;
|
||||||
let startAppFromPushNotification = false;
|
|
||||||
|
|
||||||
// mark the app as started as soon as possible
|
// mark the app as started as soon as possible
|
||||||
if (token && url && !this.appStarted) {
|
if (!this.appStarted && Platform.OS !== 'ios') {
|
||||||
this.appStarted = true;
|
this.startAppFromPushNotification = true;
|
||||||
startAppFromPushNotification = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const {data, foreground, message, userInfo, userInteraction} = deviceNotification;
|
const {data, foreground, message, userInfo, userInteraction} = deviceNotification;
|
||||||
@@ -476,18 +485,16 @@ export default class Mattermost {
|
|||||||
EventEmitter.emit(ViewTypes.NOTIFICATION_IN_APP, notification);
|
EventEmitter.emit(ViewTypes.NOTIFICATION_IN_APP, notification);
|
||||||
} else if (userInteraction && !notification.localNotification) {
|
} else if (userInteraction && !notification.localNotification) {
|
||||||
EventEmitter.emit('close_channel_drawer');
|
EventEmitter.emit('close_channel_drawer');
|
||||||
if (startAppFromPushNotification) {
|
if (this.startAppFromPushNotification) {
|
||||||
Client.setToken(token);
|
|
||||||
Client4.setToken(token);
|
Client4.setToken(token);
|
||||||
Client4.setUrl(stripTrailingSlashes(url));
|
Client4.setUrl(stripTrailingSlashes(url));
|
||||||
Client.setUrl(stripTrailingSlashes(url));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InteractionManager.runAfterInteractions(async () => {
|
InteractionManager.runAfterInteractions(async () => {
|
||||||
await loadFromPushNotification(notification)(dispatch, getState);
|
await loadFromPushNotification(notification)(dispatch, getState);
|
||||||
|
|
||||||
if (startAppFromPushNotification) {
|
if (this.startAppFromPushNotification) {
|
||||||
this.startAppFromPushNotification();
|
this.launchApp();
|
||||||
} else {
|
} else {
|
||||||
EventEmitter.emit(ViewTypes.NOTIFICATION_TAPPED);
|
EventEmitter.emit(ViewTypes.NOTIFICATION_TAPPED);
|
||||||
}
|
}
|
||||||
@@ -516,7 +523,7 @@ export default class Mattermost {
|
|||||||
Client4.setUrl(state.entities.general.credentials.url);
|
Client4.setUrl(state.entities.general.credentials.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Client.getToken()) {
|
if (!Client4.getToken()) {
|
||||||
// Make sure the Client has the server token set
|
// Make sure the Client has the server token set
|
||||||
Client4.setToken(state.entities.general.credentials.token);
|
Client4.setToken(state.entities.general.credentials.token);
|
||||||
}
|
}
|
||||||
@@ -554,9 +561,7 @@ export default class Mattermost {
|
|||||||
resetBadgeAndVersion = () => {
|
resetBadgeAndVersion = () => {
|
||||||
const {dispatch, getState} = this.store;
|
const {dispatch, getState} = this.store;
|
||||||
Client4.serverVersion = '';
|
Client4.serverVersion = '';
|
||||||
Client.serverVersion = '';
|
Client4.setUserId('');
|
||||||
Client.token = null;
|
|
||||||
Client4.userId = '';
|
|
||||||
PushNotifications.setApplicationIconBadgeNumber(0);
|
PushNotifications.setApplicationIconBadgeNumber(0);
|
||||||
PushNotifications.cancelAllLocalNotifications();
|
PushNotifications.cancelAllLocalNotifications();
|
||||||
setServerVersion('')(dispatch, getState);
|
setServerVersion('')(dispatch, getState);
|
||||||
@@ -567,6 +572,7 @@ export default class Mattermost {
|
|||||||
|
|
||||||
const {dispatch, getState} = this.store;
|
const {dispatch, getState} = this.store;
|
||||||
await loadConfigAndLicense()(dispatch, getState);
|
await loadConfigAndLicense()(dispatch, getState);
|
||||||
|
await loadMe()(dispatch, getState);
|
||||||
this.appStarted = false;
|
this.appStarted = false;
|
||||||
this.startApp('fade');
|
this.startApp('fade');
|
||||||
};
|
};
|
||||||
@@ -588,18 +594,29 @@ export default class Mattermost {
|
|||||||
statusBarHidden: false,
|
statusBarHidden: false,
|
||||||
statusBarHideWithNavBar: false
|
statusBarHideWithNavBar: false
|
||||||
}
|
}
|
||||||
},
|
|
||||||
passProps: {
|
|
||||||
justInit: true
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
startApp = (animationType = 'none') => {
|
startApp = (animationType = 'none') => {
|
||||||
if (!this.appStarted) {
|
if (!this.appStarted) {
|
||||||
|
const {dispatch, getState} = this.store;
|
||||||
|
const {entities} = getState();
|
||||||
|
let screen = 'SelectServer';
|
||||||
|
|
||||||
|
if (entities) {
|
||||||
|
const {credentials} = entities.general;
|
||||||
|
|
||||||
|
if (credentials.token && credentials.url) {
|
||||||
|
screen = 'Channel';
|
||||||
|
tracker.initialLoad = Date.now();
|
||||||
|
loadMe()(dispatch, getState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Navigation.startSingleScreenApp({
|
Navigation.startSingleScreenApp({
|
||||||
screen: {
|
screen: {
|
||||||
screen: 'Root',
|
screen,
|
||||||
navigatorStyle: {
|
navigatorStyle: {
|
||||||
navBarHidden: true,
|
navBarHidden: true,
|
||||||
statusBarHidden: false,
|
statusBarHidden: false,
|
||||||
@@ -617,28 +634,7 @@ export default class Mattermost {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.appStarted = true;
|
this.appStarted = true;
|
||||||
|
this.startAppFromPushNotification = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
startAppFromPushNotification = () => {
|
|
||||||
Navigation.startSingleScreenApp({
|
|
||||||
screen: {
|
|
||||||
screen: 'Channel',
|
|
||||||
navigatorStyle: {
|
|
||||||
navBarHidden: true,
|
|
||||||
statusBarHidden: false,
|
|
||||||
statusBarHideWithNavBar: false,
|
|
||||||
screenBackgroundColor: 'transparent'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
passProps: {
|
|
||||||
allowOtherServers: this.allowOtherServers
|
|
||||||
},
|
|
||||||
appStyle: {
|
|
||||||
orientation: 'auto'
|
|
||||||
},
|
|
||||||
animationType: 'none'
|
|
||||||
});
|
|
||||||
this.appStarted = false;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See License.txt for license information.
|
|
||||||
|
|
||||||
import {NativeModules, Platform} from 'react-native';
|
|
||||||
|
|
||||||
// TODO: Remove platform specific once android is implemented
|
|
||||||
const MattermostBucket = Platform.OS === 'ios' ? NativeModules.MattermostBucket : null;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
setPreference: (key, value, groupName) => {
|
|
||||||
if (MattermostBucket) {
|
|
||||||
MattermostBucket.setPreference(key, value, groupName);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getPreference: async (key, groupName) => {
|
|
||||||
if (MattermostBucket) {
|
|
||||||
const value = await MattermostBucket.getPreference(key, groupName);
|
|
||||||
if (value) {
|
|
||||||
try {
|
|
||||||
return JSON.parse(value);
|
|
||||||
} catch (e) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
removePreference: (key, groupName) => {
|
|
||||||
if (MattermostBucket) {
|
|
||||||
MattermostBucket.removePreference(key, groupName);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
writeToFile: (fileName, content, groupName) => {
|
|
||||||
if (MattermostBucket) {
|
|
||||||
MattermostBucket.writeToFile(fileName, content, groupName);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
readFromFile: async (fileName, groupName) => {
|
|
||||||
if (MattermostBucket) {
|
|
||||||
const value = await MattermostBucket.readFromFile(fileName, groupName);
|
|
||||||
if (value) {
|
|
||||||
try {
|
|
||||||
return JSON.parse(value);
|
|
||||||
} catch (e) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
removeFile: (fileName, groupName) => {
|
|
||||||
if (MattermostBucket) {
|
|
||||||
MattermostBucket.removeFile(fileName, groupName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -60,6 +60,8 @@ class Channel extends PureComponent {
|
|||||||
|
|
||||||
if (this.props.currentTeamId) {
|
if (this.props.currentTeamId) {
|
||||||
this.loadChannels(this.props.currentTeamId);
|
this.loadChannels(this.props.currentTeamId);
|
||||||
|
} else {
|
||||||
|
this.props.actions.selectFirstAvailableTeam();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ class ChannelAddMembers extends PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
searchProfiles = (text) => {
|
searchProfiles = (text) => {
|
||||||
const term = text.toLowerCase();
|
const term = text;
|
||||||
const {actions, currentChannel, currentTeam} = this.props;
|
const {actions, currentChannel, currentTeam} = this.props;
|
||||||
|
|
||||||
if (term) {
|
if (term) {
|
||||||
@@ -213,7 +213,7 @@ class ChannelAddMembers extends PureComponent {
|
|||||||
clearTimeout(this.searchTimeoutId);
|
clearTimeout(this.searchTimeoutId);
|
||||||
|
|
||||||
this.searchTimeoutId = setTimeout(() => {
|
this.searchTimeoutId = setTimeout(() => {
|
||||||
actions.searchProfiles(term, {not_in_channel_id: currentChannel.id, team_id: currentTeam.id});
|
actions.searchProfiles(term.toLowerCase(), {not_in_channel_id: currentChannel.id, team_id: currentTeam.id});
|
||||||
}, General.SEARCH_TIMEOUT_MILLISECONDS);
|
}, General.SEARCH_TIMEOUT_MILLISECONDS);
|
||||||
} else {
|
} else {
|
||||||
this.cancelSearch();
|
this.cancelSearch();
|
||||||
|
|||||||
@@ -253,14 +253,14 @@ class ChannelMembers extends PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
searchProfiles = (text) => {
|
searchProfiles = (text) => {
|
||||||
const term = text.toLowerCase();
|
const term = text;
|
||||||
|
|
||||||
if (term) {
|
if (term) {
|
||||||
this.setState({searching: true, term});
|
this.setState({searching: true, term});
|
||||||
clearTimeout(this.searchTimeoutId);
|
clearTimeout(this.searchTimeoutId);
|
||||||
|
|
||||||
this.searchTimeoutId = setTimeout(() => {
|
this.searchTimeoutId = setTimeout(() => {
|
||||||
this.props.actions.searchProfiles(term, {in_channel_id: this.props.currentChannel.id});
|
this.props.actions.searchProfiles(term.toLowerCase(), {in_channel_id: this.props.currentChannel.id});
|
||||||
}, General.SEARCH_TIMEOUT_MILLISECONDS);
|
}, General.SEARCH_TIMEOUT_MILLISECONDS);
|
||||||
} else {
|
} else {
|
||||||
this.cancelSearch();
|
this.cancelSearch();
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import EditChannel from 'app/screens/edit_channel';
|
|||||||
import EditPost from 'app/screens/edit_post';
|
import EditPost from 'app/screens/edit_post';
|
||||||
import EditProfile from 'app/screens/edit_profile';
|
import EditProfile from 'app/screens/edit_profile';
|
||||||
import ImagePreview from 'app/screens/image_preview';
|
import ImagePreview from 'app/screens/image_preview';
|
||||||
import LoadTeam from 'app/screens/load_team';
|
|
||||||
import Login from 'app/screens/login';
|
import Login from 'app/screens/login';
|
||||||
import LoginOptions from 'app/screens/login_options';
|
import LoginOptions from 'app/screens/login_options';
|
||||||
import Mfa from 'app/screens/mfa';
|
import Mfa from 'app/screens/mfa';
|
||||||
@@ -78,7 +77,6 @@ export function registerScreens(store, Provider) {
|
|||||||
Navigation.registerComponent('EditPost', () => wrapWithContextProvider(EditPost), store, Provider);
|
Navigation.registerComponent('EditPost', () => wrapWithContextProvider(EditPost), store, Provider);
|
||||||
Navigation.registerComponent('EditProfile', () => wrapWithContextProvider(EditProfile), store, Provider);
|
Navigation.registerComponent('EditProfile', () => wrapWithContextProvider(EditProfile), store, Provider);
|
||||||
Navigation.registerComponent('ImagePreview', () => wrapWithContextProvider(ImagePreview), store, Provider);
|
Navigation.registerComponent('ImagePreview', () => wrapWithContextProvider(ImagePreview), store, Provider);
|
||||||
Navigation.registerComponent('LoadTeam', () => wrapWithContextProvider(LoadTeam, false), store, Provider);
|
|
||||||
Navigation.registerComponent('Login', () => wrapWithContextProvider(Login), store, Provider);
|
Navigation.registerComponent('Login', () => wrapWithContextProvider(Login), store, Provider);
|
||||||
Navigation.registerComponent('LoginOptions', () => wrapWithContextProvider(LoginOptions), store, Provider);
|
Navigation.registerComponent('LoginOptions', () => wrapWithContextProvider(LoginOptions), store, Provider);
|
||||||
Navigation.registerComponent('MFA', () => wrapWithContextProvider(Mfa), store, Provider);
|
Navigation.registerComponent('MFA', () => wrapWithContextProvider(Mfa), store, Provider);
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See License.txt for license information.
|
|
||||||
|
|
||||||
import {bindActionCreators} from 'redux';
|
|
||||||
import {connect} from 'react-redux';
|
|
||||||
|
|
||||||
import {getTeams} from 'mattermost-redux/actions/teams';
|
|
||||||
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
|
|
||||||
|
|
||||||
import {handleTeamChange} from 'app/actions/views/select_team';
|
|
||||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
|
||||||
|
|
||||||
import LoadTeam from './load_team';
|
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
|
||||||
return {
|
|
||||||
config: state.entities.general.config,
|
|
||||||
theme: getTheme(state),
|
|
||||||
teams: state.entities.teams.teams,
|
|
||||||
currentTeam: getCurrentTeam(state),
|
|
||||||
myMembers: state.entities.teams.myMembers,
|
|
||||||
notification: state.views.notification
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
|
||||||
return {
|
|
||||||
actions: bindActionCreators({
|
|
||||||
getTeams,
|
|
||||||
handleTeamChange
|
|
||||||
}, dispatch)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(LoadTeam);
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See License.txt for license information.
|
|
||||||
|
|
||||||
import {PureComponent} from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
|
||||||
|
|
||||||
import {NavigationTypes} from 'app/constants';
|
|
||||||
|
|
||||||
export default class LoadTeam extends PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
actions: PropTypes.shape({
|
|
||||||
getTeams: PropTypes.func.isRequired,
|
|
||||||
handleTeamChange: PropTypes.func.isRequired
|
|
||||||
}).isRequired,
|
|
||||||
currentTeam: PropTypes.object,
|
|
||||||
myMembers: PropTypes.object.isRequired,
|
|
||||||
navigator: PropTypes.object,
|
|
||||||
teams: PropTypes.object.isRequired,
|
|
||||||
theme: PropTypes.object.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const {currentTeam, myMembers, teams} = this.props;
|
|
||||||
if (currentTeam && myMembers[currentTeam.id]) {
|
|
||||||
return this.onSelectTeam(currentTeam);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.selectFirstTeam(teams, myMembers);
|
|
||||||
}
|
|
||||||
|
|
||||||
selectFirstTeam(allTeams, myMembers) {
|
|
||||||
const teams = Object.keys(myMembers).map((key) => allTeams[key]);
|
|
||||||
const firstTeam = Object.values(teams).sort((a, b) => a.display_name.localeCompare(b.display_name))[0];
|
|
||||||
|
|
||||||
if (firstTeam) {
|
|
||||||
this.onSelectTeam(firstTeam);
|
|
||||||
} else {
|
|
||||||
const {getTeams} = this.props.actions;
|
|
||||||
getTeams().then(() => {
|
|
||||||
EventEmitter.emit(NavigationTypes.NAVIGATION_NO_TEAMS);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onSelectTeam(team) {
|
|
||||||
const {handleTeamChange} = this.props.actions;
|
|
||||||
handleTeamChange(team.id).then(this.goToChannelView);
|
|
||||||
}
|
|
||||||
|
|
||||||
goToChannelView = () => {
|
|
||||||
const {navigator, theme} = this.props;
|
|
||||||
|
|
||||||
navigator.resetTo({
|
|
||||||
screen: 'Channel',
|
|
||||||
animated: true,
|
|
||||||
animationType: 'fade',
|
|
||||||
navigatorStyle: {
|
|
||||||
navBarHidden: true,
|
|
||||||
statusBarHidden: false,
|
|
||||||
statusBarHideWithNavBar: false,
|
|
||||||
screenBackgroundColor: theme.centerChannelBg
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -77,7 +77,7 @@ class Login extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
goToLoadTeam = (expiresAt) => {
|
goToLoadTeam = (expiresAt) => {
|
||||||
const {intl, navigator, theme} = this.props;
|
const {intl, navigator} = this.props;
|
||||||
tracker.initialLoad = Date.now();
|
tracker.initialLoad = Date.now();
|
||||||
|
|
||||||
if (expiresAt) {
|
if (expiresAt) {
|
||||||
@@ -94,17 +94,17 @@ class Login extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
navigator.resetTo({
|
navigator.resetTo({
|
||||||
screen: 'LoadTeam',
|
screen: 'Channel',
|
||||||
title: '',
|
title: '',
|
||||||
animated: false,
|
animated: false,
|
||||||
backButtonTitle: '',
|
backButtonTitle: '',
|
||||||
navigatorStyle: {
|
navigatorStyle: {
|
||||||
|
animated: true,
|
||||||
|
animationType: 'fade',
|
||||||
|
navBarHidden: true,
|
||||||
statusBarHidden: false,
|
statusBarHidden: false,
|
||||||
statusBarHideWithNavBar: false,
|
statusBarHideWithNavBar: false,
|
||||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
screenBackgroundColor: 'transparent'
|
||||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
|
||||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
|
||||||
screenBackgroundColor: theme.centerChannelBg
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -153,7 +153,11 @@ class MoreChannels extends PureComponent {
|
|||||||
|
|
||||||
if (term) {
|
if (term) {
|
||||||
const channels = this.filterChannels(this.state.channels, term);
|
const channels = this.filterChannels(this.state.channels, term);
|
||||||
this.setState({channels, term, searching: true});
|
this.setState({
|
||||||
|
channels,
|
||||||
|
term: text,
|
||||||
|
searching: true
|
||||||
|
});
|
||||||
clearTimeout(this.searchTimeoutId);
|
clearTimeout(this.searchTimeoutId);
|
||||||
|
|
||||||
this.searchTimeoutId = setTimeout(() => {
|
this.searchTimeoutId = setTimeout(() => {
|
||||||
|
|||||||
@@ -162,14 +162,14 @@ class MoreDirectMessages extends PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onSearch = (text) => {
|
onSearch = (text) => {
|
||||||
const term = text.toLowerCase();
|
const term = text;
|
||||||
|
|
||||||
if (term) {
|
if (term) {
|
||||||
this.setState({searching: true, term});
|
this.setState({searching: true, term});
|
||||||
clearTimeout(this.searchTimeoutId);
|
clearTimeout(this.searchTimeoutId);
|
||||||
|
|
||||||
this.searchTimeoutId = setTimeout(() => {
|
this.searchTimeoutId = setTimeout(() => {
|
||||||
this.searchProfiles(term);
|
this.searchProfiles(term.toLowerCase());
|
||||||
}, General.SEARCH_TIMEOUT_MILLISECONDS);
|
}, General.SEARCH_TIMEOUT_MILLISECONDS);
|
||||||
} else {
|
} else {
|
||||||
this.cancelSearch();
|
this.cancelSearch();
|
||||||
|
|||||||
@@ -1,29 +1,12 @@
|
|||||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import {bindActionCreators} from 'redux';
|
import React from 'react';
|
||||||
import {connect} from 'react-redux';
|
|
||||||
|
|
||||||
import {loadMe} from 'mattermost-redux/actions/users';
|
import Loading from 'app/components/loading';
|
||||||
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
|
|
||||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
|
||||||
|
|
||||||
import Root from './root';
|
function Root() {
|
||||||
|
return <Loading/>;
|
||||||
function mapStateToProps(state) {
|
|
||||||
return {
|
|
||||||
currentUser: getCurrentUser(state),
|
|
||||||
credentials: state.entities.general.credentials,
|
|
||||||
theme: getTheme(state)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
export default Root;
|
||||||
return {
|
|
||||||
actions: bindActionCreators({
|
|
||||||
loadMe
|
|
||||||
}, dispatch)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(Root);
|
|
||||||
|
|||||||
@@ -1,101 +0,0 @@
|
|||||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See License.txt for license information.
|
|
||||||
|
|
||||||
import React, {Component} from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import {Client, Client4} from 'mattermost-redux/client';
|
|
||||||
|
|
||||||
import Loading from 'app/components/loading';
|
|
||||||
import {stripTrailingSlashes} from 'app/utils/url';
|
|
||||||
import tracker from 'app/utils/time_tracker';
|
|
||||||
|
|
||||||
export default class Root extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
actions: PropTypes.shape({
|
|
||||||
loadMe: PropTypes.func.isRequired
|
|
||||||
}).isRequired,
|
|
||||||
allowOtherServers: PropTypes.bool,
|
|
||||||
currentUser: PropTypes.object,
|
|
||||||
credentials: PropTypes.object,
|
|
||||||
justInit: PropTypes.bool,
|
|
||||||
navigator: PropTypes.object,
|
|
||||||
theme: PropTypes.object
|
|
||||||
};
|
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
|
||||||
if (nextProps.credentials !== this.props.credentials) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
if (!this.props.justInit) {
|
|
||||||
this.loadStoreAndScene();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
goToLoadTeam = () => {
|
|
||||||
const {navigator, theme} = this.props;
|
|
||||||
tracker.initialLoad = Date.now();
|
|
||||||
navigator.resetTo({
|
|
||||||
screen: 'LoadTeam',
|
|
||||||
title: '',
|
|
||||||
animated: true,
|
|
||||||
animationType: 'fade',
|
|
||||||
backButtonTitle: '',
|
|
||||||
navigatorStyle: {
|
|
||||||
statusBarHidden: false,
|
|
||||||
statusBarHideWithNavBar: false,
|
|
||||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
|
||||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
|
||||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
|
||||||
screenBackgroundColor: theme.centerChannelBg
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
goToSelectServer = () => {
|
|
||||||
const {allowOtherServers, navigator} = this.props;
|
|
||||||
|
|
||||||
navigator.resetTo({
|
|
||||||
screen: 'SelectServer',
|
|
||||||
animated: true,
|
|
||||||
animationType: 'fade',
|
|
||||||
navigatorStyle: {
|
|
||||||
navBarHidden: true,
|
|
||||||
navBarBackgroundColor: 'black',
|
|
||||||
statusBarHidden: false,
|
|
||||||
statusBarHideWithNavBar: false
|
|
||||||
},
|
|
||||||
passProps: {
|
|
||||||
allowOtherServers
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
loadStoreAndScene = () => {
|
|
||||||
const {actions, currentUser, credentials} = this.props;
|
|
||||||
const {loadMe} = actions;
|
|
||||||
if (credentials.token && credentials.url) {
|
|
||||||
Client.setToken(credentials.token);
|
|
||||||
Client4.setToken(credentials.token);
|
|
||||||
Client4.setUrl(stripTrailingSlashes(credentials.url));
|
|
||||||
Client.setUrl(stripTrailingSlashes(credentials.url));
|
|
||||||
|
|
||||||
if (currentUser) {
|
|
||||||
loadMe();
|
|
||||||
this.goToLoadTeam();
|
|
||||||
} else {
|
|
||||||
loadMe().then(this.goToLoadTeam).catch(this.goToLoadTeam);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.goToSelectServer();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return <Loading/>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
import Button from 'react-native-button';
|
import Button from 'react-native-button';
|
||||||
import urlParse from 'url-parse';
|
import urlParse from 'url-parse';
|
||||||
|
|
||||||
import {Client, Client4} from 'mattermost-redux/client';
|
import {Client4} from 'mattermost-redux/client';
|
||||||
|
|
||||||
import Config from 'assets/config';
|
import Config from 'assets/config';
|
||||||
import ErrorText from 'app/components/error_text';
|
import ErrorText from 'app/components/error_text';
|
||||||
@@ -224,7 +224,6 @@ class SelectServer extends PureComponent {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Client4.setUrl(url);
|
Client4.setUrl(url);
|
||||||
Client.setUrl(url);
|
|
||||||
handleServerUrlChanged(url);
|
handleServerUrlChanged(url);
|
||||||
|
|
||||||
let cancel = false;
|
let cancel = false;
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class SSO extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
goToLoadTeam = (expiresAt) => {
|
goToLoadTeam = (expiresAt) => {
|
||||||
const {intl, navigator, theme} = this.props;
|
const {intl, navigator} = this.props;
|
||||||
tracker.initialLoad = Date.now();
|
tracker.initialLoad = Date.now();
|
||||||
|
|
||||||
if (expiresAt) {
|
if (expiresAt) {
|
||||||
@@ -99,17 +99,17 @@ class SSO extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
navigator.resetTo({
|
navigator.resetTo({
|
||||||
screen: 'LoadTeam',
|
screen: 'Channel',
|
||||||
title: '',
|
title: '',
|
||||||
animated: false,
|
animated: false,
|
||||||
backButtonTitle: '',
|
backButtonTitle: '',
|
||||||
navigatorStyle: {
|
navigatorStyle: {
|
||||||
|
animated: true,
|
||||||
|
animationType: 'fade',
|
||||||
|
navBarHidden: true,
|
||||||
statusBarHidden: false,
|
statusBarHidden: false,
|
||||||
statusBarHideWithNavBar: false,
|
statusBarHideWithNavBar: false,
|
||||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
screenBackgroundColor: 'transparent'
|
||||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
|
||||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
|
||||||
screenBackgroundColor: theme.centerChannelBg
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import {batchActions} from 'redux-batched-actions';
|
import {batchActions} from 'redux-batched-actions';
|
||||||
import {AsyncStorage, Platform} from 'react-native';
|
import {AsyncStorage} from 'react-native';
|
||||||
import {createBlacklistFilter} from 'redux-persist-transform-filter';
|
import {createBlacklistFilter} from 'redux-persist-transform-filter';
|
||||||
import {createTransform, persistStore} from 'redux-persist';
|
import {createTransform, persistStore} from 'redux-persist';
|
||||||
|
|
||||||
@@ -13,15 +13,11 @@ import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
|||||||
|
|
||||||
import {NavigationTypes, ViewTypes} from 'app/constants';
|
import {NavigationTypes, ViewTypes} from 'app/constants';
|
||||||
import appReducer from 'app/reducers';
|
import appReducer from 'app/reducers';
|
||||||
import {throttle} from 'app/utils/general';
|
|
||||||
import networkConnectionListener from 'app/utils/network';
|
import networkConnectionListener from 'app/utils/network';
|
||||||
import {createSentryMiddleware} from 'app/utils/sentry/middleware';
|
import {createSentryMiddleware} from 'app/utils/sentry/middleware';
|
||||||
import {promiseTimeout} from 'app/utils/promise_timeout';
|
import {promiseTimeout} from 'app/utils/promise_timeout';
|
||||||
|
|
||||||
import mattermostBucket from 'app/mattermost_bucket';
|
import {messageRetention} from './middleware';
|
||||||
import Config from 'assets/config';
|
|
||||||
|
|
||||||
import {messageRetention, shareExtensionData} from './middleware';
|
|
||||||
import {transformSet} from './utils';
|
import {transformSet} from './utils';
|
||||||
|
|
||||||
function getAppReducer() {
|
function getAppReducer() {
|
||||||
@@ -134,16 +130,6 @@ export default function configureAppStore(initialState) {
|
|||||||
|
|
||||||
let purging = false;
|
let purging = false;
|
||||||
|
|
||||||
// for iOS write the entities to a shared file
|
|
||||||
if (Platform.OS === 'ios') {
|
|
||||||
store.subscribe(throttle(() => {
|
|
||||||
const state = store.getState();
|
|
||||||
if (state.entities) {
|
|
||||||
mattermostBucket.writeToFile('entities', JSON.stringify(state.entities), Config.AppGroupId);
|
|
||||||
}
|
|
||||||
}, 1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
// check to see if the logout request was successful
|
// check to see if the logout request was successful
|
||||||
store.subscribe(async () => {
|
store.subscribe(async () => {
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
@@ -225,7 +211,7 @@ export default function configureAppStore(initialState) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const additionalMiddleware = [createSentryMiddleware(), messageRetention, shareExtensionData];
|
const additionalMiddleware = [createSentryMiddleware(), messageRetention];
|
||||||
return configureStore(initialState, appReducer, offlineOptions, getAppReducer, {
|
return configureStore(initialState, appReducer, offlineOptions, getAppReducer, {
|
||||||
additionalMiddleware
|
additionalMiddleware
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,12 +3,8 @@
|
|||||||
|
|
||||||
import DeviceInfo from 'react-native-device-info';
|
import DeviceInfo from 'react-native-device-info';
|
||||||
|
|
||||||
import {UserTypes} from 'mattermost-redux/action_types';
|
|
||||||
|
|
||||||
import {ViewTypes} from 'app/constants';
|
import {ViewTypes} from 'app/constants';
|
||||||
import initialState from 'app/initial_state';
|
import initialState from 'app/initial_state';
|
||||||
import mattermostBucket from 'app/mattermost_bucket';
|
|
||||||
import Config from 'assets/config';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
captureException,
|
captureException,
|
||||||
@@ -309,18 +305,3 @@ function cleanupState(action, keepCurrent = false) {
|
|||||||
error: action.error
|
error: action.error
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function shareExtensionData() {
|
|
||||||
return (next) => (action) => {
|
|
||||||
// allow other middleware to do their things
|
|
||||||
const nextAction = next(action);
|
|
||||||
|
|
||||||
switch (action.type) {
|
|
||||||
case UserTypes.LOGOUT_SUCCESS:
|
|
||||||
mattermostBucket.removePreference('emm', Config.AppGroupId);
|
|
||||||
mattermostBucket.removeFile('entities', Config.AppGroupId);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return nextAction;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -44,10 +44,6 @@
|
|||||||
7F292A711E8AB73400A450A3 /* SplashScreenResource in Resources */ = {isa = PBXBuildFile; fileRef = 7F292A701E8AB73400A450A3 /* SplashScreenResource */; };
|
7F292A711E8AB73400A450A3 /* SplashScreenResource in Resources */ = {isa = PBXBuildFile; fileRef = 7F292A701E8AB73400A450A3 /* SplashScreenResource */; };
|
||||||
7F292AA61E8ABB1100A450A3 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7F292AA41E8ABB1100A450A3 /* LaunchScreen.xib */; };
|
7F292AA61E8ABB1100A450A3 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7F292AA41E8ABB1100A450A3 /* LaunchScreen.xib */; };
|
||||||
7F292AA71E8ABB1100A450A3 /* splash.png in Resources */ = {isa = PBXBuildFile; fileRef = 7F292AA51E8ABB1100A450A3 /* splash.png */; };
|
7F292AA71E8ABB1100A450A3 /* splash.png in Resources */ = {isa = PBXBuildFile; fileRef = 7F292AA51E8ABB1100A450A3 /* splash.png */; };
|
||||||
7F380D0B1FDB3CFC0061AAD2 /* libRCTVideo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F93F9D91FBB726B0088E416 /* libRCTVideo.a */; };
|
|
||||||
7F3F66021FE426EE0085CA0E /* libRNSVG.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FDF28E11E1F4B1F00DBBE56 /* libRNSVG.a */; };
|
|
||||||
7F3F660F1FE4280D0085CA0E /* libReactNativeExceptionHandler.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FA7950B1F61A1A500C02924 /* libReactNativeExceptionHandler.a */; };
|
|
||||||
7F3F66101FE4281A0085CA0E /* libRNSentry.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FA795061F61A1A500C02924 /* libRNSentry.a */; };
|
|
||||||
7F43D5A01F6BF882001FC614 /* libRNDeviceInfo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 37DD11281E79EBE1004111BA /* libRNDeviceInfo.a */; };
|
7F43D5A01F6BF882001FC614 /* libRNDeviceInfo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 37DD11281E79EBE1004111BA /* libRNDeviceInfo.a */; };
|
||||||
7F43D5D61F6BF8C2001FC614 /* libRNLocalAuth.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F8C49871F3DFC30003A22BA /* libRNLocalAuth.a */; };
|
7F43D5D61F6BF8C2001FC614 /* libRNLocalAuth.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F8C49871F3DFC30003A22BA /* libRNLocalAuth.a */; };
|
||||||
7F43D5D71F6BF8D0001FC614 /* libRNPasscodeStatus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F8C49F81F3E0710003A22BA /* libRNPasscodeStatus.a */; };
|
7F43D5D71F6BF8D0001FC614 /* libRNPasscodeStatus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F8C49F81F3E0710003A22BA /* libRNPasscodeStatus.a */; };
|
||||||
@@ -63,38 +59,13 @@
|
|||||||
7F43D63F1F6BFA19001FC614 /* libBVLinearGradient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 37D8FEC21E80B5230091F3BD /* libBVLinearGradient.a */; };
|
7F43D63F1F6BFA19001FC614 /* libBVLinearGradient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 37D8FEC21E80B5230091F3BD /* libBVLinearGradient.a */; };
|
||||||
7F43D6401F6BFA82001FC614 /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F63D2811E6C957C001FAE12 /* libRCTPushNotification.a */; };
|
7F43D6401F6BFA82001FC614 /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F63D2811E6C957C001FAE12 /* libRCTPushNotification.a */; };
|
||||||
7F6877B31E7836070094B63F /* libToolTipMenu.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F6877B01E7835E50094B63F /* libToolTipMenu.a */; };
|
7F6877B31E7836070094B63F /* libToolTipMenu.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F6877B01E7835E50094B63F /* libToolTipMenu.a */; };
|
||||||
7F6C47A51FE87E8C00F5A912 /* PerformRequests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F6C47A41FE87E8C00F5A912 /* PerformRequests.m */; };
|
|
||||||
7F7D7F98201645E100D31155 /* libReactNativePermissions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F7D7F87201645D300D31155 /* libReactNativePermissions.a */; };
|
7F7D7F98201645E100D31155 /* libReactNativePermissions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F7D7F87201645D300D31155 /* libReactNativePermissions.a */; };
|
||||||
7FB6006B1FE3116800DB284F /* libRNFetchBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 375218411F4B9E320035444B /* libRNFetchBlob.a */; };
|
|
||||||
7FBB5E9B1E1F5A4B000DE18A /* libRNVectorIcons.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FDF290C1E1F4B4E00DBBE56 /* libRNVectorIcons.a */; };
|
7FBB5E9B1E1F5A4B000DE18A /* libRNVectorIcons.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FDF290C1E1F4B4E00DBBE56 /* libRNVectorIcons.a */; };
|
||||||
7FC200E81EBB65370099331B /* libReactNativeNavigation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FC200DF1EBB65100099331B /* libReactNativeNavigation.a */; };
|
7FC200E81EBB65370099331B /* libReactNativeNavigation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FC200DF1EBB65100099331B /* libReactNativeNavigation.a */; };
|
||||||
7FC649EE1FE983660074E4C7 /* EvilIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 349FBA7338E74D9BBD709528 /* EvilIcons.ttf */; };
|
|
||||||
7FC649F01FE9B5D90074E4C7 /* OpenSans-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D4B1B363C2414DA19C1AC521 /* OpenSans-Bold.ttf */; };
|
|
||||||
7FDB92B11F706F58006CDFD1 /* libRNImagePicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FDB92A71F706F45006CDFD1 /* libRNImagePicker.a */; };
|
7FDB92B11F706F58006CDFD1 /* libRNImagePicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FDB92A71F706F45006CDFD1 /* libRNImagePicker.a */; };
|
||||||
7FEB10981F6101710039A015 /* BlurAppScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FEB10971F6101710039A015 /* BlurAppScreen.m */; };
|
7FEB10981F6101710039A015 /* BlurAppScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FEB10971F6101710039A015 /* BlurAppScreen.m */; };
|
||||||
7FEB109D1F61019C0039A015 /* MattermostManaged.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FEB109A1F61019C0039A015 /* MattermostManaged.m */; };
|
7FEB109D1F61019C0039A015 /* MattermostManaged.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FEB109A1F61019C0039A015 /* MattermostManaged.m */; };
|
||||||
7FEB109E1F61019C0039A015 /* UIImage+ImageEffects.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FEB109C1F61019C0039A015 /* UIImage+ImageEffects.m */; };
|
7FEB109E1F61019C0039A015 /* UIImage+ImageEffects.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FEB109C1F61019C0039A015 /* UIImage+ImageEffects.m */; };
|
||||||
7FF7BE2C1FDEE4AE005E55FE /* MattermostManaged.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FEB109A1F61019C0039A015 /* MattermostManaged.m */; };
|
|
||||||
7FF7BE6D1FDEE5E8005E55FE /* MattermostBucket.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FF7BE6C1FDEE5E8005E55FE /* MattermostBucket.m */; };
|
|
||||||
7FF7BE6E1FDEE5E8005E55FE /* MattermostBucket.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FF7BE6C1FDEE5E8005E55FE /* MattermostBucket.m */; };
|
|
||||||
7FF7BE6F1FDF3CE4005E55FE /* libRNVectorIcons.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FDF290C1E1F4B4E00DBBE56 /* libRNVectorIcons.a */; };
|
|
||||||
7FF7BE701FDF3EE7005E55FE /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 2DCFD31D3F4A4154822AB532 /* Ionicons.ttf */; };
|
|
||||||
7FF7BE711FE004A3005E55FE /* libRNDeviceInfo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 37DD11281E79EBE1004111BA /* libRNDeviceInfo.a */; };
|
|
||||||
7FF7BE721FE01FC7005E55FE /* libRCTOrientation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 374634671E848085005E1244 /* libRCTOrientation.a */; };
|
|
||||||
7FFDB3191FE3566C009E3BCF /* FontAwesome.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 005346E5C0E542BFABAE1411 /* FontAwesome.ttf */; };
|
|
||||||
7FFE329E1FD9CB650038C7A0 /* ShareViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FFE329D1FD9CB650038C7A0 /* ShareViewController.m */; };
|
|
||||||
7FFE32A11FD9CB650038C7A0 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7FFE329F1FD9CB650038C7A0 /* MainInterface.storyboard */; };
|
|
||||||
7FFE32A51FD9CB650038C7A0 /* MattermostShare.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 7FFE329A1FD9CB640038C7A0 /* MattermostShare.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
|
||||||
7FFE32E71FD9CCD00038C7A0 /* libART.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 37ABD39C1F4CE13B001FDE6B /* libART.a */; };
|
|
||||||
7FFE32E81FD9CCDE0038C7A0 /* libRCTCameraRoll.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3752184F1F4B9E980035444B /* libRCTCameraRoll.a */; };
|
|
||||||
7FFE32E91FD9CCF40038C7A0 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
|
|
||||||
7FFE32EA1FD9CD050038C7A0 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
|
|
||||||
7FFE32EB1FD9CD170038C7A0 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; };
|
|
||||||
7FFE32EC1FD9CD360038C7A0 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
|
|
||||||
7FFE32ED1FD9CD450038C7A0 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
|
|
||||||
7FFE32EE1FD9CD800038C7A0 /* libRNLocalAuth.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F8C49871F3DFC30003A22BA /* libRNLocalAuth.a */; };
|
|
||||||
7FFE32EF1FD9CD800038C7A0 /* libRNPasscodeStatus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F8C49F81F3E0710003A22BA /* libRNPasscodeStatus.a */; };
|
|
||||||
7FFE32F11FD9D64E0038C7A0 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; };
|
|
||||||
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
|
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
|
||||||
895C9A56B94A45C1BAF568FE /* Entypo.ttf in Resources */ = {isa = PBXBuildFile; fileRef = AC6EB561E1F64C17A69D2FAD /* Entypo.ttf */; };
|
895C9A56B94A45C1BAF568FE /* Entypo.ttf in Resources */ = {isa = PBXBuildFile; fileRef = AC6EB561E1F64C17A69D2FAD /* Entypo.ttf */; };
|
||||||
8D26455C994F46C39B1392F2 /* libRNSafeArea.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9263CF9B16054263B13EA23B /* libRNSafeArea.a */; };
|
8D26455C994F46C39B1392F2 /* libRNSafeArea.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9263CF9B16054263B13EA23B /* libRNSafeArea.a */; };
|
||||||
@@ -566,13 +537,6 @@
|
|||||||
remoteGlobalIDString = 6DA7B8031F692C4C00FD1D50;
|
remoteGlobalIDString = 6DA7B8031F692C4C00FD1D50;
|
||||||
remoteInfo = RNSafeArea;
|
remoteInfo = RNSafeArea;
|
||||||
};
|
};
|
||||||
7FFE32A31FD9CB650038C7A0 /* PBXContainerItemProxy */ = {
|
|
||||||
isa = PBXContainerItemProxy;
|
|
||||||
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
|
||||||
proxyType = 1;
|
|
||||||
remoteGlobalIDString = 7FFE32991FD9CB640038C7A0;
|
|
||||||
remoteInfo = MattermostShare;
|
|
||||||
};
|
|
||||||
832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = {
|
832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
|
containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
|
||||||
@@ -599,7 +563,6 @@
|
|||||||
dstPath = "";
|
dstPath = "";
|
||||||
dstSubfolderSpec = 13;
|
dstSubfolderSpec = 13;
|
||||||
files = (
|
files = (
|
||||||
7FFE32A51FD9CB650038C7A0 /* MattermostShare.appex in Embed App Extensions */,
|
|
||||||
);
|
);
|
||||||
name = "Embed App Extensions";
|
name = "Embed App Extensions";
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -668,14 +631,11 @@
|
|||||||
7F292A701E8AB73400A450A3 /* SplashScreenResource */ = {isa = PBXFileReference; lastKnownFileType = folder; path = SplashScreenResource; sourceTree = "<group>"; };
|
7F292A701E8AB73400A450A3 /* SplashScreenResource */ = {isa = PBXFileReference; lastKnownFileType = folder; path = SplashScreenResource; sourceTree = "<group>"; };
|
||||||
7F292AA41E8ABB1100A450A3 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = LaunchScreen.xib; path = SplashScreenResource/LaunchScreen.xib; sourceTree = "<group>"; };
|
7F292AA41E8ABB1100A450A3 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = LaunchScreen.xib; path = SplashScreenResource/LaunchScreen.xib; sourceTree = "<group>"; };
|
||||||
7F292AA51E8ABB1100A450A3 /* splash.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = splash.png; path = SplashScreenResource/splash.png; sourceTree = "<group>"; };
|
7F292AA51E8ABB1100A450A3 /* splash.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = splash.png; path = SplashScreenResource/splash.png; sourceTree = "<group>"; };
|
||||||
7F380D0A1FDB28160061AAD2 /* MattermostShare.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MattermostShare.entitlements; sourceTree = "<group>"; };
|
|
||||||
7F43D5DF1F6BF994001FC614 /* libRNSVG.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libRNSVG.a; path = "../../../../../../../Library/Developer/Xcode/DerivedData/Mattermost-czlinsdviifujheezzjvmisotjrm/Build/Products/Debug-iphonesimulator/libRNSVG.a"; sourceTree = "<group>"; };
|
7F43D5DF1F6BF994001FC614 /* libRNSVG.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libRNSVG.a; path = "../../../../../../../Library/Developer/Xcode/DerivedData/Mattermost-czlinsdviifujheezzjvmisotjrm/Build/Products/Debug-iphonesimulator/libRNSVG.a"; sourceTree = "<group>"; };
|
||||||
7F43D6051F6BF9EB001FC614 /* libPods-Mattermost.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-Mattermost.a"; path = "../../../../../../../Library/Developer/Xcode/DerivedData/Mattermost-czlinsdviifujheezzjvmisotjrm/Build/Products/Debug-iphonesimulator/libPods-Mattermost.a"; sourceTree = "<group>"; };
|
7F43D6051F6BF9EB001FC614 /* libPods-Mattermost.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-Mattermost.a"; path = "../../../../../../../Library/Developer/Xcode/DerivedData/Mattermost-czlinsdviifujheezzjvmisotjrm/Build/Products/Debug-iphonesimulator/libPods-Mattermost.a"; sourceTree = "<group>"; };
|
||||||
7F63D27B1E6C957C001FAE12 /* RCTPushNotification.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTPushNotification.xcodeproj; path = "../node_modules/react-native/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj"; sourceTree = "<group>"; };
|
7F63D27B1E6C957C001FAE12 /* RCTPushNotification.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTPushNotification.xcodeproj; path = "../node_modules/react-native/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj"; sourceTree = "<group>"; };
|
||||||
7F63D2C21E6DD98A001FAE12 /* Mattermost.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = Mattermost.entitlements; path = Mattermost/Mattermost.entitlements; sourceTree = "<group>"; };
|
7F63D2C21E6DD98A001FAE12 /* Mattermost.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = Mattermost.entitlements; path = Mattermost/Mattermost.entitlements; sourceTree = "<group>"; };
|
||||||
7F6877AA1E7835E50094B63F /* ToolTipMenu.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ToolTipMenu.xcodeproj; path = "../node_modules/react-native-tooltip/ToolTipMenu.xcodeproj"; sourceTree = "<group>"; };
|
7F6877AA1E7835E50094B63F /* ToolTipMenu.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ToolTipMenu.xcodeproj; path = "../node_modules/react-native-tooltip/ToolTipMenu.xcodeproj"; sourceTree = "<group>"; };
|
||||||
7F6C47A31FE87E8C00F5A912 /* PerformRequests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PerformRequests.h; sourceTree = "<group>"; };
|
|
||||||
7F6C47A41FE87E8C00F5A912 /* PerformRequests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PerformRequests.m; sourceTree = "<group>"; };
|
|
||||||
7F7D7F52201645D300D31155 /* ReactNativePermissions.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativePermissions.xcodeproj; path = "../node_modules/react-native-permissions/ios/ReactNativePermissions.xcodeproj"; sourceTree = "<group>"; };
|
7F7D7F52201645D300D31155 /* ReactNativePermissions.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativePermissions.xcodeproj; path = "../node_modules/react-native-permissions/ios/ReactNativePermissions.xcodeproj"; sourceTree = "<group>"; };
|
||||||
7FC200BC1EBB65100099331B /* ReactNativeNavigation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativeNavigation.xcodeproj; path = "../node_modules/react-native-navigation/ios/ReactNativeNavigation.xcodeproj"; sourceTree = "<group>"; };
|
7FC200BC1EBB65100099331B /* ReactNativeNavigation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativeNavigation.xcodeproj; path = "../node_modules/react-native-navigation/ios/ReactNativeNavigation.xcodeproj"; sourceTree = "<group>"; };
|
||||||
7FDB92751F706F45006CDFD1 /* RNImagePicker.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNImagePicker.xcodeproj; path = "../node_modules/react-native-image-picker/ios/RNImagePicker.xcodeproj"; sourceTree = "<group>"; };
|
7FDB92751F706F45006CDFD1 /* RNImagePicker.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNImagePicker.xcodeproj; path = "../node_modules/react-native-image-picker/ios/RNImagePicker.xcodeproj"; sourceTree = "<group>"; };
|
||||||
@@ -685,13 +645,6 @@
|
|||||||
7FEB109A1F61019C0039A015 /* MattermostManaged.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MattermostManaged.m; path = Mattermost/MattermostManaged.m; sourceTree = "<group>"; };
|
7FEB109A1F61019C0039A015 /* MattermostManaged.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MattermostManaged.m; path = Mattermost/MattermostManaged.m; sourceTree = "<group>"; };
|
||||||
7FEB109B1F61019C0039A015 /* UIImage+ImageEffects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImage+ImageEffects.h"; path = "Mattermost/UIImage+ImageEffects.h"; sourceTree = "<group>"; };
|
7FEB109B1F61019C0039A015 /* UIImage+ImageEffects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImage+ImageEffects.h"; path = "Mattermost/UIImage+ImageEffects.h"; sourceTree = "<group>"; };
|
||||||
7FEB109C1F61019C0039A015 /* UIImage+ImageEffects.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIImage+ImageEffects.m"; path = "Mattermost/UIImage+ImageEffects.m"; sourceTree = "<group>"; };
|
7FEB109C1F61019C0039A015 /* UIImage+ImageEffects.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIImage+ImageEffects.m"; path = "Mattermost/UIImage+ImageEffects.m"; sourceTree = "<group>"; };
|
||||||
7FF7BE6B1FDEE5E8005E55FE /* MattermostBucket.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MattermostBucket.h; sourceTree = "<group>"; };
|
|
||||||
7FF7BE6C1FDEE5E8005E55FE /* MattermostBucket.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MattermostBucket.m; sourceTree = "<group>"; };
|
|
||||||
7FFE329A1FD9CB640038C7A0 /* MattermostShare.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = MattermostShare.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
7FFE329C1FD9CB650038C7A0 /* ShareViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShareViewController.h; sourceTree = "<group>"; };
|
|
||||||
7FFE329D1FD9CB650038C7A0 /* ShareViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ShareViewController.m; sourceTree = "<group>"; };
|
|
||||||
7FFE32A01FD9CB650038C7A0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
|
|
||||||
7FFE32A21FD9CB650038C7A0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
|
||||||
7FFE32B51FD9CCAA0038C7A0 /* FLAnimatedImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FLAnimatedImage.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
7FFE32B51FD9CCAA0038C7A0 /* FLAnimatedImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FLAnimatedImage.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
7FFE32B61FD9CCAA0038C7A0 /* KSCrash.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = KSCrash.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
7FFE32B61FD9CCAA0038C7A0 /* KSCrash.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = KSCrash.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
7FFE32B71FD9CCAA0038C7A0 /* KSCrash.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = KSCrash.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
7FFE32B71FD9CCAA0038C7A0 /* KSCrash.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = KSCrash.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@@ -784,31 +737,6 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
7FFE32971FD9CB640038C7A0 /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
7FFE32E71FD9CCD00038C7A0 /* libART.a in Frameworks */,
|
|
||||||
7F3F66101FE4281A0085CA0E /* libRNSentry.a in Frameworks */,
|
|
||||||
7F3F660F1FE4280D0085CA0E /* libReactNativeExceptionHandler.a in Frameworks */,
|
|
||||||
7FB6006B1FE3116800DB284F /* libRNFetchBlob.a in Frameworks */,
|
|
||||||
7FF7BE721FE01FC7005E55FE /* libRCTOrientation.a in Frameworks */,
|
|
||||||
7FF7BE711FE004A3005E55FE /* libRNDeviceInfo.a in Frameworks */,
|
|
||||||
7FF7BE6F1FDF3CE4005E55FE /* libRNVectorIcons.a in Frameworks */,
|
|
||||||
7F380D0B1FDB3CFC0061AAD2 /* libRCTVideo.a in Frameworks */,
|
|
||||||
7FFE32F11FD9D64E0038C7A0 /* libRCTWebSocket.a in Frameworks */,
|
|
||||||
7FFE32EE1FD9CD800038C7A0 /* libRNLocalAuth.a in Frameworks */,
|
|
||||||
7FFE32EF1FD9CD800038C7A0 /* libRNPasscodeStatus.a in Frameworks */,
|
|
||||||
7F3F66021FE426EE0085CA0E /* libRNSVG.a in Frameworks */,
|
|
||||||
7FFE32ED1FD9CD450038C7A0 /* libRCTNetwork.a in Frameworks */,
|
|
||||||
7FFE32EC1FD9CD360038C7A0 /* libRCTText.a in Frameworks */,
|
|
||||||
7FFE32EB1FD9CD170038C7A0 /* libRCTImage.a in Frameworks */,
|
|
||||||
7FFE32EA1FD9CD050038C7A0 /* libReact.a in Frameworks */,
|
|
||||||
7FFE32E91FD9CCF40038C7A0 /* libRCTAnimation.a in Frameworks */,
|
|
||||||
7FFE32E81FD9CCDE0038C7A0 /* libRCTCameraRoll.a in Frameworks */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
@@ -931,8 +859,6 @@
|
|||||||
7F292AA41E8ABB1100A450A3 /* LaunchScreen.xib */,
|
7F292AA41E8ABB1100A450A3 /* LaunchScreen.xib */,
|
||||||
13B07FB71A68108700A75B9A /* main.m */,
|
13B07FB71A68108700A75B9A /* main.m */,
|
||||||
7F63D2C21E6DD98A001FAE12 /* Mattermost.entitlements */,
|
7F63D2C21E6DD98A001FAE12 /* Mattermost.entitlements */,
|
||||||
7FF7BE6B1FDEE5E8005E55FE /* MattermostBucket.h */,
|
|
||||||
7FF7BE6C1FDEE5E8005E55FE /* MattermostBucket.m */,
|
|
||||||
7FEB10991F61019C0039A015 /* MattermostManaged.h */,
|
7FEB10991F61019C0039A015 /* MattermostManaged.h */,
|
||||||
7FEB109A1F61019C0039A015 /* MattermostManaged.m */,
|
7FEB109A1F61019C0039A015 /* MattermostManaged.m */,
|
||||||
7F292AA51E8ABB1100A450A3 /* splash.png */,
|
7F292AA51E8ABB1100A450A3 /* splash.png */,
|
||||||
@@ -1242,20 +1168,6 @@
|
|||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
7FFE329B1FD9CB650038C7A0 /* MattermostShare */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
7F380D0A1FDB28160061AAD2 /* MattermostShare.entitlements */,
|
|
||||||
7FFE329C1FD9CB650038C7A0 /* ShareViewController.h */,
|
|
||||||
7FFE329D1FD9CB650038C7A0 /* ShareViewController.m */,
|
|
||||||
7FFE329F1FD9CB650038C7A0 /* MainInterface.storyboard */,
|
|
||||||
7FFE32A21FD9CB650038C7A0 /* Info.plist */,
|
|
||||||
7F6C47A31FE87E8C00F5A912 /* PerformRequests.h */,
|
|
||||||
7F6C47A41FE87E8C00F5A912 /* PerformRequests.m */,
|
|
||||||
);
|
|
||||||
path = MattermostShare;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
|
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -1315,7 +1227,6 @@
|
|||||||
13B07FAE1A68108700A75B9A /* Mattermost */,
|
13B07FAE1A68108700A75B9A /* Mattermost */,
|
||||||
832341AE1AAA6A7D00B99B32 /* Libraries */,
|
832341AE1AAA6A7D00B99B32 /* Libraries */,
|
||||||
00E356EF1AD99517003FC87E /* MattermostTests */,
|
00E356EF1AD99517003FC87E /* MattermostTests */,
|
||||||
7FFE329B1FD9CB650038C7A0 /* MattermostShare */,
|
|
||||||
83CBBA001A601CBA00E9B192 /* Products */,
|
83CBBA001A601CBA00E9B192 /* Products */,
|
||||||
0156F464626F49C2977D7982 /* Resources */,
|
0156F464626F49C2977D7982 /* Resources */,
|
||||||
37DF8AC51F5F0D410079BF89 /* Recovered References */,
|
37DF8AC51F5F0D410079BF89 /* Recovered References */,
|
||||||
@@ -1331,7 +1242,6 @@
|
|||||||
children = (
|
children = (
|
||||||
13B07F961A680F5B00A75B9A /* Mattermost.app */,
|
13B07F961A680F5B00A75B9A /* Mattermost.app */,
|
||||||
00E356EE1AD99517003FC87E /* MattermostTests.xctest */,
|
00E356EE1AD99517003FC87E /* MattermostTests.xctest */,
|
||||||
7FFE329A1FD9CB640038C7A0 /* MattermostShare.appex */,
|
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -1378,31 +1288,12 @@
|
|||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
7FFE32A41FD9CB650038C7A0 /* PBXTargetDependency */,
|
|
||||||
);
|
);
|
||||||
name = Mattermost;
|
name = Mattermost;
|
||||||
productName = "Hello World";
|
productName = "Hello World";
|
||||||
productReference = 13B07F961A680F5B00A75B9A /* Mattermost.app */;
|
productReference = 13B07F961A680F5B00A75B9A /* Mattermost.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
};
|
};
|
||||||
7FFE32991FD9CB640038C7A0 /* MattermostShare */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = 7FFE32A61FD9CB650038C7A0 /* Build configuration list for PBXNativeTarget "MattermostShare" */;
|
|
||||||
buildPhases = (
|
|
||||||
7FFE32961FD9CB640038C7A0 /* Sources */,
|
|
||||||
7FFE32971FD9CB640038C7A0 /* Frameworks */,
|
|
||||||
7FFE32981FD9CB640038C7A0 /* Resources */,
|
|
||||||
7FFE32F01FD9D1F00038C7A0 /* Bundle React Native code and images */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
);
|
|
||||||
name = MattermostShare;
|
|
||||||
productName = MattermostShare;
|
|
||||||
productReference = 7FFE329A1FD9CB640038C7A0 /* MattermostShare.appex */;
|
|
||||||
productType = "com.apple.product-type.app-extension";
|
|
||||||
};
|
|
||||||
/* End PBXNativeTarget section */
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
/* Begin PBXProject section */
|
/* Begin PBXProject section */
|
||||||
@@ -1431,17 +1322,6 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
7FFE32991FD9CB640038C7A0 = {
|
|
||||||
CreatedOnToolsVersion = 9.1;
|
|
||||||
DevelopmentTeam = UQ8HT4Q2XM;
|
|
||||||
LastSwiftMigration = 920;
|
|
||||||
ProvisioningStyle = Automatic;
|
|
||||||
SystemCapabilities = {
|
|
||||||
com.apple.ApplicationGroups.iOS = {
|
|
||||||
enabled = 1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Mattermost" */;
|
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Mattermost" */;
|
||||||
@@ -1605,7 +1485,6 @@
|
|||||||
targets = (
|
targets = (
|
||||||
13B07F861A680F5B00A75B9A /* Mattermost */,
|
13B07F861A680F5B00A75B9A /* Mattermost */,
|
||||||
00E356ED1AD99517003FC87E /* MattermostTests */,
|
00E356ED1AD99517003FC87E /* MattermostTests */,
|
||||||
7FFE32991FD9CB640038C7A0 /* MattermostShare */,
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
@@ -2108,18 +1987,6 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
7FFE32981FD9CB640038C7A0 /* Resources */ = {
|
|
||||||
isa = PBXResourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
7FC649F01FE9B5D90074E4C7 /* OpenSans-Bold.ttf in Resources */,
|
|
||||||
7FC649EE1FE983660074E4C7 /* EvilIcons.ttf in Resources */,
|
|
||||||
7FF7BE701FDF3EE7005E55FE /* Ionicons.ttf in Resources */,
|
|
||||||
7FFDB3191FE3566C009E3BCF /* FontAwesome.ttf in Resources */,
|
|
||||||
7FFE32A11FD9CB650038C7A0 /* MainInterface.storyboard in Resources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
@@ -2200,20 +2067,6 @@
|
|||||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Mattermost/Pods-Mattermost-resources.sh\"\n";
|
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Mattermost/Pods-Mattermost-resources.sh\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
7FFE32F01FD9D1F00038C7A0 /* Bundle React Native code and images */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "Bundle React Native code and images";
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = ./bundleReactNative.sh;
|
|
||||||
};
|
|
||||||
AE4769B235D14E6C9C64EA78 /* Upload Debug Symbols to Sentry */ = {
|
AE4769B235D14E6C9C64EA78 /* Upload Debug Symbols to Sentry */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -2279,23 +2132,11 @@
|
|||||||
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
|
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
|
||||||
7FEB109E1F61019C0039A015 /* UIImage+ImageEffects.m in Sources */,
|
7FEB109E1F61019C0039A015 /* UIImage+ImageEffects.m in Sources */,
|
||||||
13B07FC11A68108700A75B9A /* main.m in Sources */,
|
13B07FC11A68108700A75B9A /* main.m in Sources */,
|
||||||
7FF7BE6D1FDEE5E8005E55FE /* MattermostBucket.m in Sources */,
|
|
||||||
7FEB10981F6101710039A015 /* BlurAppScreen.m in Sources */,
|
7FEB10981F6101710039A015 /* BlurAppScreen.m in Sources */,
|
||||||
7FEB109D1F61019C0039A015 /* MattermostManaged.m in Sources */,
|
7FEB109D1F61019C0039A015 /* MattermostManaged.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
7FFE32961FD9CB640038C7A0 /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
7FF7BE6E1FDEE5E8005E55FE /* MattermostBucket.m in Sources */,
|
|
||||||
7FF7BE2C1FDEE4AE005E55FE /* MattermostManaged.m in Sources */,
|
|
||||||
7FFE329E1FD9CB650038C7A0 /* ShareViewController.m in Sources */,
|
|
||||||
7F6C47A51FE87E8C00F5A912 /* PerformRequests.m in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXTargetDependency section */
|
/* Begin PBXTargetDependency section */
|
||||||
@@ -2304,24 +2145,8 @@
|
|||||||
target = 13B07F861A680F5B00A75B9A /* Mattermost */;
|
target = 13B07F861A680F5B00A75B9A /* Mattermost */;
|
||||||
targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
|
targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
7FFE32A41FD9CB650038C7A0 /* PBXTargetDependency */ = {
|
|
||||||
isa = PBXTargetDependency;
|
|
||||||
target = 7FFE32991FD9CB640038C7A0 /* MattermostShare */;
|
|
||||||
targetProxy = 7FFE32A31FD9CB650038C7A0 /* PBXContainerItemProxy */;
|
|
||||||
};
|
|
||||||
/* End PBXTargetDependency section */
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
|
||||||
7FFE329F1FD9CB650038C7A0 /* MainInterface.storyboard */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
7FFE32A01FD9CB650038C7A0 /* Base */,
|
|
||||||
);
|
|
||||||
name = MainInterface.storyboard;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXVariantGroup section */
|
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
00E356F61AD99517003FC87E /* Debug */ = {
|
00E356F61AD99517003FC87E /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
@@ -2400,7 +2225,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
CURRENT_PROJECT_VERSION = 84;
|
CURRENT_PROJECT_VERSION = 86;
|
||||||
DEAD_CODE_STRIPPING = NO;
|
DEAD_CODE_STRIPPING = NO;
|
||||||
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
|
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -2449,7 +2274,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
CURRENT_PROJECT_VERSION = 84;
|
CURRENT_PROJECT_VERSION = 86;
|
||||||
DEAD_CODE_STRIPPING = NO;
|
DEAD_CODE_STRIPPING = NO;
|
||||||
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
|
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -2490,122 +2315,6 @@
|
|||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
7FFE32A71FD9CB650038C7A0 /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
|
||||||
CODE_SIGN_ENTITLEMENTS = MattermostShare/MattermostShare.entitlements;
|
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
|
||||||
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
|
||||||
HEADER_SEARCH_PATHS = (
|
|
||||||
"$(SRCROOT)/../node_modules/react-native/Libraries/PushNotificationIOS/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-orientation/iOS/RCTOrientation/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-navigation/ios/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-notifications/RNNotifications/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-local-auth",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-passcode-status/ios",
|
|
||||||
"$(SRCROOT)/../node_modules/jail-monkey/JailMonkey",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native/Libraries/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-fetch-blob/ios/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-exception-handler/ios",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-sentry/ios/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-cookies/ios/RNCookieManagerIOS",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-youtube/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-video/ios",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-doc-viewer/ios/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-safe-area/ios/RNSafeArea",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = MattermostShare/Info.plist;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
|
||||||
OTHER_LDFLAGS = (
|
|
||||||
"-ObjC",
|
|
||||||
"-lc++",
|
|
||||||
);
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.mattermost.rnbeta.MattermostShare;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SKIP_INSTALL = YES;
|
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "MattermostShare/MattermostShare-Bridging-Header.h";
|
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
|
||||||
SWIFT_VERSION = 3.0;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
7FFE32A81FD9CB650038C7A0 /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
|
||||||
CODE_SIGN_ENTITLEMENTS = MattermostShare/MattermostShare.entitlements;
|
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
|
||||||
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
|
||||||
HEADER_SEARCH_PATHS = (
|
|
||||||
"$(SRCROOT)/../node_modules/react-native/Libraries/PushNotificationIOS/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-orientation/iOS/RCTOrientation/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-navigation/ios/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-notifications/RNNotifications/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-local-auth",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-passcode-status/ios",
|
|
||||||
"$(SRCROOT)/../node_modules/jail-monkey/JailMonkey",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native/Libraries/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-fetch-blob/ios/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-exception-handler/ios",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-sentry/ios/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-cookies/ios/RNCookieManagerIOS",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-youtube/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-video/ios",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-doc-viewer/ios/**",
|
|
||||||
"$(SRCROOT)/../node_modules/react-native-safe-area/ios/RNSafeArea",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = MattermostShare/Info.plist;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
|
||||||
OTHER_LDFLAGS = (
|
|
||||||
"-ObjC",
|
|
||||||
"-lc++",
|
|
||||||
);
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.mattermost.rnbeta.MattermostShare;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SKIP_INSTALL = YES;
|
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "MattermostShare/MattermostShare-Bridging-Header.h";
|
|
||||||
SWIFT_VERSION = 3.0;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
83CBBA201A601CBA00E9B192 /* Debug */ = {
|
83CBBA201A601CBA00E9B192 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
@@ -2711,15 +2420,6 @@
|
|||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
7FFE32A61FD9CB650038C7A0 /* Build configuration list for PBXNativeTarget "MattermostShare" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
7FFE32A71FD9CB650038C7A0 /* Debug */,
|
|
||||||
7FFE32A81FD9CB650038C7A0 /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Mattermost" */ = {
|
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Mattermost" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.6.0</string>
|
<string>1.6.1</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>84</string>
|
<string>86</string>
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
#import <Foundation/Foundation.h>
|
|
||||||
#import "React/RCTBridgeModule.h"
|
|
||||||
|
|
||||||
@interface MattermostBucket : NSObject <RCTBridgeModule>
|
|
||||||
- (NSUserDefaults *)bucketByName:(NSString*)name;
|
|
||||||
-(NSString *)readFromFile:(NSString *)fileName appGroupId:(NSString *)appGroupId;
|
|
||||||
@end
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
//
|
|
||||||
// MattermostBucket.m
|
|
||||||
// Mattermost
|
|
||||||
//
|
|
||||||
// Created by Elias Nahum on 12/11/17.
|
|
||||||
// Copyright © 2017 Facebook. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MattermostBucket.h"
|
|
||||||
|
|
||||||
@implementation MattermostBucket
|
|
||||||
|
|
||||||
+(BOOL)requiresMainQueueSetup
|
|
||||||
{
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
RCT_EXPORT_MODULE();
|
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(writeToFile:(NSString *)fileName
|
|
||||||
content:(NSString *)content
|
|
||||||
bucketName:(NSString *)bucketName) {
|
|
||||||
[self writeToFile:fileName content:content appGroupId:bucketName];
|
|
||||||
}
|
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(readFromFile:(NSString *)fileName
|
|
||||||
bucketName:(NSString*)bucketName
|
|
||||||
getWithResolver:(RCTPromiseResolveBlock)resolve
|
|
||||||
rejecter:(RCTPromiseRejectBlock)reject)
|
|
||||||
{
|
|
||||||
id value = [self readFromFile:fileName appGroupId:bucketName];
|
|
||||||
|
|
||||||
if (value == nil) {
|
|
||||||
value = [NSNull null];
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(removeFile:(NSString *)fileName
|
|
||||||
bucketName:(NSString*)bucketName)
|
|
||||||
{
|
|
||||||
[self removeFile:fileName appGroupId:bucketName];
|
|
||||||
}
|
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(setPreference:(NSString *) key
|
|
||||||
value:(NSString *) value
|
|
||||||
bucketName:(NSString*) bucketName)
|
|
||||||
{
|
|
||||||
[self setPreference:key value:value appGroupId:bucketName];
|
|
||||||
}
|
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(getPreference:(NSString *) key
|
|
||||||
bucketName:(NSString*) bucketName
|
|
||||||
getWithResolver:(RCTPromiseResolveBlock)resolve
|
|
||||||
rejecter:(RCTPromiseRejectBlock)reject)
|
|
||||||
{
|
|
||||||
id value = [self getPreference:key appGroupId:bucketName];
|
|
||||||
|
|
||||||
if (value == nil) {
|
|
||||||
value = [NSNull null];
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(removePreference:(NSString *) key
|
|
||||||
bucketName:(NSString*) bucketName)
|
|
||||||
{
|
|
||||||
[self removePreference:key appGroupId:bucketName];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(NSString *)fileUrl:(NSString *)fileName appGroupdId:(NSString *)appGroupId {
|
|
||||||
NSURL *fileManagerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroupId];
|
|
||||||
return [NSString stringWithFormat:@"%@/%@", fileManagerURL.path, fileName];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)writeToFile:(NSString *)fileName content:(NSString *)content appGroupId:(NSString *)appGroupId {
|
|
||||||
NSString *filePath = [self fileUrl:fileName appGroupdId:appGroupId];
|
|
||||||
NSFileManager *fileManager= [NSFileManager defaultManager];
|
|
||||||
if(![fileManager fileExistsAtPath:filePath]) {
|
|
||||||
[fileManager createFileAtPath:filePath contents:nil attributes:nil];
|
|
||||||
}
|
|
||||||
[content writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(NSString *)readFromFile:(NSString *)fileName appGroupId:(NSString *)appGroupId {
|
|
||||||
NSString *filePath = [self fileUrl:fileName appGroupdId:appGroupId];
|
|
||||||
NSFileManager *fileManager= [NSFileManager defaultManager];
|
|
||||||
if(![fileManager fileExistsAtPath:filePath]) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
return [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)removeFile:(NSString *)fileName appGroupId:(NSString *)appGroupId {
|
|
||||||
NSString *filePath = [self fileUrl:fileName appGroupdId:appGroupId];
|
|
||||||
NSFileManager *fileManager= [NSFileManager defaultManager];
|
|
||||||
if([fileManager isDeletableFileAtPath:filePath]) {
|
|
||||||
[fileManager removeItemAtPath:filePath error:nil];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-(NSUserDefaults *)bucketByName:(NSString*)name {
|
|
||||||
return [[NSUserDefaults alloc] initWithSuiteName: name];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void) setPreference:(NSString *)key value:(NSString *) value appGroupId:(NSString*)appGroupId {
|
|
||||||
NSUserDefaults* bucket = [self bucketByName: appGroupId];
|
|
||||||
[bucket setObject:value forKey:key];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(id) getPreference:(NSString *)key appGroupId:(NSString*)appGroupId {
|
|
||||||
NSUserDefaults* bucket = [self bucketByName: appGroupId];
|
|
||||||
return [bucket objectForKey:key];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void) removePreference:(NSString *)key appGroupId:(NSString*)appGroupId {
|
|
||||||
NSUserDefaults* bucket = [self bucketByName: appGroupId];
|
|
||||||
[bucket removeObjectForKey: key];
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A278a" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="j1y-V4-xli">
|
|
||||||
<dependencies>
|
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
||||||
</dependencies>
|
|
||||||
<scenes>
|
|
||||||
<!--Share View Controller-->
|
|
||||||
<scene sceneID="ceB-am-kn3">
|
|
||||||
<objects>
|
|
||||||
<viewController id="j1y-V4-xli" customClass="ShareViewController" customModuleProvider="" sceneMemberID="viewController">
|
|
||||||
<view key="view" opaque="NO" contentMode="scaleToFill" id="wbc-yd-nQP">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
<viewLayoutGuide key="safeArea" id="1Xd-am-t49"/>
|
|
||||||
</view>
|
|
||||||
</viewController>
|
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="CEy-Cv-SGf" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
|
||||||
</objects>
|
|
||||||
</scene>
|
|
||||||
</scenes>
|
|
||||||
</document>
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>BundleEntryFilename</key>
|
|
||||||
<string>share.ios.js</string>
|
|
||||||
<key>BundleForced</key>
|
|
||||||
<true/>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
|
||||||
<key>CFBundleDisplayName</key>
|
|
||||||
<string>Mattermost</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>com.mattermost.rnbeta.MattermostShare</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>$(PRODUCT_NAME)</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>XPC!</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>1.6.0</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>84</string>
|
|
||||||
<key>NSAppTransportSecurity</key>
|
|
||||||
<dict>
|
|
||||||
<key>NSAllowsArbitraryLoads</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
<key>NSExtension</key>
|
|
||||||
<dict>
|
|
||||||
<key>NSExtensionAttributes</key>
|
|
||||||
<dict>
|
|
||||||
<key>NSExtensionActivationRule</key>
|
|
||||||
<dict>
|
|
||||||
<key>NSExtensionActivationSupportsAttachmentsWithMaxCount</key>
|
|
||||||
<integer>5</integer>
|
|
||||||
<key>NSExtensionActivationSupportsFileWithMaxCount</key>
|
|
||||||
<integer>5</integer>
|
|
||||||
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
|
|
||||||
<integer>5</integer>
|
|
||||||
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
|
|
||||||
<integer>5</integer>
|
|
||||||
<key>NSExtensionActivationSupportsText</key>
|
|
||||||
<true/>
|
|
||||||
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
|
|
||||||
<integer>1</integer>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
<key>NSExtensionMainStoryboard</key>
|
|
||||||
<string>MainInterface</string>
|
|
||||||
<key>NSExtensionPointIdentifier</key>
|
|
||||||
<string>com.apple.share-services</string>
|
|
||||||
</dict>
|
|
||||||
<key>UIAppFonts</key>
|
|
||||||
<array>
|
|
||||||
<string>Ionicons.ttf</string>
|
|
||||||
<string>FontAwesome.ttf</string>
|
|
||||||
<string>EvilIcons.ttf</string>
|
|
||||||
<string>OpenSans-Bold.ttf</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>com.apple.security.application-groups</key>
|
|
||||||
<array>
|
|
||||||
<string>group.com.mattermost.rnbeta</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
//
|
|
||||||
// PerformRequests.h
|
|
||||||
// MattermostShare
|
|
||||||
//
|
|
||||||
// Created by Elias Nahum on 12/18/17.
|
|
||||||
// Copyright © 2017 Facebook. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#import "MattermostBucket.h"
|
|
||||||
|
|
||||||
@interface PerformRequests : NSObject<NSURLSessionDelegate, NSURLSessionTaskDelegate>
|
|
||||||
@property (nonatomic, strong) NSString *appGroupId;
|
|
||||||
@property (nonatomic, strong) NSString *requestId;
|
|
||||||
@property (nonatomic, strong) NSMutableArray *fileIds;
|
|
||||||
@property (nonatomic, strong) NSArray *files;
|
|
||||||
@property (nonatomic, strong) NSDictionary *post;
|
|
||||||
|
|
||||||
@property (nonatomic, strong) NSString *serverUrl;
|
|
||||||
@property (nonatomic, strong) NSString *token;
|
|
||||||
@property (nonatomic, strong) NSExtensionContext *extensionContext;
|
|
||||||
@property MattermostBucket *bucket;
|
|
||||||
|
|
||||||
- (id) initWithPost:(NSDictionary *) post
|
|
||||||
withFiles:(NSArray *) files
|
|
||||||
forRequestId:(NSString *)requestId
|
|
||||||
inAppGroupId:(NSString *) appGroupId
|
|
||||||
inContext:(NSExtensionContext *) extensionContext;
|
|
||||||
|
|
||||||
-(void)createPost;
|
|
||||||
@end
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
//
|
|
||||||
// PerformRequests.m
|
|
||||||
// MattermostShare
|
|
||||||
//
|
|
||||||
// Created by Elias Nahum on 12/18/17.
|
|
||||||
// Copyright © 2017 Facebook. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "PerformRequests.h"
|
|
||||||
#import "MattermostBucket.h"
|
|
||||||
#import "ShareViewController.h"
|
|
||||||
|
|
||||||
@implementation PerformRequests
|
|
||||||
|
|
||||||
- (id) initWithPost:(NSDictionary *) post
|
|
||||||
withFiles:(NSArray *) files
|
|
||||||
forRequestId:(NSString *)requestId
|
|
||||||
inAppGroupId:(NSString *) appGroupId
|
|
||||||
inContext:(NSExtensionContext *) context {
|
|
||||||
self = [super init];
|
|
||||||
if (self) {
|
|
||||||
self.post = post;
|
|
||||||
self.files = files;
|
|
||||||
self.appGroupId = appGroupId;
|
|
||||||
self.requestId = requestId;
|
|
||||||
self.extensionContext = context;
|
|
||||||
|
|
||||||
self.bucket = [[MattermostBucket alloc] init];
|
|
||||||
[self setCredentials];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)setCredentials {
|
|
||||||
NSString *entitiesString = [self.bucket readFromFile:@"entities" appGroupId:self.appGroupId];
|
|
||||||
NSData *entitiesData = [entitiesString dataUsingEncoding:NSUTF8StringEncoding];
|
|
||||||
NSDictionary *entities = [NSJSONSerialization JSONObjectWithData:entitiesData options:NSJSONReadingMutableContainers error:nil];
|
|
||||||
NSDictionary *credentials = [[entities objectForKey:@"general"] objectForKey:@"credentials"];
|
|
||||||
self.serverUrl = [credentials objectForKey:@"url"];
|
|
||||||
self.token = [credentials objectForKey:@"token"];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionDataTask *)task didCompleteWithError:(nullable NSError *)error {
|
|
||||||
if(error != nil) {
|
|
||||||
NSLog(@"ERROR %@", [error userInfo]);
|
|
||||||
[self.extensionContext completeRequestReturningItems:nil
|
|
||||||
completionHandler:nil];
|
|
||||||
NSLog(@"invalidating session %@", self.requestId);
|
|
||||||
[session finishTasksAndInvalidate];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
|
|
||||||
NSString *sessionRequestId = [[session configuration] identifier];
|
|
||||||
|
|
||||||
if ([sessionRequestId containsString:@"files"]) {
|
|
||||||
NSLog(@"Got file response");
|
|
||||||
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
|
||||||
if (json != nil) {
|
|
||||||
NSArray *fileInfos = [json objectForKey:@"file_infos"];
|
|
||||||
self.fileIds = [[NSMutableArray alloc] init];
|
|
||||||
for (id file in fileInfos) {
|
|
||||||
[self.fileIds addObject:[file objectForKey:@"id"]];
|
|
||||||
}
|
|
||||||
NSLog(@"Calling sendPostRequest");
|
|
||||||
[self sendPostRequest];
|
|
||||||
}
|
|
||||||
|
|
||||||
NSLog(@"Cleaning temp files");
|
|
||||||
[self cleanUpTempFiles];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)createPost {
|
|
||||||
NSString *channelId = [self.post objectForKey:@"channel_id"];
|
|
||||||
|
|
||||||
NSURL *filesUrl = [NSURL URLWithString:[self.serverUrl stringByAppendingString:@"/api/v4/files"]];
|
|
||||||
|
|
||||||
if (self.files != nil && [self.files count] > 0) {
|
|
||||||
NSString *POST_BODY_BOUNDARY = @"mobile.client.file.upload";
|
|
||||||
NSURLSessionConfiguration* config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:[self.requestId stringByAppendingString:@"-files"]];
|
|
||||||
config.sharedContainerIdentifier = self.appGroupId;
|
|
||||||
|
|
||||||
NSMutableURLRequest *uploadRequest = [NSMutableURLRequest requestWithURL:filesUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:120.0];
|
|
||||||
[uploadRequest setHTTPMethod:@"POST"];
|
|
||||||
[uploadRequest setValue:[@"Bearer " stringByAppendingString:self.token] forHTTPHeaderField:@"Authorization"];
|
|
||||||
[uploadRequest setValue:@"application/json" forHTTPHeaderField:@"Accept"];
|
|
||||||
|
|
||||||
NSString *contentTypeValue = [NSString stringWithFormat:@"multipart/form-data;boundary=%@", POST_BODY_BOUNDARY];
|
|
||||||
[uploadRequest addValue:contentTypeValue forHTTPHeaderField:@"Content-Type"];
|
|
||||||
|
|
||||||
NSMutableData *dataForm = [NSMutableData alloc];
|
|
||||||
[dataForm appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", POST_BODY_BOUNDARY] dataUsingEncoding:NSUTF8StringEncoding]];
|
|
||||||
[dataForm appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"channel_id\";\r\n\r\n%@", channelId] dataUsingEncoding:NSUTF8StringEncoding]];
|
|
||||||
|
|
||||||
for (id file in self.files) {
|
|
||||||
NSData *fileData = [NSData dataWithContentsOfFile:[file objectForKey:@"filePath"]];
|
|
||||||
NSString *mimeType = [file objectForKey:@"mimeType"];
|
|
||||||
NSLog(@"MimeType %@", mimeType);
|
|
||||||
[dataForm appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", POST_BODY_BOUNDARY] dataUsingEncoding:NSUTF8StringEncoding]];
|
|
||||||
[dataForm appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"files\"; filename=\"%@\"\r\n",
|
|
||||||
[file objectForKey:@"filename"]] dataUsingEncoding:NSUTF8StringEncoding]];
|
|
||||||
[dataForm appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", mimeType] dataUsingEncoding:NSUTF8StringEncoding]];
|
|
||||||
[dataForm appendData:[NSData dataWithData:fileData]];
|
|
||||||
}
|
|
||||||
|
|
||||||
[dataForm appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", POST_BODY_BOUNDARY] dataUsingEncoding:NSUTF8StringEncoding]];
|
|
||||||
[uploadRequest setHTTPBody:dataForm];
|
|
||||||
NSURLSession *uploadSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
|
|
||||||
NSURLSessionDataTask *uploadTask = [uploadSession dataTaskWithRequest:uploadRequest];
|
|
||||||
NSLog(@"Executing file request");
|
|
||||||
[uploadTask resume];
|
|
||||||
} else {
|
|
||||||
[self sendPostRequest];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)sendPostRequest {
|
|
||||||
NSMutableDictionary *post = [self.post mutableCopy];
|
|
||||||
[post setValue:self.fileIds forKey:@"file_ids"];
|
|
||||||
NSData *postData = [NSJSONSerialization dataWithJSONObject:post options:NSJSONWritingPrettyPrinted error:nil];
|
|
||||||
NSString* postAsString = [[NSString alloc] initWithData:postData encoding:NSUTF8StringEncoding];
|
|
||||||
|
|
||||||
NSURL *createUrl = [NSURL URLWithString:[self.serverUrl stringByAppendingString:@"/api/v4/posts"]];
|
|
||||||
|
|
||||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:createUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0];
|
|
||||||
[request setHTTPMethod:@"POST"];
|
|
||||||
[request setValue:[@"Bearer " stringByAppendingString:self.token] forHTTPHeaderField:@"Authorization"];
|
|
||||||
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
|
|
||||||
[request setValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
|
|
||||||
[request setHTTPBody:[postAsString dataUsingEncoding:NSUTF8StringEncoding]];
|
|
||||||
|
|
||||||
NSURLSessionConfiguration* config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
|
|
||||||
NSURLSession *createSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
|
|
||||||
NSURLSessionDataTask *createTask = [createSession dataTaskWithRequest:request];
|
|
||||||
NSLog(@"Executing post request");
|
|
||||||
[createTask resume];
|
|
||||||
[self.extensionContext completeRequestReturningItems:nil
|
|
||||||
completionHandler:nil];
|
|
||||||
NSLog(@"Extension closed");
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) cleanUpTempFiles {
|
|
||||||
NSURL *tmpDirectoryURL = [ShareViewController tempContainerURL:self.appGroupId];
|
|
||||||
if (tmpDirectoryURL == nil) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
||||||
NSError *error;
|
|
||||||
NSArray *tmpFiles = [fileManager contentsOfDirectoryAtPath:[tmpDirectoryURL path] error:&error];
|
|
||||||
if (error) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (NSString *file in tmpFiles)
|
|
||||||
{
|
|
||||||
error = nil;
|
|
||||||
[fileManager removeItemAtPath:[[tmpDirectoryURL URLByAppendingPathComponent:file] path] error:&error];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#import <UIKit/UIKit.h>
|
|
||||||
#import "React/RCTBridgeModule.h"
|
|
||||||
|
|
||||||
@interface ShareViewController : UIViewController<RCTBridgeModule>
|
|
||||||
+ (NSURL*) tempContainerURL: (NSString*)appGroupId;
|
|
||||||
@end
|
|
||||||
@@ -1,273 +0,0 @@
|
|||||||
#import "ShareViewController.h"
|
|
||||||
#import <React/RCTBundleURLProvider.h>
|
|
||||||
#import <React/RCTRootView.h>
|
|
||||||
#import "PerformRequests.h"
|
|
||||||
|
|
||||||
NSExtensionContext* extensionContext;
|
|
||||||
|
|
||||||
@implementation ShareViewController
|
|
||||||
+ (BOOL)requiresMainQueueSetup
|
|
||||||
{
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UIView*) shareView {
|
|
||||||
NSURL *jsCodeLocation;
|
|
||||||
|
|
||||||
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"share.ios" fallbackResource:nil];
|
|
||||||
|
|
||||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
|
|
||||||
moduleName:@"MattermostShare"
|
|
||||||
initialProperties:nil
|
|
||||||
launchOptions:nil];
|
|
||||||
rootView.backgroundColor = nil;
|
|
||||||
return rootView;
|
|
||||||
}
|
|
||||||
|
|
||||||
RCT_EXPORT_MODULE(MattermostShare);
|
|
||||||
|
|
||||||
- (void)viewDidLoad {
|
|
||||||
[super viewDidLoad];
|
|
||||||
extensionContext = self.extensionContext;
|
|
||||||
UIView *rootView = [self shareView];
|
|
||||||
if (rootView.backgroundColor == nil) {
|
|
||||||
rootView.backgroundColor = [[UIColor alloc] initWithRed:1 green:1 blue:1 alpha:0.1];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.view = rootView;
|
|
||||||
}
|
|
||||||
|
|
||||||
RCT_REMAP_METHOD(getOrientation,
|
|
||||||
resolver:(RCTPromiseResolveBlock)resolve
|
|
||||||
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
||||||
if([UIScreen mainScreen].bounds.size.width < [UIScreen mainScreen].bounds.size.height) {
|
|
||||||
resolve(@"PORTRAIT");
|
|
||||||
} else {
|
|
||||||
resolve(@"LANDSCAPE");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(close:(NSDictionary *)data appGroupId:(NSString *)appGroupId) {
|
|
||||||
if (data != nil) {
|
|
||||||
NSDictionary *post = [data objectForKey:@"post"];
|
|
||||||
NSArray *files = [data objectForKey:@"files"];
|
|
||||||
NSString *requestId = [data objectForKey:@"requestId"];
|
|
||||||
NSLog(@"Call createPost");
|
|
||||||
PerformRequests *request = [[PerformRequests alloc] initWithPost:post withFiles:files forRequestId:requestId inAppGroupId:appGroupId inContext:extensionContext];
|
|
||||||
[request createPost];
|
|
||||||
} else {
|
|
||||||
[extensionContext completeRequestReturningItems:nil
|
|
||||||
completionHandler:nil];
|
|
||||||
NSLog(@"Extension closed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RCT_REMAP_METHOD(data,
|
|
||||||
appGroupId: (NSString *)appGroupId
|
|
||||||
resolver:(RCTPromiseResolveBlock)resolve
|
|
||||||
rejecter:(RCTPromiseRejectBlock)reject)
|
|
||||||
{
|
|
||||||
[self extractDataFromContext: extensionContext withAppGroup: appGroupId andCallback:^(NSArray* items ,NSError* err) {
|
|
||||||
if (err) {
|
|
||||||
reject(@"data", @"Failed to extract attachment content", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve(items);
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef void (^ProviderCallback)(NSString *content, NSString *contentType, BOOL owner, NSError *err);
|
|
||||||
|
|
||||||
- (void)extractDataFromContext:(NSExtensionContext *)context withAppGroup:(NSString *) appGroupId andCallback:(void(^)(NSArray *items ,NSError *err))callback {
|
|
||||||
@try {
|
|
||||||
NSExtensionItem *item = [context.inputItems firstObject];
|
|
||||||
NSArray *attachments = item.attachments;
|
|
||||||
NSMutableArray *items = [[NSMutableArray alloc] init];
|
|
||||||
|
|
||||||
__block int attachmentIdx = 0;
|
|
||||||
__block ProviderCallback providerCb = nil;
|
|
||||||
__block __weak ProviderCallback weakProviderCb = nil;
|
|
||||||
providerCb = ^ void (NSString *content, NSString *contentType, BOOL owner, NSError *err) {
|
|
||||||
if (err) {
|
|
||||||
callback(nil, err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (content != nil) {
|
|
||||||
[items addObject:@{
|
|
||||||
@"type": contentType,
|
|
||||||
@"value": content,
|
|
||||||
@"owner": [NSNumber numberWithBool:owner],
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
++attachmentIdx;
|
|
||||||
if (attachmentIdx == [attachments count]) {
|
|
||||||
callback(items, nil);
|
|
||||||
} else {
|
|
||||||
[self extractDataFromProvider:attachments[attachmentIdx] withAppGroup:appGroupId andCallback: weakProviderCb];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
weakProviderCb = providerCb;
|
|
||||||
[self extractDataFromProvider:attachments[0] withAppGroup:appGroupId andCallback: providerCb];
|
|
||||||
}
|
|
||||||
@catch (NSException *exc) {
|
|
||||||
NSError *error = [NSError errorWithDomain:@"fiftythree.paste" code:1 userInfo:@{
|
|
||||||
@"reason": [exc description]
|
|
||||||
}];
|
|
||||||
callback(nil, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)extractDataFromProvider:(NSItemProvider *)provider withAppGroup:(NSString *) appGroupId andCallback:(void(^)(NSString* content, NSString* contentType, BOOL owner, NSError *err))callback {
|
|
||||||
if([provider hasItemConformingToTypeIdentifier:@"public.movie"]) {
|
|
||||||
[provider loadItemForTypeIdentifier:@"public.movie" options:nil completionHandler:^(id<NSSecureCoding, NSObject> item, NSError *error) {
|
|
||||||
@try {
|
|
||||||
if ([item isKindOfClass: NSURL.class]) {
|
|
||||||
NSURL *url = (NSURL *)item;
|
|
||||||
return callback([url absoluteString], @"public.movie", NO, nil);
|
|
||||||
}
|
|
||||||
return callback(nil, nil, NO, nil);
|
|
||||||
}
|
|
||||||
@catch(NSException *exc) {
|
|
||||||
NSError *error = [NSError errorWithDomain:@"fiftythree.paste" code:2 userInfo:@{
|
|
||||||
@"reason": [exc description]
|
|
||||||
}];
|
|
||||||
callback(nil, nil, NO, error);
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if([provider hasItemConformingToTypeIdentifier:@"public.image"]) {
|
|
||||||
[provider loadItemForTypeIdentifier:@"public.image" options:nil completionHandler:^(id<NSSecureCoding, NSObject> item, NSError *error) {
|
|
||||||
if (error) {
|
|
||||||
callback(nil, nil, NO, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
@try {
|
|
||||||
if ([item isKindOfClass: NSURL.class]) {
|
|
||||||
NSURL *url = (NSURL *)item;
|
|
||||||
return callback([url absoluteString], @"public.image", NO, nil);
|
|
||||||
} else if ([item isKindOfClass: UIImage.class]) {
|
|
||||||
UIImage *image = (UIImage *)item;
|
|
||||||
NSString *fileName = [NSString stringWithFormat:@"%@.jpg", [[NSUUID UUID] UUIDString]];
|
|
||||||
NSURL *tempContainerURL = [ShareViewController tempContainerURL:appGroupId];
|
|
||||||
if (tempContainerURL == nil){
|
|
||||||
return callback(nil, nil, NO, nil);
|
|
||||||
}
|
|
||||||
|
|
||||||
NSURL *tempFileURL = [tempContainerURL URLByAppendingPathComponent: fileName];
|
|
||||||
BOOL created = [UIImageJPEGRepresentation(image, 1) writeToFile:[tempFileURL path] atomically:YES];
|
|
||||||
if (created) {
|
|
||||||
return callback([tempFileURL absoluteString], @"public.image", YES, nil);
|
|
||||||
} else {
|
|
||||||
return callback(nil, nil, NO, nil);
|
|
||||||
}
|
|
||||||
} else if ([item isKindOfClass: NSData.class]) {
|
|
||||||
NSString *fileName = [NSString stringWithFormat:@"%@.jpg", [[NSUUID UUID] UUIDString]];
|
|
||||||
NSData *data = (NSData *)item;
|
|
||||||
UIImage *image = [UIImage imageWithData:data];
|
|
||||||
NSURL *tempContainerURL = [ShareViewController tempContainerURL:appGroupId];
|
|
||||||
if (tempContainerURL == nil){
|
|
||||||
return callback(nil, nil, NO, nil);
|
|
||||||
}
|
|
||||||
NSURL *tempFileURL = [tempContainerURL URLByAppendingPathComponent: fileName];
|
|
||||||
BOOL created = [UIImageJPEGRepresentation(image, 0.95) writeToFile:[tempFileURL path] atomically:YES];
|
|
||||||
if (created) {
|
|
||||||
return callback([tempFileURL absoluteString], @"public.image", YES, nil);
|
|
||||||
} else {
|
|
||||||
return callback(nil, nil, NO, nil);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Do nothing, some type we don't support.
|
|
||||||
return callback(nil, nil, NO, nil);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@catch(NSException *exc) {
|
|
||||||
NSError *error = [NSError errorWithDomain:@"fiftythree.paste" code:2 userInfo:@{
|
|
||||||
@"reason": [exc description]
|
|
||||||
}];
|
|
||||||
callback(nil, nil, NO, error);
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if([provider hasItemConformingToTypeIdentifier:@"public.file-url"]) {
|
|
||||||
[provider loadItemForTypeIdentifier:@"public.file-url" options:nil completionHandler:^(id<NSSecureCoding, NSObject> item, NSError *error) {
|
|
||||||
if (error) {
|
|
||||||
callback(nil, nil, NO, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([item isKindOfClass:NSURL.class]) {
|
|
||||||
return callback([(NSURL *)item absoluteString], @"public.file-url", NO, nil);
|
|
||||||
} else if ([item isKindOfClass:NSString.class]) {
|
|
||||||
return callback((NSString *)item, @"public.file-url", NO, nil);
|
|
||||||
}
|
|
||||||
callback(nil, nil, NO, nil);
|
|
||||||
}];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if([provider hasItemConformingToTypeIdentifier:@"public.url"]) {
|
|
||||||
[provider loadItemForTypeIdentifier:@"public.url" options:nil completionHandler:^(id<NSSecureCoding, NSObject> item, NSError *error) {
|
|
||||||
if (error) {
|
|
||||||
callback(nil, nil, NO, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([item isKindOfClass:NSURL.class]) {
|
|
||||||
return callback([(NSURL *)item absoluteString], @"public.url", NO, nil);
|
|
||||||
} else if ([item isKindOfClass:NSString.class]) {
|
|
||||||
return callback((NSString *)item, @"public.url", NO, nil);
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if([provider hasItemConformingToTypeIdentifier:@"public.plain-text"]) {
|
|
||||||
[provider loadItemForTypeIdentifier:@"public.plain-text" options:nil completionHandler:^(id<NSSecureCoding, NSObject> item, NSError *error) {
|
|
||||||
if (error) {
|
|
||||||
callback(nil, nil, NO, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([item isKindOfClass:NSString.class]) {
|
|
||||||
return callback((NSString *)item, @"public.plain-text", NO, nil);
|
|
||||||
} else if ([item isKindOfClass:NSAttributedString.class]) {
|
|
||||||
NSAttributedString *str = (NSAttributedString *)item;
|
|
||||||
return callback([str string], @"public.plain-text", NO, nil);
|
|
||||||
} else if ([item isKindOfClass:NSData.class]) {
|
|
||||||
NSString *str = [[NSString alloc] initWithData:(NSData *)item encoding:NSUTF8StringEncoding];
|
|
||||||
if (str) {
|
|
||||||
return callback(str, @"public.plain-text", NO, nil);
|
|
||||||
} else {
|
|
||||||
return callback(nil, nil, NO, nil);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return callback(nil, nil, NO, nil);
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(nil, nil, NO, nil);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSURL*) tempContainerURL: (NSString*)appGroupId {
|
|
||||||
NSFileManager *manager = [NSFileManager defaultManager];
|
|
||||||
NSURL *containerURL = [manager containerURLForSecurityApplicationGroupIdentifier: appGroupId];
|
|
||||||
NSURL *tempDirectoryURL = [containerURL URLByAppendingPathComponent:@"shareTempItems"];
|
|
||||||
if (![manager fileExistsAtPath:[tempDirectoryURL path]]) {
|
|
||||||
NSError *err;
|
|
||||||
[manager createDirectoryAtURL:tempDirectoryURL withIntermediateDirectories:YES attributes:nil error:&err];
|
|
||||||
if (err) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return tempDirectoryURL;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
@@ -15,10 +15,10 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>BNDL</string>
|
<string>BNDL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.3.0</string>
|
<string>1.6.1</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>84</string>
|
<string>86</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See License.txt for license information.
|
|
||||||
|
|
||||||
import {AppRegistry} from 'react-native';
|
|
||||||
|
|
||||||
import ShareExtension from 'share_extension/ios';
|
|
||||||
|
|
||||||
AppRegistry.registerComponent('MattermostShare', () => ShareExtension);
|
|
||||||
@@ -1,324 +0,0 @@
|
|||||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See License.txt for license information.
|
|
||||||
|
|
||||||
import React, {PureComponent} from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import {
|
|
||||||
ActivityIndicator,
|
|
||||||
SectionList,
|
|
||||||
Text,
|
|
||||||
View
|
|
||||||
} from 'react-native';
|
|
||||||
import DeviceInfo from 'react-native-device-info';
|
|
||||||
import {intlShape} from 'react-intl';
|
|
||||||
|
|
||||||
import {General} from 'mattermost-redux/constants';
|
|
||||||
import {getChannelsInTeam, getDirectChannels} from 'mattermost-redux/selectors/entities/channels';
|
|
||||||
|
|
||||||
import SearchBar from 'app/components/search_bar';
|
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
|
||||||
|
|
||||||
import ExtensionChannelItem from 'share_extension/common/extension_channel_item';
|
|
||||||
|
|
||||||
import ExtensionNavBar from './extension_nav_bar';
|
|
||||||
|
|
||||||
export default class ExtensionChannels extends PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
entities: PropTypes.object,
|
|
||||||
currentChannelId: PropTypes.string.isRequired,
|
|
||||||
navigator: PropTypes.object.isRequired,
|
|
||||||
onSelectChannel: PropTypes.func.isRequired,
|
|
||||||
teamId: PropTypes.string.isRequired,
|
|
||||||
theme: PropTypes.object.isRequired,
|
|
||||||
title: PropTypes.string.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
intl: intlShape
|
|
||||||
};
|
|
||||||
|
|
||||||
state = {
|
|
||||||
sections: null
|
|
||||||
};
|
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
this.loadChannels();
|
|
||||||
}
|
|
||||||
|
|
||||||
buildSections = (term) => {
|
|
||||||
const {channels} = this.state;
|
|
||||||
const sections = [];
|
|
||||||
const publicChannels = [];
|
|
||||||
const privateChannels = [];
|
|
||||||
const directChannels = [];
|
|
||||||
|
|
||||||
channels.forEach((channel) => {
|
|
||||||
const include = term ? channel.display_name.toLowerCase().includes(term.toLowerCase()) : true;
|
|
||||||
if (channel.display_name && include) {
|
|
||||||
switch (channel.type) {
|
|
||||||
case General.OPEN_CHANNEL:
|
|
||||||
publicChannels.push(channel);
|
|
||||||
break;
|
|
||||||
case General.PRIVATE_CHANNEL:
|
|
||||||
privateChannels.push(channel);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
directChannels.push(channel);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (publicChannels.length) {
|
|
||||||
sections.push({
|
|
||||||
id: 'sidebar.channels',
|
|
||||||
defaultMessage: 'PUBLIC CHANNELS',
|
|
||||||
data: publicChannels.sort(this.sortDisplayName)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (privateChannels.length) {
|
|
||||||
sections.push({
|
|
||||||
id: 'sidebar.pg',
|
|
||||||
defaultMessage: 'PRIVATE CHANNELS',
|
|
||||||
data: privateChannels.sort(this.sortDisplayName)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (directChannels.length) {
|
|
||||||
sections.push({
|
|
||||||
id: 'sidebar.direct',
|
|
||||||
defaultMessage: 'DIRECT MESSAGES',
|
|
||||||
data: directChannels.sort(this.sortDisplayName)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({sections});
|
|
||||||
};
|
|
||||||
|
|
||||||
goBack = () => {
|
|
||||||
this.props.navigator.pop();
|
|
||||||
};
|
|
||||||
|
|
||||||
keyExtractor = (item) => item.id;
|
|
||||||
|
|
||||||
loadChannels = async () => {
|
|
||||||
try {
|
|
||||||
const {entities, teamId} = this.props;
|
|
||||||
|
|
||||||
// get the channels for the specified team
|
|
||||||
const channelsInTeam = getChannelsInTeam({entities});
|
|
||||||
const channelIds = channelsInTeam[teamId] || [];
|
|
||||||
const direct = getDirectChannels({entities});
|
|
||||||
const channels = channelIds.map((id) => this.props.entities.channels.channels[id]).concat(direct);
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
channels
|
|
||||||
}, () => {
|
|
||||||
this.buildSections();
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
this.setState({error});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleSearch = (term) => {
|
|
||||||
this.setState({term}, () => {
|
|
||||||
if (this.throttleTimeout) {
|
|
||||||
clearTimeout(this.throttleTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.throttleTimeout = setTimeout(() => {
|
|
||||||
this.buildSections(term);
|
|
||||||
}, 300);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleSelectChannel = (channel) => {
|
|
||||||
this.props.onSelectChannel(channel);
|
|
||||||
this.goBack();
|
|
||||||
};
|
|
||||||
|
|
||||||
renderBody = (styles) => {
|
|
||||||
const {error, sections} = this.state;
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return (
|
|
||||||
<View style={styles.errorContainer}>
|
|
||||||
<Text style={styles.error}>
|
|
||||||
{error.message}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sections) {
|
|
||||||
return (
|
|
||||||
<View style={styles.loadingContainer}>
|
|
||||||
<ActivityIndicator/>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SectionList
|
|
||||||
sections={sections}
|
|
||||||
ListHeaderComponent={this.renderSearchBar(styles)}
|
|
||||||
ItemSeparatorComponent={this.renderItemSeparator}
|
|
||||||
renderItem={this.renderItem}
|
|
||||||
renderSectionHeader={this.renderSectionHeader}
|
|
||||||
keyExtractor={this.keyExtractor}
|
|
||||||
keyboardShouldPersistTaps='always'
|
|
||||||
keyboardDismissMode='on-drag'
|
|
||||||
initialNumToRender={10}
|
|
||||||
maxToRenderPerBatch={10}
|
|
||||||
stickySectionHeadersEnabled={true}
|
|
||||||
scrollEventThrottle={100}
|
|
||||||
windowSize={5}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
renderItem = ({item}) => {
|
|
||||||
const {currentChannelId, theme} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ExtensionChannelItem
|
|
||||||
channel={item}
|
|
||||||
currentChannelId={currentChannelId}
|
|
||||||
onSelectChannel={this.handleSelectChannel}
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
renderItemSeparator = () => {
|
|
||||||
const {theme} = this.props;
|
|
||||||
const styles = getStyleSheet(theme);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={styles.separatorContainer}>
|
|
||||||
<View style={styles.separator}/>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
renderSearchBar = (styles) => {
|
|
||||||
const {formatMessage} = this.context.intl;
|
|
||||||
const {theme} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={styles.searchContainer}>
|
|
||||||
<SearchBar
|
|
||||||
ref='search_bar'
|
|
||||||
placeholder={formatMessage({id: 'search_bar.search', defaultMessage: 'Search'})}
|
|
||||||
cancelTitle={formatMessage({id: 'mobile.post.cancel', defaultMessage: 'Cancel'})}
|
|
||||||
backgroundColor='transparent'
|
|
||||||
inputHeight={33}
|
|
||||||
inputStyle={styles.searchBarInput}
|
|
||||||
placeholderTextColor={changeOpacity(theme.centerChannelColor, 0.5)}
|
|
||||||
tintColorSearch={changeOpacity(theme.centerChannelColor, 0.5)}
|
|
||||||
tintColorDelete={changeOpacity(theme.centerChannelColor, 0.3)}
|
|
||||||
titleCancelColor={theme.linkColor}
|
|
||||||
onChangeText={this.handleSearch}
|
|
||||||
value={this.state.term}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
renderSectionHeader = ({section}) => {
|
|
||||||
const {intl} = this.context;
|
|
||||||
const {theme} = this.props;
|
|
||||||
const styles = getStyleSheet(theme);
|
|
||||||
const {
|
|
||||||
defaultMessage,
|
|
||||||
id
|
|
||||||
} = section;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={[styles.titleContainer, {backgroundColor: theme.centerChannelBg}]}>
|
|
||||||
<View style={{backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), justifyContent: 'center'}}>
|
|
||||||
<Text style={styles.title}>
|
|
||||||
{intl.formatMessage({id, defaultMessage}).toUpperCase()}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
sort = (a, b) => {
|
|
||||||
const locale = DeviceInfo.getDeviceLocale().split('-')[0];
|
|
||||||
return a.localeCompare(b, locale, {numeric: true});
|
|
||||||
};
|
|
||||||
|
|
||||||
sortDisplayName = (a, b) => {
|
|
||||||
const locale = DeviceInfo.getDeviceLocale().split('-')[0];
|
|
||||||
return a.display_name.localeCompare(b.display_name, locale, {numeric: true});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {theme, title} = this.props;
|
|
||||||
const styles = getStyleSheet(theme);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={styles.flex}>
|
|
||||||
<ExtensionNavBar
|
|
||||||
backButton={true}
|
|
||||||
onLeftButtonPress={this.goBack}
|
|
||||||
title={title}
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
{this.renderBody(styles)}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|
||||||
return {
|
|
||||||
flex: {
|
|
||||||
flex: 1
|
|
||||||
},
|
|
||||||
separatorContainer: {
|
|
||||||
paddingLeft: 35
|
|
||||||
},
|
|
||||||
separator: {
|
|
||||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.2),
|
|
||||||
height: 1
|
|
||||||
},
|
|
||||||
loadingContainer: {
|
|
||||||
alignItems: 'center',
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: 'center'
|
|
||||||
},
|
|
||||||
searchContainer: {
|
|
||||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.2),
|
|
||||||
paddingBottom: 2
|
|
||||||
},
|
|
||||||
searchBarInput: {
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
color: theme.centerChannelColor,
|
|
||||||
fontSize: 15
|
|
||||||
},
|
|
||||||
titleContainer: {
|
|
||||||
height: 30
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
color: changeOpacity(theme.centerChannelColor, 0.6),
|
|
||||||
fontSize: 15,
|
|
||||||
lineHeight: 30,
|
|
||||||
paddingHorizontal: 15
|
|
||||||
},
|
|
||||||
errorContainer: {
|
|
||||||
alignItems: 'center',
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: 'center',
|
|
||||||
paddingHorizontal: 15
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
color: theme.errorTextColor,
|
|
||||||
fontSize: 14
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See License.txt for license information.
|
|
||||||
|
|
||||||
import React, {PureComponent} from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import {Text, TouchableOpacity, View} from 'react-native';
|
|
||||||
import IonIcon from 'react-native-vector-icons/Ionicons';
|
|
||||||
|
|
||||||
import {emptyFunction} from 'app/utils/general';
|
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
|
||||||
|
|
||||||
export default class ExtensionNavBar extends PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
authenticated: PropTypes.bool,
|
|
||||||
backButton: PropTypes.bool,
|
|
||||||
leftButtonTitle: PropTypes.string,
|
|
||||||
onLeftButtonPress: PropTypes.func,
|
|
||||||
onRightButtonPress: PropTypes.func,
|
|
||||||
rightButtonTitle: PropTypes.string,
|
|
||||||
theme: PropTypes.object.isRequired,
|
|
||||||
title: PropTypes.string
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
backButton: false,
|
|
||||||
onLeftButtonPress: emptyFunction,
|
|
||||||
title: 'Mattermost'
|
|
||||||
};
|
|
||||||
|
|
||||||
renderLeftButton = (styles) => {
|
|
||||||
const {backButton, leftButtonTitle, onLeftButtonPress} = this.props;
|
|
||||||
let backComponent;
|
|
||||||
if (backButton) {
|
|
||||||
backComponent = (
|
|
||||||
<IonIcon
|
|
||||||
name='ios-arrow-back'
|
|
||||||
style={styles.backButton}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else if (leftButtonTitle) {
|
|
||||||
backComponent = (
|
|
||||||
<Text
|
|
||||||
ellipsisMode='tail'
|
|
||||||
numberOfLines={1}
|
|
||||||
style={styles.leftButton}
|
|
||||||
>
|
|
||||||
{leftButtonTitle}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (backComponent) {
|
|
||||||
return (
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={onLeftButtonPress}
|
|
||||||
style={styles.backButtonContainer}
|
|
||||||
>
|
|
||||||
{backComponent}
|
|
||||||
</TouchableOpacity>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <View style={styles.backButtonContainer}/>;
|
|
||||||
};
|
|
||||||
|
|
||||||
renderRightButton = (styles) => {
|
|
||||||
const {authenticated, onRightButtonPress, rightButtonTitle} = this.props;
|
|
||||||
|
|
||||||
if (rightButtonTitle && authenticated) {
|
|
||||||
return (
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={onRightButtonPress}
|
|
||||||
style={styles.rightButtonContainer}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
ellipsisMode='tail'
|
|
||||||
numberOfLines={1}
|
|
||||||
style={styles.rightButton}
|
|
||||||
>
|
|
||||||
{rightButtonTitle}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <View style={styles.rightButtonContainer}/>;
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {theme, title} = this.props;
|
|
||||||
const styles = getStyleSheet(theme);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={styles.container}>
|
|
||||||
{this.renderLeftButton(styles)}
|
|
||||||
<View style={styles.titleContainer}>
|
|
||||||
<Text style={styles.title}>
|
|
||||||
{title}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
{this.renderRightButton(styles)}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|
||||||
return {
|
|
||||||
container: {
|
|
||||||
borderBottomColor: changeOpacity(theme.centerChannelColor, 0.2),
|
|
||||||
borderBottomWidth: 1,
|
|
||||||
flexDirection: 'row',
|
|
||||||
height: 45
|
|
||||||
},
|
|
||||||
backButtonContainer: {
|
|
||||||
justifyContent: 'center',
|
|
||||||
paddingHorizontal: 15,
|
|
||||||
width: '30%'
|
|
||||||
},
|
|
||||||
titleContainer: {
|
|
||||||
alignItems: 'center',
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: 'center'
|
|
||||||
},
|
|
||||||
backButton: {
|
|
||||||
color: theme.linkColor,
|
|
||||||
fontSize: 34
|
|
||||||
},
|
|
||||||
leftButton: {
|
|
||||||
color: theme.linkColor,
|
|
||||||
fontSize: 16
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
fontSize: 17,
|
|
||||||
fontWeight: '600'
|
|
||||||
},
|
|
||||||
rightButtonContainer: {
|
|
||||||
alignItems: 'flex-end',
|
|
||||||
justifyContent: 'center',
|
|
||||||
paddingHorizontal: 15,
|
|
||||||
width: '30%'
|
|
||||||
},
|
|
||||||
rightButton: {
|
|
||||||
color: theme.linkColor,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: '600'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -1,758 +0,0 @@
|
|||||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See License.txt for license information.
|
|
||||||
|
|
||||||
import React, {PureComponent} from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import {intlShape} from 'react-intl';
|
|
||||||
import {
|
|
||||||
ActivityIndicator,
|
|
||||||
Dimensions,
|
|
||||||
Image,
|
|
||||||
NativeModules,
|
|
||||||
ScrollView,
|
|
||||||
Text,
|
|
||||||
TextInput,
|
|
||||||
TouchableHighlight,
|
|
||||||
View
|
|
||||||
} from 'react-native';
|
|
||||||
import IonIcon from 'react-native-vector-icons/Ionicons';
|
|
||||||
import Video from 'react-native-video';
|
|
||||||
import LocalAuth from 'react-native-local-auth';
|
|
||||||
import RNFetchBlob from 'react-native-fetch-blob';
|
|
||||||
|
|
||||||
import {Client4} from 'mattermost-redux/client';
|
|
||||||
import {getFormattedFileSize, lookupMimeType} from 'mattermost-redux/utils/file_utils';
|
|
||||||
|
|
||||||
import mattermostBucket from 'app/mattermost_bucket';
|
|
||||||
import {generateId} from 'app/utils/file';
|
|
||||||
import {wrapWithPreventDoubleTap} from 'app/utils/tap';
|
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
|
||||||
import Config from 'assets/config';
|
|
||||||
|
|
||||||
import {
|
|
||||||
ExcelSvg,
|
|
||||||
GenericSvg,
|
|
||||||
PdfSvg,
|
|
||||||
PptSvg,
|
|
||||||
ZipSvg
|
|
||||||
} from 'share_extension/common/icons';
|
|
||||||
|
|
||||||
import ExtensionChannels from './extension_channels';
|
|
||||||
import ExtensionNavBar from './extension_nav_bar';
|
|
||||||
import ExtensionTeams from './extension_teams';
|
|
||||||
import {General} from 'mattermost-redux/constants/index';
|
|
||||||
|
|
||||||
const ShareExtension = NativeModules.MattermostShare;
|
|
||||||
const MAX_INPUT_HEIGHT = 95;
|
|
||||||
const MAX_MESSAGE_LENGTH = 4000;
|
|
||||||
const MAX_FILE_SIZE = 20 * 1024 * 1024;
|
|
||||||
|
|
||||||
const extensionSvg = {
|
|
||||||
csv: ExcelSvg,
|
|
||||||
pdf: PdfSvg,
|
|
||||||
ppt: PptSvg,
|
|
||||||
pptx: PptSvg,
|
|
||||||
xls: ExcelSvg,
|
|
||||||
xlsx: ExcelSvg,
|
|
||||||
zip: ZipSvg
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class ExtensionPost extends PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
authenticated: PropTypes.bool.isRequired,
|
|
||||||
entities: PropTypes.object,
|
|
||||||
navigator: PropTypes.object.isRequired,
|
|
||||||
onClose: PropTypes.func.isRequired,
|
|
||||||
theme: PropTypes.object.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
intl: intlShape
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
|
|
||||||
const {height, width} = Dimensions.get('window');
|
|
||||||
const isLandscape = width > height;
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
entities: props.entities,
|
|
||||||
error: null,
|
|
||||||
files: [],
|
|
||||||
isLandscape,
|
|
||||||
totalSize: 0,
|
|
||||||
value: '',
|
|
||||||
sending: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
this.loadData();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.focusInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
this.focusInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
emmAuthenticationIfNeeded = async () => {
|
|
||||||
try {
|
|
||||||
const emmSecured = await mattermostBucket.getPreference('emm', Config.AppGroupId);
|
|
||||||
if (emmSecured) {
|
|
||||||
const {intl} = this.context;
|
|
||||||
await LocalAuth.authenticate({
|
|
||||||
reason: intl.formatMessage({
|
|
||||||
id: 'mobile.managed.secured_by',
|
|
||||||
defaultMessage: 'Secured by {vendor}'
|
|
||||||
}, {emmSecured}),
|
|
||||||
fallbackToPasscode: true,
|
|
||||||
suppressEnterPassword: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
this.props.onClose();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
focusInput = () => {
|
|
||||||
if (this.input && !this.input.isFocused()) {
|
|
||||||
this.input.focus();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
getInputRef = (ref) => {
|
|
||||||
this.input = ref;
|
|
||||||
};
|
|
||||||
|
|
||||||
getScrollViewRef = (ref) => {
|
|
||||||
this.scrollView = ref;
|
|
||||||
};
|
|
||||||
|
|
||||||
goToChannels = wrapWithPreventDoubleTap(() => {
|
|
||||||
const {navigator, theme} = this.props;
|
|
||||||
const {channel, entities, team} = this.state;
|
|
||||||
|
|
||||||
navigator.push({
|
|
||||||
component: ExtensionChannels,
|
|
||||||
wrapperStyle: {
|
|
||||||
borderRadius: 10,
|
|
||||||
backgroundColor: theme.centerChannelBg
|
|
||||||
},
|
|
||||||
passProps: {
|
|
||||||
currentChannelId: channel.id,
|
|
||||||
entities,
|
|
||||||
onSelectChannel: this.selectChannel,
|
|
||||||
teamId: team.id,
|
|
||||||
theme,
|
|
||||||
title: team.display_name
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
goToTeams = wrapWithPreventDoubleTap(() => {
|
|
||||||
const {navigator, theme} = this.props;
|
|
||||||
const {formatMessage} = this.context.intl;
|
|
||||||
const {team} = this.state;
|
|
||||||
|
|
||||||
navigator.push({
|
|
||||||
component: ExtensionTeams,
|
|
||||||
title: formatMessage({id: 'quick_switch_modal.teams', defaultMessage: 'Teams'}),
|
|
||||||
wrapperStyle: {
|
|
||||||
borderRadius: 10,
|
|
||||||
backgroundColor: theme.centerChannelBg
|
|
||||||
},
|
|
||||||
passProps: {
|
|
||||||
entities: this.state.entities,
|
|
||||||
currentTeamId: team.id,
|
|
||||||
onSelectTeam: this.selectTeam,
|
|
||||||
theme
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
handleCancel = wrapWithPreventDoubleTap(() => {
|
|
||||||
this.props.onClose();
|
|
||||||
});
|
|
||||||
|
|
||||||
handleTextChange = (value) => {
|
|
||||||
this.setState({value});
|
|
||||||
};
|
|
||||||
|
|
||||||
loadData = async () => {
|
|
||||||
const {entities} = this.state;
|
|
||||||
if (this.props.authenticated) {
|
|
||||||
try {
|
|
||||||
const {credentials} = entities.general;
|
|
||||||
const {currentUserId} = entities.users;
|
|
||||||
const team = entities.teams.teams[entities.teams.currentTeamId];
|
|
||||||
const channel = entities.channels.channels[entities.channels.currentChannelId];
|
|
||||||
const items = await ShareExtension.data(Config.AppGroupId);
|
|
||||||
const text = [];
|
|
||||||
const urls = [];
|
|
||||||
const files = [];
|
|
||||||
let totalSize = 0;
|
|
||||||
|
|
||||||
for (let i = 0; i < items.length; i++) {
|
|
||||||
const item = items[i];
|
|
||||||
switch (item.type) {
|
|
||||||
case 'public.plain-text':
|
|
||||||
text.push(item.value);
|
|
||||||
break;
|
|
||||||
case 'public.url':
|
|
||||||
urls.push(item.value);
|
|
||||||
break;
|
|
||||||
default: {
|
|
||||||
const fullPath = item.value;
|
|
||||||
const filePath = fullPath.replace('file://', '');
|
|
||||||
const fileSize = await RNFetchBlob.fs.stat(filePath);
|
|
||||||
const filename = fullPath.replace(/^.*[\\/]/, '');
|
|
||||||
const extension = filename.split('.').pop();
|
|
||||||
|
|
||||||
totalSize += fileSize.size;
|
|
||||||
files.push({
|
|
||||||
extension,
|
|
||||||
filename,
|
|
||||||
filePath,
|
|
||||||
fullPath,
|
|
||||||
mimeType: lookupMimeType(filename.toLowerCase()),
|
|
||||||
size: getFormattedFileSize(fileSize),
|
|
||||||
type: item.type
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let value = text.join('\n');
|
|
||||||
if (urls.length) {
|
|
||||||
value += text.length ? `\n${urls.join('\n')}` : urls.join('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
Client4.setUrl(credentials.url);
|
|
||||||
Client4.setToken(credentials.token);
|
|
||||||
Client4.setUserId(currentUserId);
|
|
||||||
this.setState({channel, files, team, value, totalSize});
|
|
||||||
} catch (error) {
|
|
||||||
this.setState({error});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onLayout = async () => {
|
|
||||||
const isLandscape = await ShareExtension.getOrientation() === 'LANDSCAPE';
|
|
||||||
|
|
||||||
if (this.state.isLandscape !== isLandscape) {
|
|
||||||
if (this.scrollView) {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.scrollView.scrollTo({y: 0, animated: false});
|
|
||||||
}, 250);
|
|
||||||
}
|
|
||||||
this.setState({isLandscape});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
renderBody = (styles) => {
|
|
||||||
const {formatMessage} = this.context.intl;
|
|
||||||
const {authenticated, theme} = this.props;
|
|
||||||
const {error, sending, totalSize, value} = this.state;
|
|
||||||
|
|
||||||
if (sending) {
|
|
||||||
return (
|
|
||||||
<View style={styles.sendingContainer}>
|
|
||||||
<ActivityIndicator/>
|
|
||||||
<Text style={styles.sendingText}>
|
|
||||||
{formatMessage({
|
|
||||||
id: 'mobile.extension.posting',
|
|
||||||
defaultMessage: 'Posting...'
|
|
||||||
})}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (totalSize >= MAX_FILE_SIZE) {
|
|
||||||
return (
|
|
||||||
<View style={styles.unauthenticatedContainer}>
|
|
||||||
<Text style={styles.unauthenticated}>
|
|
||||||
{formatMessage({
|
|
||||||
id: 'mobile.extension.max_file_size',
|
|
||||||
defaultMessage: 'File attachments shared in Mattermost must be less than 20 Mb.'
|
|
||||||
})}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (authenticated && !error) {
|
|
||||||
return (
|
|
||||||
<ScrollView
|
|
||||||
ref={this.getScrollViewRef}
|
|
||||||
contentContainerStyle={styles.scrollView}
|
|
||||||
style={styles.flex}
|
|
||||||
>
|
|
||||||
<TextInput
|
|
||||||
ref={this.getInputRef}
|
|
||||||
maxLength={MAX_MESSAGE_LENGTH}
|
|
||||||
multiline={true}
|
|
||||||
onChangeText={this.handleTextChange}
|
|
||||||
placeholder={formatMessage({id: 'create_post.write', defaultMessage: 'Write a message...'})}
|
|
||||||
placeholderTextColor={changeOpacity(theme.centerChannelColor, 0.5)}
|
|
||||||
style={[styles.input, {maxHeight: MAX_INPUT_HEIGHT}]}
|
|
||||||
value={value}
|
|
||||||
/>
|
|
||||||
{this.renderFiles(styles)}
|
|
||||||
</ScrollView>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return (
|
|
||||||
<View style={styles.unauthenticatedContainer}>
|
|
||||||
<Text style={styles.unauthenticated}>
|
|
||||||
{error.message}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={styles.unauthenticatedContainer}>
|
|
||||||
<Text style={styles.unauthenticated}>
|
|
||||||
{formatMessage({
|
|
||||||
id: 'mobile.extension.authentication_required',
|
|
||||||
defaultMessage: 'Authentication required: Please first login using the app.'
|
|
||||||
})}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
renderChannelButton = (styles) => {
|
|
||||||
const {formatMessage} = this.context.intl;
|
|
||||||
const {authenticated, theme} = this.props;
|
|
||||||
const {channel, sending} = this.state;
|
|
||||||
const channelName = channel ? channel.display_name : '';
|
|
||||||
|
|
||||||
if (sending) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!authenticated) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={this.goToChannels}
|
|
||||||
style={styles.buttonContainer}
|
|
||||||
underlayColor={changeOpacity(theme.centerChannelColor, 0.2)}
|
|
||||||
>
|
|
||||||
<View style={styles.buttonWrapper}>
|
|
||||||
<View style={styles.buttonLabelContainer}>
|
|
||||||
<Text style={styles.buttonLabel}>
|
|
||||||
{formatMessage({id: 'mobile.share_extension.channel', defaultMessage: 'Channel'})}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<View style={styles.buttonValueContainer}>
|
|
||||||
<Text
|
|
||||||
ellipsizeMode='tail'
|
|
||||||
numberOfLines={1}
|
|
||||||
style={styles.buttonValue}
|
|
||||||
>
|
|
||||||
{channelName}
|
|
||||||
</Text>
|
|
||||||
<View style={styles.arrowContainer}>
|
|
||||||
<IonIcon
|
|
||||||
color={changeOpacity(theme.centerChannelColor, 0.4)}
|
|
||||||
name='ios-arrow-forward'
|
|
||||||
size={25}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
renderFiles = (styles) => {
|
|
||||||
const {files} = this.state;
|
|
||||||
return files.map((file, index) => {
|
|
||||||
let component;
|
|
||||||
|
|
||||||
switch (file.type) {
|
|
||||||
case 'public.image':
|
|
||||||
component = (
|
|
||||||
<View
|
|
||||||
key={`item-${index}`}
|
|
||||||
style={styles.imageContainer}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
source={{uri: file.fullPath}}
|
|
||||||
resizeMode='cover'
|
|
||||||
style={styles.image}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 'public.movie':
|
|
||||||
component = (
|
|
||||||
<View
|
|
||||||
key={`item-${index}`}
|
|
||||||
style={styles.imageContainer}
|
|
||||||
>
|
|
||||||
<Video
|
|
||||||
style={styles.video}
|
|
||||||
resizeMode='cover'
|
|
||||||
source={{uri: file.fullPath}}
|
|
||||||
volume={0}
|
|
||||||
paused={true}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 'public.file-url': {
|
|
||||||
let SvgIcon = extensionSvg[file.extension];
|
|
||||||
if (!SvgIcon) {
|
|
||||||
SvgIcon = GenericSvg;
|
|
||||||
}
|
|
||||||
|
|
||||||
component = (
|
|
||||||
<View
|
|
||||||
key={`item-${index}`}
|
|
||||||
style={styles.otherContainer}
|
|
||||||
>
|
|
||||||
<View style={styles.otherWrapper}>
|
|
||||||
<View style={styles.fileIcon}>
|
|
||||||
<SvgIcon
|
|
||||||
width={19}
|
|
||||||
height={48}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View
|
|
||||||
style={styles.fileContainer}
|
|
||||||
key={`item-${index}`}
|
|
||||||
>
|
|
||||||
{component}
|
|
||||||
<Text
|
|
||||||
ellipsisMode='tail'
|
|
||||||
numberOfLines={1}
|
|
||||||
style={styles.filename}
|
|
||||||
>
|
|
||||||
{`${file.size} - ${file.filename}`}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
renderTeamButton = (styles) => {
|
|
||||||
const {formatMessage} = this.context.intl;
|
|
||||||
const {authenticated, theme} = this.props;
|
|
||||||
const {sending, team} = this.state;
|
|
||||||
const teamName = team ? team.display_name : '';
|
|
||||||
|
|
||||||
if (sending) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!authenticated) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={this.goToTeams}
|
|
||||||
style={styles.buttonContainer}
|
|
||||||
underlayColor={changeOpacity(theme.centerChannelColor, 0.2)}
|
|
||||||
>
|
|
||||||
<View style={styles.buttonWrapper}>
|
|
||||||
<View style={styles.flex}>
|
|
||||||
<Text style={styles.buttonLabel}>
|
|
||||||
{formatMessage({id: 'mobile.share_extension.team', defaultMessage: 'Team'})}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<View style={styles.buttonValueContainer}>
|
|
||||||
<Text style={styles.buttonValue}>
|
|
||||||
{teamName}
|
|
||||||
</Text>
|
|
||||||
<View style={styles.arrowContainer}>
|
|
||||||
<IonIcon
|
|
||||||
color={changeOpacity(theme.centerChannelColor, 0.4)}
|
|
||||||
name='ios-arrow-forward'
|
|
||||||
size={25}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
selectChannel = (channel) => {
|
|
||||||
this.setState({channel});
|
|
||||||
};
|
|
||||||
|
|
||||||
selectTeam = (team, channel) => {
|
|
||||||
this.setState({channel, team});
|
|
||||||
|
|
||||||
// Update the channels for the team
|
|
||||||
Client4.getMyChannels(team.id).then((channels) => {
|
|
||||||
const defaultChannel = channels.find((c) => c.name === General.DEFAULT_CHANNEL && c.team_id === team.id);
|
|
||||||
this.updateChannelsInEntities(channels);
|
|
||||||
if (!channel) {
|
|
||||||
this.setState({channel: defaultChannel});
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
this.setState({error});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
sendMessage = wrapWithPreventDoubleTap(async () => {
|
|
||||||
const {authenticated, onClose} = this.props;
|
|
||||||
const {channel, entities, files, value} = this.state;
|
|
||||||
const {currentUserId} = entities.users;
|
|
||||||
|
|
||||||
// If no text and no files do nothing
|
|
||||||
if (!value && !files.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentUserId && authenticated) {
|
|
||||||
await this.emmAuthenticationIfNeeded();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Check to see if the use still belongs to the channel
|
|
||||||
await Client4.getMyChannelMember(channel.id);
|
|
||||||
const post = {
|
|
||||||
user_id: currentUserId,
|
|
||||||
channel_id: channel.id,
|
|
||||||
message: value
|
|
||||||
};
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
files,
|
|
||||||
post,
|
|
||||||
requestId: generateId()
|
|
||||||
};
|
|
||||||
|
|
||||||
this.setState({sending: true});
|
|
||||||
onClose(data);
|
|
||||||
} catch (error) {
|
|
||||||
this.setState({error});
|
|
||||||
setTimeout(() => {
|
|
||||||
onClose();
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
updateChannelsInEntities = (newChannels) => {
|
|
||||||
const {entities} = this.state;
|
|
||||||
const newEntities = {
|
|
||||||
...entities,
|
|
||||||
channels: {
|
|
||||||
...entities.channels,
|
|
||||||
channels: {...entities.channels.channels},
|
|
||||||
channelsInTeam: {...entities.channels.channelsInTeam}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const {channels, channelsInTeam} = newEntities.channels;
|
|
||||||
|
|
||||||
newChannels.forEach((c) => {
|
|
||||||
channels[c.id] = c;
|
|
||||||
const channelIdsInTeam = channelsInTeam[c.team_id];
|
|
||||||
if (channelIdsInTeam) {
|
|
||||||
if (!channelIdsInTeam.includes(c.id)) {
|
|
||||||
channelsInTeam[c.team_id].push(c.id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
channelsInTeam[c.team_id] = [c.id];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.setState({entities: newEntities});
|
|
||||||
mattermostBucket.writeToFile('entities', JSON.stringify(newEntities), Config.AppGroupId);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {authenticated, theme} = this.props;
|
|
||||||
const {channel, totalSize, sending} = this.state;
|
|
||||||
const {formatMessage} = this.context.intl;
|
|
||||||
const styles = getStyleSheet(theme);
|
|
||||||
|
|
||||||
let postButtonText = formatMessage({id: 'mobile.share_extension.send', defaultMessage: 'Send'});
|
|
||||||
if (totalSize >= MAX_FILE_SIZE || sending || !channel) {
|
|
||||||
postButtonText = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View
|
|
||||||
onLayout={this.onLayout}
|
|
||||||
style={styles.container}
|
|
||||||
>
|
|
||||||
<ExtensionNavBar
|
|
||||||
authenticated={authenticated}
|
|
||||||
leftButtonTitle={sending ? null : formatMessage({id: 'mobile.share_extension.cancel', defaultMessage: 'Cancel'})}
|
|
||||||
onLeftButtonPress={this.handleCancel}
|
|
||||||
onRightButtonPress={this.sendMessage}
|
|
||||||
rightButtonTitle={postButtonText}
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
{this.renderBody(styles)}
|
|
||||||
{this.renderTeamButton(styles)}
|
|
||||||
{this.renderChannelButton(styles)}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|
||||||
return {
|
|
||||||
flex: {
|
|
||||||
flex: 1
|
|
||||||
},
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.05)
|
|
||||||
},
|
|
||||||
input: {
|
|
||||||
color: theme.centerChannelColor,
|
|
||||||
fontSize: 17,
|
|
||||||
marginBottom: 5,
|
|
||||||
width: '100%'
|
|
||||||
},
|
|
||||||
divider: {
|
|
||||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.1),
|
|
||||||
height: 1,
|
|
||||||
marginVertical: 5,
|
|
||||||
width: '100%'
|
|
||||||
},
|
|
||||||
scrollView: {
|
|
||||||
paddingHorizontal: 15
|
|
||||||
},
|
|
||||||
buttonContainer: {
|
|
||||||
borderTopColor: changeOpacity(theme.centerChannelColor, 0.2),
|
|
||||||
borderTopWidth: 1,
|
|
||||||
height: 45,
|
|
||||||
paddingHorizontal: 15
|
|
||||||
},
|
|
||||||
buttonWrapper: {
|
|
||||||
alignItems: 'center',
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'row'
|
|
||||||
},
|
|
||||||
buttonLabelContainer: {
|
|
||||||
flex: 1
|
|
||||||
},
|
|
||||||
buttonLabel: {
|
|
||||||
fontSize: 17,
|
|
||||||
lineHeight: 45
|
|
||||||
},
|
|
||||||
buttonValueContainer: {
|
|
||||||
justifyContent: 'flex-end',
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'row'
|
|
||||||
},
|
|
||||||
buttonValue: {
|
|
||||||
color: changeOpacity(theme.centerChannelColor, 0.4),
|
|
||||||
alignSelf: 'flex-end',
|
|
||||||
fontSize: 17,
|
|
||||||
lineHeight: 45
|
|
||||||
},
|
|
||||||
arrowContainer: {
|
|
||||||
height: 45,
|
|
||||||
justifyContent: 'center',
|
|
||||||
marginLeft: 15,
|
|
||||||
top: 2
|
|
||||||
},
|
|
||||||
unauthenticatedContainer: {
|
|
||||||
alignItems: 'center',
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: 'center',
|
|
||||||
paddingHorizontal: 15
|
|
||||||
},
|
|
||||||
unauthenticated: {
|
|
||||||
color: theme.errorTextColor,
|
|
||||||
fontSize: 14
|
|
||||||
},
|
|
||||||
fileContainer: {
|
|
||||||
alignItems: 'center',
|
|
||||||
backgroundColor: theme.centerChannelBg,
|
|
||||||
borderColor: changeOpacity(theme.centerChannelColor, 0.2),
|
|
||||||
borderRadius: 4,
|
|
||||||
borderWidth: 1,
|
|
||||||
flexDirection: 'row',
|
|
||||||
height: 48,
|
|
||||||
marginBottom: 10,
|
|
||||||
width: '100%'
|
|
||||||
},
|
|
||||||
filename: {
|
|
||||||
color: changeOpacity(theme.centerChannelColor, 0.5),
|
|
||||||
fontSize: 13,
|
|
||||||
flex: 1
|
|
||||||
},
|
|
||||||
otherContainer: {
|
|
||||||
borderBottomLeftRadius: 4,
|
|
||||||
borderTopLeftRadius: 4,
|
|
||||||
height: 48,
|
|
||||||
marginRight: 10,
|
|
||||||
paddingVertical: 10,
|
|
||||||
width: 38
|
|
||||||
},
|
|
||||||
otherWrapper: {
|
|
||||||
borderRightWidth: 1,
|
|
||||||
borderRightColor: changeOpacity(theme.centerChannelColor, 0.2),
|
|
||||||
flex: 1
|
|
||||||
},
|
|
||||||
fileIcon: {
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
flex: 1
|
|
||||||
},
|
|
||||||
imageContainer: {
|
|
||||||
borderBottomLeftRadius: 4,
|
|
||||||
borderTopLeftRadius: 4,
|
|
||||||
height: 48,
|
|
||||||
marginRight: 10,
|
|
||||||
width: 38
|
|
||||||
},
|
|
||||||
image: {
|
|
||||||
alignItems: 'center',
|
|
||||||
height: 48,
|
|
||||||
justifyContent: 'center',
|
|
||||||
overflow: 'hidden',
|
|
||||||
width: 38
|
|
||||||
},
|
|
||||||
video: {
|
|
||||||
backgroundColor: theme.centerChannelBg,
|
|
||||||
alignItems: 'center',
|
|
||||||
height: 48,
|
|
||||||
justifyContent: 'center',
|
|
||||||
overflow: 'hidden',
|
|
||||||
width: 38
|
|
||||||
},
|
|
||||||
sendingContainer: {
|
|
||||||
alignItems: 'center',
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: 'center',
|
|
||||||
paddingHorizontal: 15
|
|
||||||
},
|
|
||||||
sendingText: {
|
|
||||||
color: theme.centerChannelColor,
|
|
||||||
fontSize: 16,
|
|
||||||
paddingTop: 10
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See License.txt for license information.
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import {
|
|
||||||
Text,
|
|
||||||
TouchableHighlight,
|
|
||||||
View
|
|
||||||
} from 'react-native';
|
|
||||||
import IonIcon from 'react-native-vector-icons/Ionicons';
|
|
||||||
|
|
||||||
import {wrapWithPreventDoubleTap} from 'app/utils/tap';
|
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
|
||||||
|
|
||||||
export default class TeamsListItem extends React.PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
currentTeamId: PropTypes.string.isRequired,
|
|
||||||
onSelectTeam: PropTypes.func.isRequired,
|
|
||||||
team: PropTypes.object.isRequired,
|
|
||||||
theme: PropTypes.object.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
onPress = wrapWithPreventDoubleTap(() => {
|
|
||||||
const {onSelectTeam, team} = this.props;
|
|
||||||
onSelectTeam(team);
|
|
||||||
});
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
currentTeamId,
|
|
||||||
team,
|
|
||||||
theme
|
|
||||||
} = this.props;
|
|
||||||
const styles = getStyleSheet(theme);
|
|
||||||
|
|
||||||
let current;
|
|
||||||
if (team.id === currentTeamId) {
|
|
||||||
current = (
|
|
||||||
<View style={styles.checkmarkContainer}>
|
|
||||||
<IonIcon
|
|
||||||
name='md-checkmark'
|
|
||||||
style={styles.checkmark}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const icon = (
|
|
||||||
<View style={styles.iconContainer}>
|
|
||||||
<Text style={styles.icon}>
|
|
||||||
{team.display_name.substr(0, 2).toUpperCase()}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableHighlight
|
|
||||||
underlayColor={changeOpacity(theme.sidebarTextHoverBg, 0.5)}
|
|
||||||
onPress={this.onPress}
|
|
||||||
>
|
|
||||||
<View style={styles.container}>
|
|
||||||
<View style={styles.item}>
|
|
||||||
{icon}
|
|
||||||
<Text
|
|
||||||
style={[styles.text]}
|
|
||||||
ellipsizeMode='tail'
|
|
||||||
numberOfLines={1}
|
|
||||||
>
|
|
||||||
{team.display_name}
|
|
||||||
</Text>
|
|
||||||
{current}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|
||||||
return {
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'row',
|
|
||||||
height: 45,
|
|
||||||
paddingHorizontal: 15
|
|
||||||
},
|
|
||||||
item: {
|
|
||||||
alignItems: 'center',
|
|
||||||
height: 45,
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'row'
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
color: theme.centerChannelColor,
|
|
||||||
flex: 1,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: '600',
|
|
||||||
lineHeight: 16,
|
|
||||||
paddingRight: 5
|
|
||||||
},
|
|
||||||
iconContainer: {
|
|
||||||
alignItems: 'center',
|
|
||||||
backgroundColor: theme.linkColor,
|
|
||||||
borderRadius: 2,
|
|
||||||
height: 30,
|
|
||||||
justifyContent: 'center',
|
|
||||||
width: 30,
|
|
||||||
marginRight: 10
|
|
||||||
},
|
|
||||||
icon: {
|
|
||||||
color: theme.sidebarText,
|
|
||||||
fontFamily: 'OpenSans',
|
|
||||||
fontSize: 15,
|
|
||||||
fontWeight: '600'
|
|
||||||
},
|
|
||||||
checkmarkContainer: {
|
|
||||||
alignItems: 'flex-end'
|
|
||||||
},
|
|
||||||
checkmark: {
|
|
||||||
color: theme.linkColor,
|
|
||||||
fontSize: 16
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -1,218 +0,0 @@
|
|||||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See License.txt for license information.
|
|
||||||
|
|
||||||
import React, {PureComponent} from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import {ActivityIndicator, FlatList, Text, View} from 'react-native';
|
|
||||||
import DeviceInfo from 'react-native-device-info';
|
|
||||||
import {intlShape} from 'react-intl';
|
|
||||||
|
|
||||||
import {General} from 'mattermost-redux/constants';
|
|
||||||
import {getChannelsInTeam} from 'mattermost-redux/selectors/entities/channels';
|
|
||||||
|
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
|
||||||
|
|
||||||
import ExtensionNavBar from './extension_nav_bar';
|
|
||||||
import ExtensionTeamItem from './extension_team_item';
|
|
||||||
|
|
||||||
export default class ExtensionTeams extends PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
currentTeamId: PropTypes.string.isRequired,
|
|
||||||
entities: PropTypes.object,
|
|
||||||
navigator: PropTypes.object.isRequired,
|
|
||||||
onSelectTeam: PropTypes.func.isRequired,
|
|
||||||
theme: PropTypes.object.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
intl: intlShape
|
|
||||||
};
|
|
||||||
|
|
||||||
state = {
|
|
||||||
defaultChannels: null,
|
|
||||||
error: null,
|
|
||||||
myTeams: null
|
|
||||||
};
|
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
this.loadTeams();
|
|
||||||
}
|
|
||||||
|
|
||||||
goBack = () => {
|
|
||||||
this.props.navigator.pop();
|
|
||||||
};
|
|
||||||
|
|
||||||
handleSelectTeam = (team) => {
|
|
||||||
const {defaultChannels} = this.state;
|
|
||||||
const townSquare = defaultChannels[team.id];
|
|
||||||
this.props.onSelectTeam(team, townSquare);
|
|
||||||
this.goBack();
|
|
||||||
};
|
|
||||||
|
|
||||||
keyExtractor = (item) => item.id;
|
|
||||||
|
|
||||||
loadTeams = async () => {
|
|
||||||
try {
|
|
||||||
const defaultChannels = {};
|
|
||||||
const {teams, myMembers} = this.props.entities.teams;
|
|
||||||
const myTeams = [];
|
|
||||||
const channelsInTeam = getChannelsInTeam({entities: this.props.entities});
|
|
||||||
|
|
||||||
for (const key in teams) {
|
|
||||||
if (teams.hasOwnProperty(key)) {
|
|
||||||
const team = teams[key];
|
|
||||||
const belong = myMembers[key];
|
|
||||||
if (belong) {
|
|
||||||
const channelIds = channelsInTeam[key];
|
|
||||||
let channels;
|
|
||||||
if (channelIds) {
|
|
||||||
channels = channelIds.map((id) => this.props.entities.channels.channels[id]);
|
|
||||||
defaultChannels[team.id] = channels.find((channel) => channel.name === General.DEFAULT_CHANNEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
myTeams.push(team);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
defaultChannels,
|
|
||||||
myTeams: myTeams.sort(this.sortDisplayName)
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
this.setState({error});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
renderBody = (styles) => {
|
|
||||||
const {error, myTeams} = this.state;
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return (
|
|
||||||
<View style={styles.errorContainer}>
|
|
||||||
<Text style={styles.error}>
|
|
||||||
{error.message}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!myTeams) {
|
|
||||||
return (
|
|
||||||
<View style={styles.loadingContainer}>
|
|
||||||
<ActivityIndicator/>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FlatList
|
|
||||||
data={myTeams}
|
|
||||||
ItemSeparatorComponent={this.renderItemSeparator}
|
|
||||||
renderItem={this.renderItem}
|
|
||||||
keyExtractor={this.keyExtractor}
|
|
||||||
keyboardShouldPersistTaps='always'
|
|
||||||
keyboardDismissMode='on-drag'
|
|
||||||
initialNumToRender={10}
|
|
||||||
maxToRenderPerBatch={10}
|
|
||||||
scrollEventThrottle={100}
|
|
||||||
windowSize={5}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
renderItem = ({item}) => {
|
|
||||||
const {currentTeamId, theme} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ExtensionTeamItem
|
|
||||||
currentTeamId={currentTeamId}
|
|
||||||
onSelectTeam={this.handleSelectTeam}
|
|
||||||
team={item}
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
renderItemSeparator = () => {
|
|
||||||
const {theme} = this.props;
|
|
||||||
const styles = getStyleSheet(theme);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={styles.separatorContainer}>
|
|
||||||
<View style={styles.separator}/>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
sortDisplayName = (a, b) => {
|
|
||||||
const locale = DeviceInfo.getDeviceLocale().split('-')[0];
|
|
||||||
return a.display_name.localeCompare(b.display_name, locale, {numeric: true});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {formatMessage} = this.context.intl;
|
|
||||||
const {theme} = this.props;
|
|
||||||
const styles = getStyleSheet(theme);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={styles.flex}>
|
|
||||||
<ExtensionNavBar
|
|
||||||
backButton={true}
|
|
||||||
onLeftButtonPress={this.goBack}
|
|
||||||
title={formatMessage({id: 'mobile.drawer.teamsTitle', defaultMessage: 'Teams'})}
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
{this.renderBody(styles)}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|
||||||
return {
|
|
||||||
flex: {
|
|
||||||
flex: 1
|
|
||||||
},
|
|
||||||
separatorContainer: {
|
|
||||||
paddingLeft: 60
|
|
||||||
},
|
|
||||||
separator: {
|
|
||||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.2),
|
|
||||||
height: 1
|
|
||||||
},
|
|
||||||
loadingContainer: {
|
|
||||||
alignItems: 'center',
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: 'center'
|
|
||||||
},
|
|
||||||
searchContainer: {
|
|
||||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.2),
|
|
||||||
paddingBottom: 2
|
|
||||||
},
|
|
||||||
searchBarInput: {
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
color: theme.centerChannelColor,
|
|
||||||
fontSize: 15
|
|
||||||
},
|
|
||||||
titleContainer: {
|
|
||||||
height: 30
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
color: changeOpacity(theme.centerChannelColor, 0.6),
|
|
||||||
fontSize: 15,
|
|
||||||
lineHeight: 30,
|
|
||||||
paddingHorizontal: 15
|
|
||||||
},
|
|
||||||
errorContainer: {
|
|
||||||
alignItems: 'center',
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: 'center',
|
|
||||||
paddingHorizontal: 15
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
color: theme.errorTextColor,
|
|
||||||
fontSize: 14
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See License.txt for license information.
|
|
||||||
|
|
||||||
import React, {PureComponent} from 'react';
|
|
||||||
import {IntlProvider} from 'react-intl';
|
|
||||||
import DeviceInfo from 'react-native-device-info';
|
|
||||||
import {
|
|
||||||
Animated,
|
|
||||||
Dimensions,
|
|
||||||
NativeModules,
|
|
||||||
NavigatorIOS,
|
|
||||||
StyleSheet,
|
|
||||||
View
|
|
||||||
} from 'react-native';
|
|
||||||
|
|
||||||
import {Preferences} from 'mattermost-redux/constants';
|
|
||||||
|
|
||||||
import {getTranslations} from 'app/i18n';
|
|
||||||
import mattermostBucket from 'app/mattermost_bucket';
|
|
||||||
import Config from 'assets/config';
|
|
||||||
|
|
||||||
import ExtensionPost from './extension_post';
|
|
||||||
|
|
||||||
const {View: AnimatedView} = Animated;
|
|
||||||
const ShareExtension = NativeModules.MattermostShare;
|
|
||||||
|
|
||||||
export default class SharedApp extends PureComponent {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
const {height, width} = Dimensions.get('window');
|
|
||||||
const isLandscape = width > height;
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
backdropOpacity: new Animated.Value(0),
|
|
||||||
containerOpacity: new Animated.Value(0),
|
|
||||||
isLandscape
|
|
||||||
};
|
|
||||||
|
|
||||||
mattermostBucket.readFromFile('entities', Config.AppGroupId).then((value) => {
|
|
||||||
this.entities = value;
|
|
||||||
this.setState({init: true});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
Animated.parallel([
|
|
||||||
Animated.timing(
|
|
||||||
this.state.backdropOpacity,
|
|
||||||
{
|
|
||||||
toValue: 0.5,
|
|
||||||
duration: 100
|
|
||||||
}),
|
|
||||||
Animated.timing(
|
|
||||||
this.state.containerOpacity,
|
|
||||||
{
|
|
||||||
toValue: 1,
|
|
||||||
duration: 250
|
|
||||||
})
|
|
||||||
]).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
onClose = (data) => {
|
|
||||||
ShareExtension.close(data, Config.AppGroupId);
|
|
||||||
};
|
|
||||||
|
|
||||||
onLayout = (e) => {
|
|
||||||
const {height, width} = e.nativeEvent.layout;
|
|
||||||
const isLandscape = width > height;
|
|
||||||
if (this.state.isLandscape !== isLandscape) {
|
|
||||||
this.setState({isLandscape});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
userIsLoggedIn = () => {
|
|
||||||
return Boolean(this.entities && this.entities.general && this.entities.general.credentials &&
|
|
||||||
this.entities.general.credentials.token && this.entities.general.credentials.url);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {init, isLandscape} = this.state;
|
|
||||||
|
|
||||||
if (!init) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const theme = Preferences.THEMES.default;
|
|
||||||
const locale = DeviceInfo.getDeviceLocale().split('-')[0];
|
|
||||||
|
|
||||||
const initialRoute = {
|
|
||||||
component: ExtensionPost,
|
|
||||||
title: 'Mattermost',
|
|
||||||
passProps: {
|
|
||||||
authenticated: this.userIsLoggedIn(),
|
|
||||||
entities: this.entities,
|
|
||||||
onClose: this.onClose,
|
|
||||||
isLandscape,
|
|
||||||
theme
|
|
||||||
},
|
|
||||||
wrapperStyle: {
|
|
||||||
borderRadius: 10,
|
|
||||||
backgroundColor: theme.centerChannelBg
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IntlProvider
|
|
||||||
locale={locale}
|
|
||||||
messages={getTranslations(locale)}
|
|
||||||
>
|
|
||||||
<View
|
|
||||||
style={styles.flex}
|
|
||||||
onLayout={this.onLayout}
|
|
||||||
>
|
|
||||||
<AnimatedView style={[styles.backdrop, {opacity: this.state.backdropOpacity}]}/>
|
|
||||||
<View style={styles.wrapper}>
|
|
||||||
<AnimatedView
|
|
||||||
style={[
|
|
||||||
styles.container,
|
|
||||||
{
|
|
||||||
opacity: this.state.containerOpacity,
|
|
||||||
height: this.userIsLoggedIn() ? 250 : 130,
|
|
||||||
top: isLandscape ? 20 : 65
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<NavigatorIOS
|
|
||||||
initialRoute={initialRoute}
|
|
||||||
style={styles.flex}
|
|
||||||
navigationBarHidden={true}
|
|
||||||
/>
|
|
||||||
</AnimatedView>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</IntlProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
flex: {
|
|
||||||
flex: 1
|
|
||||||
},
|
|
||||||
backdrop: {
|
|
||||||
position: 'absolute',
|
|
||||||
flex: 1,
|
|
||||||
backgroundColor: '#000',
|
|
||||||
height: '100%',
|
|
||||||
width: '100%'
|
|
||||||
},
|
|
||||||
wrapper: {
|
|
||||||
flex: 1,
|
|
||||||
marginHorizontal: 20
|
|
||||||
},
|
|
||||||
container: {
|
|
||||||
backgroundColor: 'white',
|
|
||||||
borderRadius: 10,
|
|
||||||
position: 'relative',
|
|
||||||
width: '100%'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user