Switch to react-navigation (#687)
23
README.md
|
@ -227,25 +227,4 @@ $ detox build
|
|||
|
||||
```bash
|
||||
$ detox test
|
||||
```
|
||||
|
||||
## Storybook
|
||||
- General requirements
|
||||
- Install storybook
|
||||
```bash
|
||||
$ yarn global add @storybook/cli
|
||||
```
|
||||
|
||||
- Running storybook
|
||||
- Run storybook application
|
||||
```bash
|
||||
$ yarn storybook
|
||||
```
|
||||
- Run application in other shell
|
||||
```bash
|
||||
$ react-native run-ios
|
||||
```
|
||||
- Running storybook on browser to help stories navigation
|
||||
```
|
||||
open http://localhost:7007/
|
||||
```
|
||||
```
|
|
@ -0,0 +1,3 @@
|
|||
export default {
|
||||
hide: () => ''
|
||||
};
|
|
@ -73,7 +73,7 @@ import com.android.build.OutputFile
|
|||
*/
|
||||
|
||||
project.ext.react = [
|
||||
entryFile: "index.android.js",
|
||||
entryFile: "index.js",
|
||||
iconFontNames: [ 'custom.ttf' ]
|
||||
]
|
||||
|
||||
|
@ -107,14 +107,7 @@ android {
|
|||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
missingDimensionStrategy "RNN.reactNativeVersion", "reactNative57_5"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
multiDexEnabled true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
|
@ -192,6 +185,9 @@ configurations.all {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':react-native-orientation-locker')
|
||||
implementation project(':react-native-splash-screen')
|
||||
implementation project(':react-native-screens')
|
||||
implementation project(':react-native-action-sheet')
|
||||
implementation project(':react-native-device-info')
|
||||
implementation project(':react-native-gesture-handler')
|
||||
|
@ -206,7 +202,6 @@ dependencies {
|
|||
implementation project(':@remobile/react-native-toast')
|
||||
implementation project(':react-native-fast-image')
|
||||
implementation project(':realm')
|
||||
implementation project(':react-native-navigation')
|
||||
implementation project(':reactnativenotifications')
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation "com.android.support:appcompat-v7:27.1.1"
|
||||
|
@ -230,4 +225,3 @@ task copyDownloadableDepsToLibs(type: Copy) {
|
|||
from configurations.compile
|
||||
into 'libs'
|
||||
}
|
||||
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
|
||||
|
|
|
@ -1,40 +1,47 @@
|
|||
package chat.rocket.reactnative;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.widget.LinearLayout;
|
||||
// import com.reactnativenavigation.controllers.SplashActivity;
|
||||
import com.reactnativenavigation.NavigationActivity;
|
||||
import android.view.View;
|
||||
import android.content.Intent;
|
||||
import com.facebook.react.ReactActivityDelegate;
|
||||
import com.facebook.react.ReactRootView;
|
||||
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.facebook.react.ReactFragmentActivity;
|
||||
import org.devio.rn.splashscreen.SplashScreen;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
|
||||
public class MainActivity extends NavigationActivity {
|
||||
public class MainActivity extends ReactFragmentActivity {
|
||||
|
||||
@Override
|
||||
public void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
setIntent(intent);
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
SplashScreen.show(this);
|
||||
super.onCreate(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
/**
|
||||
* Returns the name of the main component registered from JavaScript.
|
||||
* This is used to schedule rendering of the component.
|
||||
*/
|
||||
@Override
|
||||
protected String getMainComponentName() {
|
||||
return "RocketChatRN";
|
||||
}
|
||||
|
||||
View view = new View(this);
|
||||
view.setBackgroundResource(R.drawable.launch_screen_bitmap);
|
||||
setContentView(view);
|
||||
@Override
|
||||
protected ReactActivityDelegate createReactActivityDelegate() {
|
||||
return new ReactActivityDelegate(this, getMainComponentName()) {
|
||||
@Override
|
||||
protected ReactRootView createRootView() {
|
||||
return new RNGestureHandlerEnabledRootView(MainActivity.this);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
Intent intent = new Intent("onConfigurationChanged");
|
||||
intent.putExtra("newConfig", newConfig);
|
||||
this.sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
|
||||
// public class MainActivity extends SplashActivity {
|
||||
// @Override
|
||||
// public LinearLayout createSplashLayout() {
|
||||
// LinearLayout splash = new LinearLayout(this);
|
||||
// Drawable launch_screen_bitmap = ContextCompat.getDrawable(getApplicationContext(),R.drawable.launch_screen_bitmap);
|
||||
// splash.setBackground(launch_screen_bitmap);
|
||||
|
||||
// return splash;
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
package chat.rocket.reactnative;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.app.Application;
|
||||
|
||||
import com.facebook.react.ReactApplication;
|
||||
import org.wonday.orientation.OrientationPackage;
|
||||
import org.devio.rn.splashscreen.SplashScreenReactPackage;
|
||||
import com.facebook.react.ReactNativeHost;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.shell.MainReactPackage;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
import com.AlexanderZaytsev.RNI18n.RNI18nPackage;
|
||||
import com.reactnative.ivpusic.imagepicker.PickerPackage;
|
||||
|
@ -9,16 +16,10 @@ import com.RNFetchBlob.RNFetchBlobPackage;
|
|||
import com.brentvatne.react.ReactVideoPackage;
|
||||
import com.crashlytics.android.Crashlytics;
|
||||
import com.dylanvann.fastimage.FastImageViewPackage;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.shell.MainReactPackage;
|
||||
import com.oblador.vectoricons.VectorIconsPackage;
|
||||
import com.reactnativenavigation.NavigationApplication;
|
||||
import com.facebook.react.ReactNativeHost;
|
||||
import com.remobile.toast.RCTToastPackage;
|
||||
import com.rnim.rn.audio.ReactNativeAudioPackage;
|
||||
import com.smixx.fabric.FabricPackage;
|
||||
import com.reactnativenavigation.react.NavigationReactNativeHost;
|
||||
import com.reactnativenavigation.react.ReactGateway;
|
||||
import com.wix.reactnativekeyboardinput.KeyboardInputPackage;
|
||||
import com.wix.reactnativenotifications.RNNotificationsPackage;
|
||||
import com.wix.reactnativenotifications.core.AppLaunchHelper;
|
||||
|
@ -29,82 +30,76 @@ import com.wix.reactnativenotifications.core.notification.IPushNotification;
|
|||
import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;
|
||||
import com.learnium.RNDeviceInfo.RNDeviceInfo;
|
||||
import com.actionsheet.ActionSheetPackage;
|
||||
import io.fabric.sdk.android.Fabric;
|
||||
import io.realm.react.RealmReactPackage;
|
||||
import com.swmansion.rnscreens.RNScreensPackage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import io.fabric.sdk.android.Fabric;
|
||||
import io.realm.react.RealmReactPackage;
|
||||
public class MainApplication extends Application implements ReactApplication, INotificationsApplication {
|
||||
|
||||
public class MainApplication extends NavigationApplication implements INotificationsApplication {
|
||||
|
||||
// private NotificationsLifecycleFacade notificationsLifecycleFacade;
|
||||
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
|
||||
@Override
|
||||
public boolean getUseDeveloperSupport() {
|
||||
return BuildConfig.DEBUG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebug() {
|
||||
return BuildConfig.DEBUG;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public String getJSMainModuleName() {
|
||||
// return "index.android";
|
||||
// }
|
||||
|
||||
protected ReactGateway createReactGateway() {
|
||||
ReactNativeHost host = new NavigationReactNativeHost(this, isDebug(), createAdditionalReactPackages()) {
|
||||
@Override
|
||||
protected String getJSMainModuleName() {
|
||||
return "index.android";
|
||||
}
|
||||
};
|
||||
return new ReactGateway(this, isDebug(), host);
|
||||
}
|
||||
|
||||
|
||||
protected List<ReactPackage> getPackages() {
|
||||
// Add additional packages you require here
|
||||
// No need to add RnnPackage and MainReactPackage
|
||||
return Arrays.<ReactPackage>asList(
|
||||
);
|
||||
return Arrays.<ReactPackage>asList(
|
||||
new MainReactPackage(),
|
||||
new OrientationPackage(),
|
||||
new SplashScreenReactPackage(),
|
||||
new RNGestureHandlerPackage(),
|
||||
new RNScreensPackage(),
|
||||
new ActionSheetPackage(),
|
||||
new RNDeviceInfo(),
|
||||
new PickerPackage(),
|
||||
new VectorIconsPackage(),
|
||||
new RNFetchBlobPackage(),
|
||||
new RealmReactPackage(),
|
||||
new ReactVideoPackage(),
|
||||
new RCTToastPackage(),
|
||||
new ReactNativeAudioPackage(),
|
||||
new KeyboardInputPackage(MainApplication.this),
|
||||
new RocketChatNativePackage(),
|
||||
new FabricPackage(),
|
||||
new FastImageViewPackage(),
|
||||
new RNI18nPackage(),
|
||||
new RNNotificationsPackage(MainApplication.this)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ReactPackage> createAdditionalReactPackages() {
|
||||
return Arrays.<ReactPackage>asList(
|
||||
new MainReactPackage(),
|
||||
new ActionSheetPackage(),
|
||||
new RNDeviceInfo(),
|
||||
new RNGestureHandlerPackage(),
|
||||
new PickerPackage(),
|
||||
new VectorIconsPackage(),
|
||||
new RNFetchBlobPackage(),
|
||||
new RealmReactPackage(),
|
||||
new ReactVideoPackage(),
|
||||
new RCTToastPackage(),
|
||||
new ReactNativeAudioPackage(),
|
||||
new KeyboardInputPackage(MainApplication.this),
|
||||
new RocketChatNativePackage(),
|
||||
new FabricPackage(),
|
||||
new FastImageViewPackage(),
|
||||
new RNI18nPackage(),
|
||||
new RNNotificationsPackage(MainApplication.this)
|
||||
);
|
||||
protected String getJSMainModuleName() {
|
||||
return "index";
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Fabric.with(this, new Crashlytics());
|
||||
}
|
||||
@Override
|
||||
public ReactNativeHost getReactNativeHost() {
|
||||
return mReactNativeHost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPushNotification getPushNotification(Context context, Bundle bundle, AppLifecycleFacade defaultFacade, AppLaunchHelper defaultAppLaunchHelper) {
|
||||
return new CustomPushNotification(
|
||||
context,
|
||||
bundle,
|
||||
defaultFacade,
|
||||
defaultAppLaunchHelper,
|
||||
new JsIOHelper()
|
||||
);
|
||||
}
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Fabric.with(this, new Crashlytics());
|
||||
SoLoader.init(this, /* native exopackage */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPushNotification getPushNotification(Context context, Bundle bundle, AppLifecycleFacade defaultFacade, AppLaunchHelper defaultAppLaunchHelper) {
|
||||
return new CustomPushNotification(
|
||||
context,
|
||||
bundle,
|
||||
defaultFacade,
|
||||
defaultAppLaunchHelper,
|
||||
new JsIOHelper()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/launch_screen" android:scaleType="centerCrop" />
|
||||
</RelativeLayout>
|
|
@ -46,12 +46,6 @@ subprojects { subproject ->
|
|||
defaultConfig {
|
||||
targetSdkVersion 28
|
||||
}
|
||||
variantFilter { variant ->
|
||||
def names = variant.flavors*.name
|
||||
if (names.contains("reactNative51") || names.contains("reactNative55") || names.contains("reactNative56") || names.contains("reactNative57") || names.contains("reactNative57WixFork")) {
|
||||
setIgnore(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,6 @@
|
|||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
# android.enableAapt2=false
|
||||
android.enableAapt2=false # commenting this makes notifications to stop working
|
||||
android.useDeprecatedNdk=true
|
||||
VERSIONCODE=999999999
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
rootProject.name = 'RocketChatRN'
|
||||
include ':react-native-orientation-locker'
|
||||
project(':react-native-orientation-locker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-orientation-locker/android')
|
||||
include ':react-native-splash-screen'
|
||||
project(':react-native-splash-screen').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-splash-screen/android')
|
||||
include ':react-native-screens'
|
||||
project(':react-native-screens').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-screens/android')
|
||||
include ':react-native-action-sheet'
|
||||
project(':react-native-action-sheet').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-action-sheet/android')
|
||||
include ':react-native-device-info'
|
||||
|
@ -27,8 +33,6 @@ include ':react-native-vector-icons'
|
|||
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
|
||||
include ':realm'
|
||||
project(':realm').projectDir = new File(rootProject.projectDir, '../node_modules/realm/android')
|
||||
include ':react-native-navigation'
|
||||
project(':react-native-navigation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-navigation/lib/android/app/')
|
||||
include ':reactnativenotifications'
|
||||
project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/android')
|
||||
include ':app'
|
||||
|
|
|
@ -38,7 +38,7 @@ export const ROOM = createRequestTypes('ROOM', [
|
|||
'MESSAGE_RECEIVED',
|
||||
'SET_LAST_OPEN'
|
||||
]);
|
||||
export const APP = createRequestTypes('APP', ['START', 'READY', 'INIT', 'SET_STACK_ROOT']);
|
||||
export const APP = createRequestTypes('APP', ['START', 'READY', 'INIT']);
|
||||
export const MESSAGES = createRequestTypes('MESSAGES', [
|
||||
...defaultTypes,
|
||||
'ACTIONS_SHOW',
|
||||
|
|
|
@ -20,13 +20,6 @@ export function appInit() {
|
|||
};
|
||||
}
|
||||
|
||||
export function setStackRoot(stackRoot) {
|
||||
return {
|
||||
type: APP.SET_STACK_ROOT,
|
||||
stackRoot
|
||||
};
|
||||
}
|
||||
|
||||
export function setCurrentServer(server) {
|
||||
return {
|
||||
type: types.SET_CURRENT_SERVER,
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
import * as types from './actionsTypes';
|
||||
|
||||
export function openSnippetedMessages(rid, limit) {
|
||||
return {
|
||||
type: types.SNIPPETED_MESSAGES.OPEN,
|
||||
rid,
|
||||
limit
|
||||
};
|
||||
}
|
||||
|
||||
export function readySnippetedMessages() {
|
||||
return {
|
||||
type: types.SNIPPETED_MESSAGES.READY
|
||||
};
|
||||
}
|
||||
|
||||
export function closeSnippetedMessages() {
|
||||
return {
|
||||
type: types.SNIPPETED_MESSAGES.CLOSE
|
||||
};
|
||||
}
|
||||
|
||||
export function snippetedMessagesReceived(messages) {
|
||||
return {
|
||||
type: types.SNIPPETED_MESSAGES.MESSAGES_RECEIVED,
|
||||
messages
|
||||
};
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
import { isIOS } from '../utils/deviceInfo';
|
||||
|
||||
export const COLOR_DANGER = '#f5455c';
|
||||
export const COLOR_BUTTON_PRIMARY = '#1d74f5';
|
||||
export const COLOR_TEXT = '#292E35';
|
||||
|
@ -8,3 +10,7 @@ export const STATUS_COLORS = {
|
|||
away: '#ffd21f',
|
||||
offline: '#cbced1'
|
||||
};
|
||||
|
||||
export const HEADER_BACKGROUND = isIOS ? '#FFF' : '#2F343D';
|
||||
export const HEADER_TITLE = isIOS ? '#0C0D0F' : '#FFF';
|
||||
export const HEADER_BACK = isIOS ? '#1d74f5' : '#FFF';
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
import { Platform } from 'react-native';
|
||||
|
||||
export const DARK_HEADER = {
|
||||
statusBar: {
|
||||
backgroundColor: '#2F343D',
|
||||
style: 'light'
|
||||
},
|
||||
topBar: {
|
||||
backButton: {
|
||||
showTitle: false,
|
||||
color: '#fff'
|
||||
},
|
||||
background: {
|
||||
color: '#2F343D'
|
||||
},
|
||||
title: {
|
||||
color: '#FFF'
|
||||
},
|
||||
leftButtonStyle: {
|
||||
color: '#FFF'
|
||||
},
|
||||
rightButtonStyle: {
|
||||
color: '#FFF'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const LIGHT_HEADER = {
|
||||
statusBar: {
|
||||
backgroundColor: '#FFF',
|
||||
style: 'dark'
|
||||
},
|
||||
topBar: {
|
||||
backButton: {
|
||||
showTitle: false,
|
||||
color: '#1d74f5'
|
||||
},
|
||||
background: {
|
||||
color: undefined
|
||||
},
|
||||
title: {
|
||||
color: '#0C0D0F'
|
||||
},
|
||||
leftButtonStyle: {
|
||||
color: '#1d74f5'
|
||||
},
|
||||
rightButtonStyle: {
|
||||
color: '#1d74f5'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const DEFAULT_HEADER = {
|
||||
...Platform.select({
|
||||
ios: {
|
||||
...LIGHT_HEADER
|
||||
},
|
||||
android: {
|
||||
...DARK_HEADER
|
||||
}
|
||||
})
|
||||
};
|
|
@ -0,0 +1,63 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Text } from 'react-native';
|
||||
import HeaderButtons, { HeaderButton, Item } from 'react-navigation-header-buttons';
|
||||
|
||||
import { CustomIcon } from '../lib/Icons';
|
||||
import { isIOS } from '../utils/deviceInfo';
|
||||
|
||||
const color = isIOS ? '#1D74F5' : '#FFF';
|
||||
|
||||
const CustomHeaderButton = React.memo(props => (
|
||||
<HeaderButton {...props} IconComponent={CustomIcon} iconSize={23} color={color} />
|
||||
));
|
||||
|
||||
export const CustomHeaderButtons = React.memo(props => (
|
||||
<HeaderButtons
|
||||
HeaderButtonComponent={CustomHeaderButton}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
||||
export const DrawerButton = React.memo(({ navigation, testID }) => (
|
||||
<CustomHeaderButtons left>
|
||||
<Item title='drawer' iconName='customize' onPress={navigation.toggleDrawer} testID={testID} />
|
||||
</CustomHeaderButtons>
|
||||
));
|
||||
|
||||
export const CloseModalButton = React.memo(({ navigation, testID }) => (
|
||||
<CustomHeaderButtons left>
|
||||
<Item title='close' iconName='cross' onPress={() => navigation.pop()} testID={testID} />
|
||||
</CustomHeaderButtons>
|
||||
));
|
||||
|
||||
export const MoreButton = React.memo(({ onPress, testID }) => (
|
||||
<CustomHeaderButtons>
|
||||
<Item title='more' iconName='menu' onPress={onPress} testID={testID} />
|
||||
</CustomHeaderButtons>
|
||||
));
|
||||
|
||||
export const LegalButton = React.memo(({ navigation, testID }) => (
|
||||
<MoreButton onPress={() => navigation.navigate('LegalView')} testID={testID} />
|
||||
));
|
||||
|
||||
DrawerButton.propTypes = {
|
||||
navigation: PropTypes.object.isRequired,
|
||||
testID: PropTypes.string.isRequired
|
||||
};
|
||||
CloseModalButton.propTypes = {
|
||||
navigation: PropTypes.object.isRequired,
|
||||
testID: PropTypes.string.isRequired
|
||||
};
|
||||
MoreButton.propTypes = {
|
||||
onPress: PropTypes.func.isRequired,
|
||||
testID: PropTypes.string.isRequired
|
||||
};
|
||||
LegalButton.propTypes = {
|
||||
navigation: PropTypes.object.isRequired,
|
||||
testID: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export { Item };
|
||||
|
||||
export default () => <Text>a</Text>;
|
|
@ -6,7 +6,7 @@ const styles = StyleSheet.create({
|
|||
style: {
|
||||
marginRight: 7,
|
||||
marginTop: 3,
|
||||
color: '#9EA2A8'
|
||||
tintColor: '#9EA2A8'
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import React from 'react';
|
||||
import { StatusBar as StatusBarRN } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { isIOS } from '../utils/deviceInfo';
|
||||
import { HEADER_BACKGROUND } from '../constants/colors';
|
||||
|
||||
const HEADER_BAR_STYLE = isIOS ? 'dark-content' : 'light-content';
|
||||
|
||||
const StatusBar = React.memo(({ light }) => {
|
||||
if (light) {
|
||||
return <StatusBarRN backgroundColor='#FFF' barStyle='dark-content' animated />;
|
||||
}
|
||||
return <StatusBarRN backgroundColor={HEADER_BACKGROUND} barStyle={HEADER_BAR_STYLE} animated />;
|
||||
});
|
||||
|
||||
StatusBar.propTypes = {
|
||||
light: PropTypes.bool
|
||||
};
|
||||
|
||||
StatusBar.defaultProps = {
|
||||
light: false
|
||||
};
|
||||
|
||||
export default StatusBar;
|
|
@ -214,7 +214,6 @@ export default {
|
|||
No_mentioned_messages: 'Keine erwähnten Nachrichten',
|
||||
No_pinned_messages: 'Keine angehefteten Nachrichten',
|
||||
No_results_found: 'keine Ergebnisse gefunden',
|
||||
No_snippeted_messages: 'Keine Nachrichten-Snippets',
|
||||
No_starred_messages: 'Keine markierten Nachrichten',
|
||||
No_announcement_provided: 'Keine Ankündigung erfolgt.',
|
||||
No_description_provided: 'Keine Beschreibung angegeben.',
|
||||
|
@ -292,9 +291,6 @@ export default {
|
|||
Share: 'Teilen',
|
||||
Sign_in_your_server: 'Melden Sie sich bei Ihrem Server an',
|
||||
Sign_Up: 'Anmelden',
|
||||
Snippet_Messages: 'Snippet-Nachrichten',
|
||||
snippeted: 'snippeted',
|
||||
Snippets: 'Snippets',
|
||||
Some_field_is_invalid_or_empty: 'Ein Feld ist ungültig oder leer',
|
||||
Sorting_by: 'Sortierung nach {{key}}',
|
||||
Star_room: 'Favorisierter Raum',
|
||||
|
|
|
@ -214,7 +214,6 @@ export default {
|
|||
No_mentioned_messages: 'No mentioned messages',
|
||||
No_pinned_messages: 'No pinned messages',
|
||||
No_results_found: 'No results found',
|
||||
No_snippeted_messages: 'No snippeted messages',
|
||||
No_starred_messages: 'No starred messages',
|
||||
No_announcement_provided: 'No announcement provided.',
|
||||
No_description_provided: 'No description provided.',
|
||||
|
@ -292,9 +291,6 @@ export default {
|
|||
Share: 'Share',
|
||||
Sign_in_your_server: 'Sign in your server',
|
||||
Sign_Up: 'Sign Up',
|
||||
Snippet_Messages: 'Snippet Messages',
|
||||
snippeted: 'snippeted',
|
||||
Snippets: 'Snippets',
|
||||
Some_field_is_invalid_or_empty: 'Some field is invalid or empty',
|
||||
Sorting_by: 'Sorting by {{key}}',
|
||||
Star_room: 'Star room',
|
||||
|
|
|
@ -214,7 +214,6 @@ export default {
|
|||
No_mentioned_messages: 'Aucun message mentionné',
|
||||
No_pinned_messages: 'Aucun message épinglé',
|
||||
No_results_found: 'Aucun résultat trouvé',
|
||||
No_snippeted_messages: 'Aucun message extrait',
|
||||
No_starred_messages: 'Pas de messages suivis',
|
||||
No_announcement_provided: 'Aucune annonce fournie.',
|
||||
No_description_provided: 'Aucune description fournie.',
|
||||
|
@ -292,9 +291,6 @@ export default {
|
|||
Share: 'Partager',
|
||||
Sign_in_your_server: 'Connectez-vous à votre serveur',
|
||||
Sign_Up: 'S\'inscrire',
|
||||
Snippet_Messages: 'Messages Extraits',
|
||||
snippeted: 'extrait',
|
||||
Snippets: 'Extraits',
|
||||
Some_field_is_invalid_or_empty: 'Certains champs sont invalides ou vides',
|
||||
Sorting_by: 'Tri par {{key}}',
|
||||
Star_room: 'Favoriser canal',
|
||||
|
|
|
@ -217,7 +217,6 @@ export default {
|
|||
No_mentioned_messages: 'Não há menções',
|
||||
No_pinned_messages: 'Não há mensagens fixadas',
|
||||
No_results_found: 'Nenhum resultado encontrado',
|
||||
No_snippeted_messages: 'Não há trechos de mensagens',
|
||||
No_starred_messages: 'Não há mensagens favoritas',
|
||||
No_announcement_provided: 'Sem anúncio.',
|
||||
No_description_provided: 'Sem descrição.',
|
||||
|
@ -293,9 +292,6 @@ export default {
|
|||
Share: 'Compartilhar',
|
||||
Sign_in_your_server: 'Entrar no seu servidor',
|
||||
Sign_Up: 'Registrar',
|
||||
Snippet_Messages: 'Trecho de Mensagens',
|
||||
snippeted: 'trecho de mensagem',
|
||||
Snippets: 'Trecho de mensagem',
|
||||
Some_field_is_invalid_or_empty: 'Algum campo está inválido ou vazio',
|
||||
Sorting_by: 'Ordenando por {{key}}',
|
||||
Star_room: 'Favoritar sala',
|
||||
|
|
|
@ -183,7 +183,6 @@ export default {
|
|||
No_files: 'Нет файлов',
|
||||
No_mentioned_messages: 'Нет упоминаний',
|
||||
No_pinned_messages: 'Нет прикрепленных сообщений',
|
||||
No_snippeted_messages: 'Нет сообщений со сниппетом',
|
||||
No_starred_messages: 'Нет отмеченных сообщений',
|
||||
No_announcement_provided: 'Нет объявлений.',
|
||||
No_description_provided: 'Нет описания.',
|
||||
|
@ -255,9 +254,6 @@ export default {
|
|||
Share: 'Поделиться',
|
||||
Sign_in_your_server: 'Войдите на ваш сервер',
|
||||
Sign_Up: 'Регистрация',
|
||||
Snippet_Messages: 'Сообщения со сниппетом',
|
||||
snippeted: 'сниппет добавлен',
|
||||
Snippets: 'Сниппеты',
|
||||
Some_field_is_invalid_or_empty: 'Некоторые поля недопустимы или пусты',
|
||||
Star_room: 'Star room',
|
||||
Star: 'Звезда',
|
||||
|
|
|
@ -287,9 +287,6 @@ export default {
|
|||
Share: '分享',
|
||||
Sign_in_your_server: '登录你的服务器',
|
||||
Sign_Up: '注册',
|
||||
Snippet_Messages: '代码片段消息',
|
||||
snippeted: '代码片段',
|
||||
Snippets: '代码片段',
|
||||
Some_field_is_invalid_or_empty: '某些字段无效或为空',
|
||||
Sorting_by: '按{{key}}排序',
|
||||
Star_room: '将房间标星',
|
||||
|
|
283
app/index.js
|
@ -1,78 +1,49 @@
|
|||
import { Component } from 'react';
|
||||
import React from 'react';
|
||||
import {
|
||||
createStackNavigator, createAppContainer, createSwitchNavigator, createDrawerNavigator
|
||||
} from 'react-navigation';
|
||||
import { Provider } from 'react-redux';
|
||||
import { useScreens } from 'react-native-screens'; // eslint-disable-line import/no-unresolved
|
||||
import { Linking } from 'react-native';
|
||||
|
||||
import { appInit } from './actions';
|
||||
import { deepLinkingOpen } from './actions/deepLinking';
|
||||
import store from './lib/createStore';
|
||||
import Icons from './lib/Icons';
|
||||
import OnboardingView from './views/OnboardingView';
|
||||
import NewServerView from './views/NewServerView';
|
||||
import LoginSignupView from './views/LoginSignupView';
|
||||
import AuthLoadingView from './views/AuthLoadingView';
|
||||
import RoomsListView from './views/RoomsListView';
|
||||
import RoomView from './views/RoomView';
|
||||
import NewMessageView from './views/NewMessageView';
|
||||
import LoginView from './views/LoginView';
|
||||
import Navigation from './lib/Navigation';
|
||||
import Sidebar from './views/SidebarView';
|
||||
import ProfileView from './views/ProfileView';
|
||||
import SettingsView from './views/SettingsView';
|
||||
import RoomActionsView from './views/RoomActionsView';
|
||||
import RoomInfoView from './views/RoomInfoView';
|
||||
import RoomInfoEditView from './views/RoomInfoEditView';
|
||||
import RoomMembersView from './views/RoomMembersView';
|
||||
import RoomFilesView from './views/RoomFilesView';
|
||||
import MentionedMessagesView from './views/MentionedMessagesView';
|
||||
import StarredMessagesView from './views/StarredMessagesView';
|
||||
import SearchMessagesView from './views/SearchMessagesView';
|
||||
import PinnedMessagesView from './views/PinnedMessagesView';
|
||||
import SelectedUsersView from './views/SelectedUsersView';
|
||||
import CreateChannelView from './views/CreateChannelView';
|
||||
import LegalView from './views/LegalView';
|
||||
import TermsServiceView from './views/TermsServiceView';
|
||||
import PrivacyPolicyView from './views/PrivacyPolicyView';
|
||||
import ForgotPasswordView from './views/ForgotPasswordView';
|
||||
import RegisterView from './views/RegisterView';
|
||||
import OAuthView from './views/OAuthView';
|
||||
import SetUsernameView from './views/SetUsernameView';
|
||||
import { HEADER_BACKGROUND, HEADER_TITLE, HEADER_BACK } from './constants/colors';
|
||||
import parseQuery from './lib/methods/helpers/parseQuery';
|
||||
import { initializePushNotifications } from './push';
|
||||
import { DEFAULT_HEADER } from './constants/headerOptions';
|
||||
import store from './lib/createStore';
|
||||
|
||||
const startLogged = () => {
|
||||
Navigation.loadView('ProfileView');
|
||||
Navigation.loadView('RoomsListHeaderView');
|
||||
Navigation.loadView('RoomsListView');
|
||||
Navigation.loadView('RoomView');
|
||||
Navigation.loadView('RoomHeaderView');
|
||||
Navigation.loadView('SettingsView');
|
||||
Navigation.loadView('SidebarView');
|
||||
|
||||
Navigation.setRoot({
|
||||
root: {
|
||||
stack: {
|
||||
id: 'AppRoot',
|
||||
children: [{
|
||||
component: {
|
||||
id: 'RoomsListView',
|
||||
name: 'RoomsListView'
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const startNotLogged = () => {
|
||||
Navigation.loadView('OnboardingView');
|
||||
Navigation.setRoot({
|
||||
root: {
|
||||
stack: {
|
||||
children: [{
|
||||
component: {
|
||||
name: 'OnboardingView'
|
||||
}
|
||||
}],
|
||||
options: {
|
||||
layout: {
|
||||
orientation: ['portrait']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const startSetUsername = () => {
|
||||
Navigation.loadView('SetUsernameView');
|
||||
Navigation.setRoot({
|
||||
root: {
|
||||
stack: {
|
||||
children: [{
|
||||
component: {
|
||||
name: 'SetUsernameView'
|
||||
}
|
||||
}],
|
||||
options: {
|
||||
layout: {
|
||||
orientation: ['portrait']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
useScreens();
|
||||
initializePushNotifications();
|
||||
|
||||
const handleOpenURL = ({ url }) => {
|
||||
if (url) {
|
||||
|
@ -86,51 +57,139 @@ const handleOpenURL = ({ url }) => {
|
|||
}
|
||||
};
|
||||
|
||||
Icons.configure();
|
||||
Linking
|
||||
.getInitialURL()
|
||||
.then(url => handleOpenURL({ url }))
|
||||
.catch(e => console.warn(e));
|
||||
Linking.addEventListener('url', handleOpenURL);
|
||||
|
||||
export default class App extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
initializePushNotifications();
|
||||
const defaultHeader = {
|
||||
headerStyle: {
|
||||
backgroundColor: HEADER_BACKGROUND
|
||||
},
|
||||
headerTitleStyle: {
|
||||
color: HEADER_TITLE
|
||||
},
|
||||
headerBackTitle: null,
|
||||
headerTintColor: HEADER_BACK
|
||||
};
|
||||
|
||||
Navigation.events().registerAppLaunchedListener(() => {
|
||||
Navigation.setDefaultOptions({
|
||||
...DEFAULT_HEADER,
|
||||
sideMenu: {
|
||||
left: {
|
||||
enabled: false
|
||||
},
|
||||
right: {
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
});
|
||||
store.dispatch(appInit());
|
||||
store.subscribe(this.onStoreUpdate.bind(this));
|
||||
});
|
||||
Linking
|
||||
.getInitialURL()
|
||||
.then(url => handleOpenURL({ url }))
|
||||
.catch(e => console.warn(e));
|
||||
Linking.addEventListener('url', handleOpenURL);
|
||||
// Outside
|
||||
const OutsideStack = createStackNavigator({
|
||||
OnboardingView: {
|
||||
screen: OnboardingView,
|
||||
header: null
|
||||
},
|
||||
NewServerView,
|
||||
LoginSignupView,
|
||||
LoginView,
|
||||
ForgotPasswordView,
|
||||
RegisterView
|
||||
}, {
|
||||
defaultNavigationOptions: defaultHeader
|
||||
});
|
||||
|
||||
const LegalStack = createStackNavigator({
|
||||
LegalView,
|
||||
TermsServiceView,
|
||||
PrivacyPolicyView
|
||||
}, {
|
||||
defaultNavigationOptions: defaultHeader
|
||||
});
|
||||
|
||||
const OAuthStack = createStackNavigator({
|
||||
OAuthView
|
||||
}, {
|
||||
defaultNavigationOptions: defaultHeader
|
||||
});
|
||||
|
||||
const OutsideStackModal = createStackNavigator({
|
||||
OutsideStack,
|
||||
LegalStack,
|
||||
OAuthStack
|
||||
},
|
||||
{
|
||||
mode: 'modal',
|
||||
headerMode: 'none'
|
||||
});
|
||||
|
||||
// Inside
|
||||
const ChatsStack = createStackNavigator({
|
||||
RoomsListView,
|
||||
RoomView,
|
||||
RoomActionsView,
|
||||
RoomInfoView,
|
||||
RoomInfoEditView,
|
||||
RoomMembersView,
|
||||
RoomFilesView,
|
||||
MentionedMessagesView,
|
||||
StarredMessagesView,
|
||||
SearchMessagesView,
|
||||
PinnedMessagesView,
|
||||
SelectedUsersView
|
||||
}, {
|
||||
defaultNavigationOptions: defaultHeader
|
||||
});
|
||||
|
||||
const ProfileStack = createStackNavigator({
|
||||
ProfileView
|
||||
}, {
|
||||
defaultNavigationOptions: defaultHeader
|
||||
});
|
||||
|
||||
const SettingsStack = createStackNavigator({
|
||||
SettingsView
|
||||
}, {
|
||||
defaultNavigationOptions: defaultHeader
|
||||
});
|
||||
|
||||
const ChatsDrawer = createDrawerNavigator({
|
||||
ChatsStack,
|
||||
ProfileStack,
|
||||
SettingsStack
|
||||
}, {
|
||||
contentComponent: Sidebar
|
||||
});
|
||||
|
||||
const NewMessageStack = createStackNavigator({
|
||||
NewMessageView,
|
||||
SelectedUsersViewCreateChannel: SelectedUsersView,
|
||||
CreateChannelView
|
||||
}, {
|
||||
defaultNavigationOptions: defaultHeader
|
||||
});
|
||||
|
||||
const InsideStackModal = createStackNavigator({
|
||||
Main: ChatsDrawer,
|
||||
NewMessageStack
|
||||
},
|
||||
{
|
||||
mode: 'modal',
|
||||
headerMode: 'none'
|
||||
});
|
||||
|
||||
const SetUsernameStack = createStackNavigator({
|
||||
SetUsernameView
|
||||
});
|
||||
|
||||
const App = createAppContainer(createSwitchNavigator(
|
||||
{
|
||||
OutsideStack: OutsideStackModal,
|
||||
InsideStack: InsideStackModal,
|
||||
AuthLoading: AuthLoadingView,
|
||||
SetUsernameStack
|
||||
},
|
||||
{
|
||||
initialRouteName: 'AuthLoading'
|
||||
}
|
||||
));
|
||||
|
||||
onStoreUpdate = () => {
|
||||
const { root } = store.getState().app;
|
||||
|
||||
if (this.currentRoot !== root) {
|
||||
this.currentRoot = root;
|
||||
if (root === 'outside') {
|
||||
startNotLogged();
|
||||
} else if (root === 'inside') {
|
||||
startLogged();
|
||||
} else if (root === 'setUsername') {
|
||||
startSetUsername();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setDeviceToken(deviceToken) {
|
||||
this.deviceToken = deviceToken;
|
||||
}
|
||||
}
|
||||
export default () => (
|
||||
<Provider store={store}>
|
||||
<App
|
||||
ref={(navigatorRef) => {
|
||||
Navigation.setTopLevelNavigator(navigatorRef);
|
||||
}}
|
||||
/>
|
||||
</Provider>
|
||||
);
|
||||
|
|
|
@ -9,36 +9,3 @@ const CustomIcon = createIconSetFromIcoMoon(
|
|||
);
|
||||
|
||||
export { CustomIcon };
|
||||
|
||||
// icon name from provider: [ size of the uri, icon provider, name to be used later ]
|
||||
const icons = {
|
||||
'Star-filled': [25, CustomIcon, 'star'],
|
||||
star: [25, CustomIcon, 'starOutline'],
|
||||
menu: [25, CustomIcon, 'more'],
|
||||
edit: [25, CustomIcon, 'edit'],
|
||||
cross: [25, CustomIcon, 'close'],
|
||||
customize: [25, CustomIcon, 'settings'],
|
||||
magnifier: [25, CustomIcon, 'search'],
|
||||
'edit-rounded': [25, CustomIcon, 'new_channel']
|
||||
};
|
||||
|
||||
class Icons {
|
||||
constructor() {
|
||||
this.icons = {};
|
||||
}
|
||||
|
||||
async configure() {
|
||||
const promises = Object.keys(icons).map((icon) => {
|
||||
const Provider = icons[icon][1];
|
||||
return Provider.getImageSource(icon, icons[icon][0], '#FFF');
|
||||
});
|
||||
const sources = await Promise.all(promises);
|
||||
Object.keys(icons).forEach((icon, i) => (this.icons[icons[icon][2]] = sources[i]));
|
||||
}
|
||||
|
||||
getSource(icon) {
|
||||
return this.icons[icon];
|
||||
}
|
||||
}
|
||||
|
||||
export default new Icons();
|
||||
|
|
|
@ -1,260 +1,21 @@
|
|||
import { Navigation } from 'react-native-navigation';
|
||||
import { Provider } from 'react-redux';
|
||||
import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
|
||||
import { NavigationActions } from 'react-navigation';
|
||||
|
||||
import store from './createStore';
|
||||
import debounce from '../utils/debounce';
|
||||
let _navigator;
|
||||
|
||||
const DRAWER_ID = 'SidebarView';
|
||||
|
||||
class NavigationManager {
|
||||
constructor() {
|
||||
this.views = {
|
||||
OnboardingView: {
|
||||
name: 'OnboardingView',
|
||||
loaded: false,
|
||||
require: () => require('../views/OnboardingView').default
|
||||
},
|
||||
ProfileView: {
|
||||
name: 'ProfileView',
|
||||
loaded: false,
|
||||
require: () => require('../views/ProfileView').default
|
||||
},
|
||||
RoomsListHeaderView: {
|
||||
name: 'RoomsListHeaderView',
|
||||
loaded: false,
|
||||
require: () => require('../views/RoomsListView/Header').default
|
||||
},
|
||||
RoomsListView: {
|
||||
name: 'RoomsListView',
|
||||
loaded: false,
|
||||
require: () => require('../views/RoomsListView').default
|
||||
},
|
||||
RoomView: {
|
||||
name: 'RoomView',
|
||||
loaded: false,
|
||||
require: () => require('../views/RoomView').default
|
||||
},
|
||||
RoomHeaderView: {
|
||||
name: 'RoomHeaderView',
|
||||
loaded: false,
|
||||
require: () => require('../views/RoomView/Header').default
|
||||
},
|
||||
SettingsView: {
|
||||
name: 'SettingsView',
|
||||
loaded: false,
|
||||
require: () => require('../views/SettingsView').default
|
||||
},
|
||||
SidebarView: {
|
||||
name: 'SidebarView',
|
||||
loaded: false,
|
||||
require: () => require('../views/SidebarView').default
|
||||
},
|
||||
NewServerView: {
|
||||
name: 'NewServerView',
|
||||
loaded: false,
|
||||
require: () => require('../views/NewServerView').default
|
||||
},
|
||||
CreateChannelView: {
|
||||
name: 'CreateChannelView',
|
||||
loaded: false,
|
||||
require: () => require('../views/CreateChannelView').default
|
||||
},
|
||||
ForgotPasswordView: {
|
||||
name: 'ForgotPasswordView',
|
||||
loaded: false,
|
||||
require: () => require('../views/ForgotPasswordView').default
|
||||
},
|
||||
LegalView: {
|
||||
name: 'LegalView',
|
||||
loaded: false,
|
||||
require: () => require('../views/LegalView').default
|
||||
},
|
||||
LoginSignupView: {
|
||||
name: 'LoginSignupView',
|
||||
loaded: false,
|
||||
require: () => require('../views/LoginSignupView').default
|
||||
},
|
||||
LoginView: {
|
||||
name: 'LoginView',
|
||||
loaded: false,
|
||||
require: () => require('../views/LoginView').default
|
||||
},
|
||||
NewMessageView: {
|
||||
name: 'NewMessageView',
|
||||
loaded: false,
|
||||
require: () => require('../views/NewMessageView').default
|
||||
},
|
||||
OAuthView: {
|
||||
name: 'OAuthView',
|
||||
loaded: false,
|
||||
require: () => require('../views/OAuthView').default
|
||||
},
|
||||
PrivacyPolicyView: {
|
||||
name: 'PrivacyPolicyView',
|
||||
loaded: false,
|
||||
require: () => require('../views/PrivacyPolicyView').default
|
||||
},
|
||||
RegisterView: {
|
||||
name: 'RegisterView',
|
||||
loaded: false,
|
||||
require: () => require('../views/RegisterView').default
|
||||
},
|
||||
SelectedUsersView: {
|
||||
name: 'SelectedUsersView',
|
||||
loaded: false,
|
||||
require: () => require('../views/SelectedUsersView').default
|
||||
},
|
||||
SetUsernameView: {
|
||||
name: 'SetUsernameView',
|
||||
loaded: false,
|
||||
require: () => require('../views/SetUsernameView').default
|
||||
},
|
||||
TermsServiceView: {
|
||||
name: 'TermsServiceView',
|
||||
loaded: false,
|
||||
require: () => require('../views/TermsServiceView').default
|
||||
},
|
||||
MentionedMessagesView: {
|
||||
name: 'MentionedMessagesView',
|
||||
loaded: false,
|
||||
require: () => require('../views/MentionedMessagesView').default
|
||||
},
|
||||
PinnedMessagesView: {
|
||||
name: 'PinnedMessagesView',
|
||||
loaded: false,
|
||||
require: () => require('../views/PinnedMessagesView').default
|
||||
},
|
||||
RoomActionsView: {
|
||||
name: 'RoomActionsView',
|
||||
loaded: false,
|
||||
require: () => require('../views/RoomActionsView').default
|
||||
},
|
||||
RoomFilesView: {
|
||||
name: 'RoomFilesView',
|
||||
loaded: false,
|
||||
require: () => require('../views/RoomFilesView').default
|
||||
},
|
||||
RoomInfoEditView: {
|
||||
name: 'RoomInfoEditView',
|
||||
loaded: false,
|
||||
require: () => require('../views/RoomInfoEditView').default
|
||||
},
|
||||
RoomInfoView: {
|
||||
name: 'RoomInfoView',
|
||||
loaded: false,
|
||||
require: () => require('../views/RoomInfoView').default
|
||||
},
|
||||
RoomMembersView: {
|
||||
name: 'RoomMembersView',
|
||||
loaded: false,
|
||||
require: () => require('../views/RoomMembersView').default
|
||||
},
|
||||
SearchMessagesView: {
|
||||
name: 'SearchMessagesView',
|
||||
loaded: false,
|
||||
require: () => require('../views/SearchMessagesView').default
|
||||
},
|
||||
SnippetedMessagesView: {
|
||||
name: 'SnippetedMessagesView',
|
||||
loaded: false,
|
||||
require: () => require('../views/SnippetedMessagesView').default
|
||||
},
|
||||
StarredMessagesView: {
|
||||
name: 'StarredMessagesView',
|
||||
loaded: false,
|
||||
require: () => require('../views/StarredMessagesView').default
|
||||
}
|
||||
};
|
||||
this.isDrawerVisible = false;
|
||||
|
||||
Navigation.events().registerComponentDidAppearListener(({ componentId }) => {
|
||||
if (componentId === DRAWER_ID) {
|
||||
this.isDrawerVisible = true;
|
||||
}
|
||||
});
|
||||
|
||||
Navigation.events().registerComponentDidDisappearListener(({ componentId }) => {
|
||||
if (componentId === DRAWER_ID) {
|
||||
this.isDrawerVisible = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleComponentName = (componentName) => {
|
||||
if (!componentName) {
|
||||
return console.error('componentName not found');
|
||||
}
|
||||
}
|
||||
|
||||
loadView = (componentName) => {
|
||||
const view = this.views[componentName];
|
||||
if (!view) {
|
||||
return console.error('view not found');
|
||||
}
|
||||
if (!view.loaded) {
|
||||
Navigation.registerComponentWithRedux(view.name, () => gestureHandlerRootHOC(view.require()), Provider, store);
|
||||
view.loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
push = debounce((...args) => {
|
||||
let componentName;
|
||||
try {
|
||||
componentName = args[1].component.name;
|
||||
} catch (error) {
|
||||
return console.error(error);
|
||||
}
|
||||
this.handleComponentName(componentName);
|
||||
this.loadView(componentName);
|
||||
Navigation.push(...args);
|
||||
}, 300, true)
|
||||
|
||||
showModal = debounce((...args) => {
|
||||
let componentName;
|
||||
try {
|
||||
componentName = args[0].stack.children[0].component.name;
|
||||
} catch (error) {
|
||||
return console.error(error);
|
||||
}
|
||||
this.handleComponentName(componentName);
|
||||
this.loadView(componentName);
|
||||
Navigation.showModal(...args);
|
||||
}, 300, true)
|
||||
|
||||
pop = (...args) => Navigation.pop(...args);
|
||||
|
||||
popToRoot = (...args) => Navigation.popToRoot(...args);
|
||||
|
||||
dismissModal = (...args) => Navigation.dismissModal(...args);
|
||||
|
||||
dismissAllModals = (...args) => Navigation.dismissAllModals(...args);
|
||||
|
||||
events = (...args) => Navigation.events(...args);
|
||||
|
||||
mergeOptions = (...args) => Navigation.mergeOptions(...args);
|
||||
|
||||
setDefaultOptions = (...args) => Navigation.setDefaultOptions(...args);
|
||||
|
||||
setRoot = (...args) => Navigation.setRoot(...args);
|
||||
|
||||
setStackRoot = (...args) => Navigation.setStackRoot(...args);
|
||||
|
||||
toggleDrawer = () => {
|
||||
try {
|
||||
const visibility = !this.isDrawerVisible;
|
||||
Navigation.mergeOptions(DRAWER_ID, {
|
||||
sideMenu: {
|
||||
left: {
|
||||
visible: visibility
|
||||
}
|
||||
}
|
||||
});
|
||||
this.isDrawerVisible = visibility;
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
}
|
||||
}
|
||||
function setTopLevelNavigator(navigatorRef) {
|
||||
_navigator = navigatorRef;
|
||||
}
|
||||
|
||||
export default new NavigationManager();
|
||||
function navigate(routeName, params) {
|
||||
_navigator.dispatch(
|
||||
NavigationActions.navigate({
|
||||
routeName,
|
||||
params
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export default {
|
||||
navigate,
|
||||
setTopLevelNavigator
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { createStore as reduxCreateStore, applyMiddleware, compose } from 'redux';
|
||||
import Reactotron from 'reactotron-react-native' ; // eslint-disable-line
|
||||
import Reactotron from 'reactotron-react-native';
|
||||
import createSagaMiddleware from 'redux-saga';
|
||||
import applyAppStateListener from 'redux-enhancer-react-native-appstate';
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ import {
|
|||
} from '../actions/login';
|
||||
import { disconnect, connectSuccess, connectRequest } from '../actions/connect';
|
||||
import { setActiveUser } from '../actions/activeUsers';
|
||||
import { snippetedMessagesReceived } from '../actions/snippetedMessages';
|
||||
import { someoneTyping, roomMessageReceived } from '../actions/room';
|
||||
import { setRoles } from '../actions/roles';
|
||||
|
||||
|
@ -213,27 +212,6 @@ const RocketChat = {
|
|||
}
|
||||
}));
|
||||
|
||||
this.sdk.onStreamData('rocketchat_snippeted_message', protectedFunction((ddpMessage) => {
|
||||
if (ddpMessage.msg === 'added') {
|
||||
this.snippetedMessages = this.snippetedMessages || [];
|
||||
|
||||
if (this.snippetedMessagesTimer) {
|
||||
clearTimeout(this.snippetedMessagesTimer);
|
||||
this.snippetedMessagesTimer = null;
|
||||
}
|
||||
|
||||
this.snippetedMessagesTimer = setTimeout(() => {
|
||||
reduxStore.dispatch(snippetedMessagesReceived(this.snippetedMessages));
|
||||
this.snippetedMessagesTimer = null;
|
||||
return this.snippetedMessages = [];
|
||||
}, 1000);
|
||||
const message = ddpMessage.fields;
|
||||
message._id = ddpMessage.id;
|
||||
const snippetedMessage = _buildMessage(message);
|
||||
this.snippetedMessages = [...this.snippetedMessages, snippetedMessage];
|
||||
}
|
||||
}));
|
||||
|
||||
this.sdk.onStreamData('rocketchat_roles', protectedFunction((ddpMessage) => {
|
||||
this.roles = this.roles || {};
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ const renderNumber = (unread, userMentions) => {
|
|||
);
|
||||
};
|
||||
|
||||
const attrs = ['name', 'unread', 'userMentions', 'alert', 'showLastMessage', 'type'];
|
||||
const attrs = ['name', 'unread', 'userMentions', 'StoreLastMessage', 'alert', 'type'];
|
||||
@connect(state => ({
|
||||
user: {
|
||||
id: state.login.user && state.login.user.id,
|
||||
|
@ -128,7 +128,6 @@ export default class RoomItem extends React.Component {
|
|||
StoreLastMessage: PropTypes.bool,
|
||||
_updatedAt: PropTypes.string,
|
||||
lastMessage: PropTypes.object,
|
||||
showLastMessage: PropTypes.bool,
|
||||
favorite: PropTypes.bool,
|
||||
alert: PropTypes.bool,
|
||||
unread: PropTypes.number,
|
||||
|
@ -146,7 +145,6 @@ export default class RoomItem extends React.Component {
|
|||
}
|
||||
|
||||
static defaultProps = {
|
||||
showLastMessage: true,
|
||||
avatarSize: 48
|
||||
}
|
||||
|
||||
|
@ -174,10 +172,10 @@ export default class RoomItem extends React.Component {
|
|||
|
||||
get lastMessage() {
|
||||
const {
|
||||
lastMessage, type, showLastMessage, StoreLastMessage, user
|
||||
lastMessage, type, StoreLastMessage, user
|
||||
} = this.props;
|
||||
|
||||
if (!StoreLastMessage || !showLastMessage) {
|
||||
if (!StoreLastMessage) {
|
||||
return '';
|
||||
}
|
||||
if (!lastMessage) {
|
||||
|
|
|
@ -24,6 +24,7 @@ class PushNotification {
|
|||
configure(params) {
|
||||
this.onRegister = params.onRegister;
|
||||
this.onNotification = params.onNotification;
|
||||
NotificationsAndroid.refreshToken();
|
||||
|
||||
PendingNotifications.getInitialNotification()
|
||||
.then((notification) => {
|
||||
|
|
|
@ -3,7 +3,6 @@ import { APP } from '../actions/actionsTypes';
|
|||
|
||||
const initialState = {
|
||||
root: null,
|
||||
stackRoot: 'RoomsListView',
|
||||
ready: false,
|
||||
inactive: false,
|
||||
background: false
|
||||
|
@ -37,11 +36,6 @@ export default function app(state = initialState, action) {
|
|||
...state,
|
||||
root: action.root
|
||||
};
|
||||
case APP.SET_STACK_ROOT:
|
||||
return {
|
||||
...state,
|
||||
stackRoot: action.stackRoot
|
||||
};
|
||||
case APP.INIT:
|
||||
return {
|
||||
...state,
|
||||
|
|
|
@ -12,7 +12,6 @@ import app from './app';
|
|||
import customEmojis from './customEmojis';
|
||||
import activeUsers from './activeUsers';
|
||||
import roles from './roles';
|
||||
import snippetedMessages from './snippetedMessages';
|
||||
import sortPreferences from './sortPreferences';
|
||||
|
||||
export default combineReducers({
|
||||
|
@ -29,6 +28,5 @@ export default combineReducers({
|
|||
customEmojis,
|
||||
activeUsers,
|
||||
roles,
|
||||
snippetedMessages,
|
||||
sortPreferences
|
||||
});
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
import { SNIPPETED_MESSAGES } from '../actions/actionsTypes';
|
||||
|
||||
const initialState = {
|
||||
messages: [],
|
||||
ready: false
|
||||
};
|
||||
|
||||
export default function server(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case SNIPPETED_MESSAGES.OPEN:
|
||||
return {
|
||||
...state,
|
||||
ready: false
|
||||
};
|
||||
case SNIPPETED_MESSAGES.READY:
|
||||
return {
|
||||
...state,
|
||||
ready: true
|
||||
};
|
||||
case SNIPPETED_MESSAGES.MESSAGES_RECEIVED:
|
||||
return {
|
||||
...state,
|
||||
messages: [...state.messages, ...action.messages]
|
||||
};
|
||||
case SNIPPETED_MESSAGES.CLOSE:
|
||||
return initialState;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -6,7 +6,6 @@ import {
|
|||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import * as types from '../actions/actionsTypes';
|
||||
import { appStart, setStackRoot } from '../actions';
|
||||
import { selectServerRequest } from '../actions/server';
|
||||
import database from '../lib/realm';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
|
@ -16,40 +15,12 @@ const roomTypes = {
|
|||
channel: 'c', direct: 'd', group: 'p'
|
||||
};
|
||||
|
||||
const navigate = function* navigate({ params, sameServer = true }) {
|
||||
if (!sameServer) {
|
||||
yield put(appStart('inside'));
|
||||
}
|
||||
const navigate = function* navigate({ params }) {
|
||||
if (params.rid) {
|
||||
const canOpenRoom = yield RocketChat.canOpenRoom(params);
|
||||
if (canOpenRoom) {
|
||||
const stack = 'RoomsListView';
|
||||
const stackRoot = yield select(state => state.app.stackRoot);
|
||||
|
||||
// Make sure current stack is RoomsListView before navigate to RoomView
|
||||
if (stackRoot !== stack) {
|
||||
yield Navigation.setStackRoot('AppRoot', {
|
||||
component: {
|
||||
id: stack,
|
||||
name: stack
|
||||
}
|
||||
});
|
||||
yield put(setStackRoot(stack));
|
||||
}
|
||||
try {
|
||||
yield Navigation.popToRoot(stack);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
const [type, name] = params.path.split('/');
|
||||
Navigation.push(stack, {
|
||||
component: {
|
||||
name: 'RoomView',
|
||||
passProps: {
|
||||
rid: params.rid, name, t: roomTypes[type]
|
||||
}
|
||||
}
|
||||
});
|
||||
Navigation.navigate('RoomView', { rid: params.rid, name, t: roomTypes[type] });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -100,9 +71,13 @@ const handleOpen = function* handleOpen({ params }) {
|
|||
const servers = yield database.databases.serversDB.objects('servers').filtered('id = $0', host); // TODO: need better test
|
||||
if (servers.length && user) {
|
||||
yield put(selectServerRequest(host));
|
||||
yield navigate({ params, sameServer: false });
|
||||
yield race({
|
||||
typing: take(types.SERVER.SELECT_SUCCESS),
|
||||
timeout: delay(3000)
|
||||
});
|
||||
yield navigate({ params });
|
||||
} else {
|
||||
yield put(appStart('outside'));
|
||||
Navigation.navigate('OnboardingView', { previousServer: server });
|
||||
yield delay(1000);
|
||||
EventEmitter.emit('NewServer', { server: host });
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import selectServer from './selectServer';
|
|||
import createChannel from './createChannel';
|
||||
import init from './init';
|
||||
import state from './state';
|
||||
import snippetedMessages from './snippetedMessages';
|
||||
import deepLinking from './deepLinking';
|
||||
|
||||
const root = function* root() {
|
||||
|
@ -20,7 +19,6 @@ const root = function* root() {
|
|||
messages(),
|
||||
selectServer(),
|
||||
state(),
|
||||
snippetedMessages(),
|
||||
deepLinking()
|
||||
]);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { AsyncStorage } from 'react-native';
|
||||
import { put, takeLatest, all } from 'redux-saga/effects';
|
||||
import SplashScreen from 'react-native-splash-screen';
|
||||
|
||||
import * as actions from '../actions';
|
||||
import { selectServerRequest } from '../actions/server';
|
||||
|
@ -7,6 +8,7 @@ import { setAllPreferences } from '../actions/sortPreferences';
|
|||
import { APP } from '../actions/actionsTypes';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import log from '../utils/log';
|
||||
import Navigation from '../lib/Navigation';
|
||||
|
||||
const restore = function* restore() {
|
||||
try {
|
||||
|
@ -34,7 +36,19 @@ const restore = function* restore() {
|
|||
}
|
||||
};
|
||||
|
||||
const start = function* start({ root }) {
|
||||
if (root === 'inside') {
|
||||
yield Navigation.navigate('InsideStack');
|
||||
} else if (root === 'setUsername') {
|
||||
yield Navigation.navigate('SetUsernameView');
|
||||
} else if (root === 'outside') {
|
||||
yield Navigation.navigate('OutsideStack');
|
||||
}
|
||||
SplashScreen.hide();
|
||||
};
|
||||
|
||||
const root = function* root() {
|
||||
yield takeLatest(APP.INIT, restore);
|
||||
yield takeLatest(APP.START, start);
|
||||
};
|
||||
export default root;
|
||||
|
|
|
@ -3,7 +3,6 @@ import {
|
|||
put, call, takeLatest, select
|
||||
} from 'redux-saga/effects';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import * as types from '../actions/actionsTypes';
|
||||
import { appStart } from '../actions';
|
||||
import { serverFinishAdd, selectServerRequest } from '../actions/server';
|
||||
|
@ -50,7 +49,7 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
|
|||
yield put(appStart('setUsername'));
|
||||
} else if (adding) {
|
||||
yield put(serverFinishAdd());
|
||||
yield Navigation.dismissAllModals();
|
||||
yield put(appStart('inside'));
|
||||
} else {
|
||||
yield put(appStart('inside'));
|
||||
}
|
||||
|
|
|
@ -74,16 +74,9 @@ const handleTogglePinRequest = function* handleTogglePinRequest({ message }) {
|
|||
}
|
||||
};
|
||||
|
||||
const goRoom = function* goRoom({ rid, name }) {
|
||||
yield Navigation.popToRoot('RoomsListView');
|
||||
Navigation.push('RoomsListView', {
|
||||
component: {
|
||||
name: 'RoomView',
|
||||
passProps: {
|
||||
rid, name, t: 'd'
|
||||
}
|
||||
}
|
||||
});
|
||||
const goRoom = function goRoom({ rid, name }) {
|
||||
Navigation.navigate('RoomsListView');
|
||||
Navigation.navigate('RoomView', { rid, name, t: 'd' });
|
||||
};
|
||||
|
||||
const handleReplyBroadcast = function* handleReplyBroadcast({ message }) {
|
||||
|
|
|
@ -124,7 +124,7 @@ const handleLeaveRoom = function* handleLeaveRoom({ rid, t }) {
|
|||
try {
|
||||
const result = yield RocketChat.leaveRoom(rid, t);
|
||||
if (result.success) {
|
||||
yield Navigation.popToRoot('RoomsListView');
|
||||
yield Navigation.navigate('RoomsListView');
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.data && e.data.errorType === 'error-you-are-last-owner') {
|
||||
|
@ -139,7 +139,7 @@ const handleEraseRoom = function* handleEraseRoom({ rid, t }) {
|
|||
try {
|
||||
const result = yield RocketChat.eraseRoom(rid, t);
|
||||
if (result.success) {
|
||||
yield Navigation.popToRoot('RoomsListView');
|
||||
yield Navigation.navigate('RoomsListView');
|
||||
}
|
||||
} catch (e) {
|
||||
Alert.alert(I18n.t('Oops'), I18n.t('There_was_an_error_while_action', { action: I18n.t('erasing_room') }));
|
||||
|
|
|
@ -53,17 +53,9 @@ const handleServerRequest = function* handleServerRequest({ server }) {
|
|||
|
||||
const loginServicesLength = yield RocketChat.getLoginServices(server);
|
||||
if (loginServicesLength === 0) {
|
||||
yield Navigation.push('NewServerView', {
|
||||
component: {
|
||||
name: 'LoginView'
|
||||
}
|
||||
});
|
||||
Navigation.navigate('LoginView');
|
||||
} else {
|
||||
yield Navigation.push('NewServerView', {
|
||||
component: {
|
||||
name: 'LoginSignupView'
|
||||
}
|
||||
});
|
||||
Navigation.navigate('LoginSignupView');
|
||||
}
|
||||
|
||||
database.databases.serversDB.write(() => {
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
import { put, takeLatest } from 'redux-saga/effects';
|
||||
|
||||
import * as types from '../actions/actionsTypes';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import { readySnippetedMessages } from '../actions/snippetedMessages';
|
||||
import log from '../utils/log';
|
||||
|
||||
let sub;
|
||||
let newSub;
|
||||
|
||||
const openSnippetedMessagesRoom = function* openSnippetedMessagesRoom({ rid, limit }) {
|
||||
try {
|
||||
newSub = yield RocketChat.subscribe('snippetedMessages', rid, limit);
|
||||
yield put(readySnippetedMessages());
|
||||
if (sub) {
|
||||
sub.unsubscribe().catch(err => console.warn(err));
|
||||
}
|
||||
sub = newSub;
|
||||
} catch (e) {
|
||||
log('openSnippetedMessagesRoom', e);
|
||||
}
|
||||
};
|
||||
|
||||
const closeSnippetedMessagesRoom = function* closeSnippetedMessagesRoom() {
|
||||
try {
|
||||
if (sub) {
|
||||
yield sub.unsubscribe();
|
||||
}
|
||||
if (newSub) {
|
||||
yield newSub.unsubscribe();
|
||||
}
|
||||
} catch (e) {
|
||||
log('closeSnippetedMessagesRoom', e);
|
||||
}
|
||||
};
|
||||
|
||||
const root = function* root() {
|
||||
yield takeLatest(types.SNIPPETED_MESSAGES.OPEN, openSnippetedMessagesRoom);
|
||||
yield takeLatest(types.SNIPPETED_MESSAGES.CLOSE, closeSnippetedMessagesRoom);
|
||||
};
|
||||
export default root;
|
|
@ -0,0 +1,38 @@
|
|||
import React from 'react';
|
||||
import { StyleSheet, Image } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import { isAndroid } from '../utils/deviceInfo';
|
||||
import { appInit as appInitAction } from '../actions';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
image: {
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
}
|
||||
});
|
||||
|
||||
@connect(null, dispatch => ({
|
||||
appInit: () => dispatch(appInitAction())
|
||||
}))
|
||||
export default class Loading extends React.PureComponent {
|
||||
static propTypes = {
|
||||
appInit: PropTypes.func
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
props.appInit();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<StatusBar />
|
||||
{isAndroid ? <Image source={{ uri: 'launch_screen' }} style={styles.image} /> : null}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,10 +4,9 @@ import PropTypes from 'prop-types';
|
|||
import {
|
||||
View, Text, Switch, ScrollView, TextInput, StyleSheet, FlatList
|
||||
} from 'react-native';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import Loading from '../containers/Loading';
|
||||
import LoggedView from './View';
|
||||
import { createChannelRequest as createChannelRequestAction } from '../actions/createChannel';
|
||||
|
@ -19,6 +18,8 @@ import I18n from '../i18n';
|
|||
import UserItem from '../presentation/UserItem';
|
||||
import { showErrorAlert } from '../utils/info';
|
||||
import { isAndroid } from '../utils/deviceInfo';
|
||||
import { CustomHeaderButtons, Item } from '../containers/HeaderButton';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -91,18 +92,25 @@ const styles = StyleSheet.create({
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class CreateChannelView extends LoggedView {
|
||||
static options() {
|
||||
static navigationOptions = ({ navigation }) => {
|
||||
const submit = navigation.getParam('submit', () => {});
|
||||
const showSubmit = navigation.getParam('showSubmit');
|
||||
return {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Create_Channel')
|
||||
}
|
||||
}
|
||||
title: I18n.t('Create_Channel'),
|
||||
headerRight: (
|
||||
showSubmit
|
||||
? (
|
||||
<CustomHeaderButtons>
|
||||
<Item title={I18n.t('Create')} onPress={submit} testID='create-channel-submit' />
|
||||
</CustomHeaderButtons>
|
||||
)
|
||||
: null
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
baseUrl: PropTypes.string,
|
||||
create: PropTypes.func.isRequired,
|
||||
removeUser: PropTypes.func.isRequired,
|
||||
|
@ -125,10 +133,11 @@ export default class CreateChannelView extends LoggedView {
|
|||
readOnly: false,
|
||||
broadcast: false
|
||||
};
|
||||
Navigation.events().bindComponent(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { navigation } = this.props;
|
||||
navigation.setParams({ submit: this.submit });
|
||||
this.timeout = setTimeout(() => {
|
||||
this.channelNameRef.focus();
|
||||
}, 600);
|
||||
|
@ -173,26 +182,18 @@ export default class CreateChannelView extends LoggedView {
|
|||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
isFetching, failure, error, result, componentId
|
||||
isFetching, failure, error, result, navigation
|
||||
} = this.props;
|
||||
|
||||
if (!isFetching && isFetching !== prevProps.isFetching) {
|
||||
setTimeout(async() => {
|
||||
setTimeout(() => {
|
||||
if (failure) {
|
||||
const msg = error.reason || I18n.t('There_was_an_error_while_action', { action: I18n.t('creating_channel') });
|
||||
showErrorAlert(msg);
|
||||
} else {
|
||||
const { type } = this.state;
|
||||
const { rid, name } = result;
|
||||
await Navigation.dismissModal(componentId);
|
||||
Navigation.push('RoomsListView', {
|
||||
component: {
|
||||
name: 'RoomView',
|
||||
passProps: {
|
||||
rid, name, t: type ? 'p' : 'c'
|
||||
}
|
||||
}
|
||||
});
|
||||
navigation.navigate('RoomView', { rid, name, t: type ? 'p' : 'c' });
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
@ -205,30 +206,11 @@ export default class CreateChannelView extends LoggedView {
|
|||
}
|
||||
|
||||
onChangeText = (channelName) => {
|
||||
const { componentId } = this.props;
|
||||
const rightButtons = [];
|
||||
if (channelName.trim().length > 0) {
|
||||
rightButtons.push({
|
||||
id: 'create',
|
||||
text: 'Create',
|
||||
testID: 'create-channel-submit',
|
||||
color: isAndroid ? '#FFF' : undefined
|
||||
});
|
||||
}
|
||||
Navigation.mergeOptions(componentId, {
|
||||
topBar: {
|
||||
rightButtons
|
||||
}
|
||||
});
|
||||
const { navigation } = this.props;
|
||||
navigation.setParams({ showSubmit: channelName.trim().length > 0 });
|
||||
this.setState({ channelName });
|
||||
}
|
||||
|
||||
navigationButtonPressed = ({ buttonId }) => {
|
||||
if (buttonId === 'create') {
|
||||
this.submit();
|
||||
}
|
||||
}
|
||||
|
||||
submit = () => {
|
||||
const {
|
||||
channelName, type, readOnly, broadcast
|
||||
|
@ -354,6 +336,7 @@ export default class CreateChannelView extends LoggedView {
|
|||
contentContainerStyle={[sharedStyles.container, styles.container]}
|
||||
keyboardVerticalOffset={128}
|
||||
>
|
||||
<StatusBar />
|
||||
<SafeAreaView testID='create-channel-view' style={styles.container} forceInset={{ bottom: 'never' }}>
|
||||
<ScrollView {...scrollPersistTaps}>
|
||||
<View style={sharedStyles.separatorVertical}>
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Text, ScrollView } from 'react-native';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import LoggedView from './View';
|
||||
import KeyboardView from '../presentation/KeyboardView';
|
||||
import TextInput from '../containers/TextInput';
|
||||
|
@ -13,19 +12,20 @@ import { showErrorAlert } from '../utils/info';
|
|||
import isValidEmail from '../utils/isValidEmail';
|
||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
import I18n from '../i18n';
|
||||
import { DARK_HEADER } from '../constants/headerOptions';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
|
||||
/** @extends React.Component */
|
||||
export default class ForgotPasswordView extends LoggedView {
|
||||
static options() {
|
||||
static navigationOptions = ({ navigation }) => {
|
||||
const title = navigation.getParam('title', 'Rocket.Chat');
|
||||
return {
|
||||
...DARK_HEADER
|
||||
title
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string
|
||||
navigation: PropTypes.object
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
|
@ -81,8 +81,8 @@ export default class ForgotPasswordView extends LoggedView {
|
|||
this.setState({ isFetching: true });
|
||||
const result = await RocketChat.forgotPassword(email);
|
||||
if (result.success) {
|
||||
const { componentId } = this.props;
|
||||
Navigation.pop(componentId);
|
||||
const { navigation } = this.props;
|
||||
navigation.pop();
|
||||
showErrorAlert(I18n.t('Forgot_password_If_this_email_is_registered'), I18n.t('Alert'));
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -100,6 +100,7 @@ export default class ForgotPasswordView extends LoggedView {
|
|||
contentContainerStyle={sharedStyles.container}
|
||||
keyboardVerticalOffset={128}
|
||||
>
|
||||
<StatusBar />
|
||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
|
||||
<SafeAreaView style={sharedStyles.container} testID='forgot-password-view' forceInset={{ bottom: 'never' }}>
|
||||
<Text style={[sharedStyles.loginTitle, sharedStyles.textBold]}>{I18n.t('Forgot_password')}</Text>
|
||||
|
|
|
@ -3,18 +3,16 @@ import PropTypes from 'prop-types';
|
|||
import {
|
||||
Text, ScrollView, View, StyleSheet
|
||||
} from 'react-native';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import { RectButton } from 'react-native-gesture-handler';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import sharedStyles from './Styles';
|
||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
import { isIOS, isAndroid } from '../utils/deviceInfo';
|
||||
import LoggedView from './View';
|
||||
import I18n from '../i18n';
|
||||
import { DARK_HEADER } from '../constants/headerOptions';
|
||||
import Icons from '../lib/Icons';
|
||||
import DisclosureIndicator from '../containers/DisclosureIndicator';
|
||||
import { CloseModalButton } from '../containers/HeaderButton';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -55,48 +53,22 @@ const Separator = () => <View style={styles.separator} />;
|
|||
|
||||
/** @extends React.Component */
|
||||
export default class LegalView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
...DARK_HEADER,
|
||||
topBar: {
|
||||
...DARK_HEADER.topBar,
|
||||
title: {
|
||||
...DARK_HEADER.topBar.title,
|
||||
text: I18n.t('Legal')
|
||||
},
|
||||
leftButtons: [{
|
||||
id: 'close',
|
||||
icon: isAndroid ? Icons.getSource('close') : undefined,
|
||||
text: isIOS ? I18n.t('Close') : undefined,
|
||||
testID: 'legal-view-close'
|
||||
}]
|
||||
}
|
||||
};
|
||||
}
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
headerLeft: <CloseModalButton testID='legal-view-close' navigation={navigation} />,
|
||||
title: I18n.t('Legal')
|
||||
})
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string
|
||||
navigation: PropTypes.object
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super('LegalView', props);
|
||||
Navigation.events().bindComponent(this);
|
||||
}
|
||||
|
||||
navigationButtonPressed = ({ buttonId }) => {
|
||||
if (buttonId === 'close') {
|
||||
const { componentId } = this.props;
|
||||
Navigation.dismissModal(componentId);
|
||||
}
|
||||
}
|
||||
|
||||
onPressItem = ({ route }) => {
|
||||
const { componentId } = this.props;
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
name: route
|
||||
}
|
||||
});
|
||||
const { navigation } = this.props;
|
||||
navigation.navigate(route);
|
||||
}
|
||||
|
||||
renderItem = ({ text, route, testID }) => (
|
||||
|
@ -109,6 +81,7 @@ export default class LegalView extends LoggedView {
|
|||
render() {
|
||||
return (
|
||||
<SafeAreaView style={styles.container} testID='legal-view' forceInset={{ bottom: 'never' }}>
|
||||
<StatusBar />
|
||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.scroll}>
|
||||
{this.renderItem({ text: 'Terms_of_Service', route: 'TermsServiceView', testID: 'legal-terms-button' })}
|
||||
<Separator />
|
||||
|
|
|
@ -5,19 +5,18 @@ import {
|
|||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { Base64 } from 'js-base64';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import { RectButton, BorderlessButton } from 'react-native-gesture-handler';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import LoggedView from './View';
|
||||
import sharedStyles from './Styles';
|
||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
import random from '../utils/random';
|
||||
import Button from '../containers/Button';
|
||||
import I18n from '../i18n';
|
||||
import { DARK_HEADER } from '../constants/headerOptions';
|
||||
import Icons from '../lib/Icons';
|
||||
import { LegalButton } from '../containers/HeaderButton';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -96,22 +95,16 @@ const SERVICES_COLLAPSED_HEIGHT = 174;
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class LoginSignupView extends LoggedView {
|
||||
static options() {
|
||||
static navigationOptions = ({ navigation }) => {
|
||||
const title = navigation.getParam('title', 'Rocket.Chat');
|
||||
return {
|
||||
...DARK_HEADER,
|
||||
topBar: {
|
||||
...DARK_HEADER.topBar,
|
||||
rightButtons: [{
|
||||
id: 'more',
|
||||
icon: Icons.getSource('more'),
|
||||
testID: 'welcome-view-more'
|
||||
}]
|
||||
}
|
||||
title,
|
||||
headerRight: <LegalButton testID='welcome-view-more' navigation={navigation} />
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
server: PropTypes.string,
|
||||
services: PropTypes.object,
|
||||
Site_Name: PropTypes.string
|
||||
|
@ -123,9 +116,8 @@ export default class LoginSignupView extends LoggedView {
|
|||
collapsed: true,
|
||||
servicesHeight: new Animated.Value(SERVICES_COLLAPSED_HEIGHT)
|
||||
};
|
||||
Navigation.events().bindComponent(this);
|
||||
const { componentId, Site_Name } = this.props;
|
||||
this.setTitle(componentId, Site_Name);
|
||||
const { Site_Name } = this.props;
|
||||
this.setTitle(Site_Name);
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
|
@ -150,34 +142,15 @@ export default class LoginSignupView extends LoggedView {
|
|||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { componentId, Site_Name } = this.props;
|
||||
const { Site_Name } = this.props;
|
||||
if (Site_Name && prevProps.Site_Name !== Site_Name) {
|
||||
this.setTitle(componentId, Site_Name);
|
||||
this.setTitle(Site_Name);
|
||||
}
|
||||
}
|
||||
|
||||
setTitle = (componentId, title) => {
|
||||
Navigation.mergeOptions(componentId, {
|
||||
topBar: {
|
||||
title: {
|
||||
text: title
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
navigationButtonPressed = ({ buttonId }) => {
|
||||
if (buttonId === 'more') {
|
||||
Navigation.showModal({
|
||||
stack: {
|
||||
children: [{
|
||||
component: {
|
||||
name: 'LegalView'
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
}
|
||||
setTitle = (title) => {
|
||||
const { navigation } = this.props;
|
||||
navigation.setParams({ title });
|
||||
}
|
||||
|
||||
onPressFacebook = () => {
|
||||
|
@ -258,57 +231,18 @@ export default class LoginSignupView extends LoggedView {
|
|||
}
|
||||
|
||||
openOAuth = (oAuthUrl) => {
|
||||
Navigation.showModal({
|
||||
stack: {
|
||||
children: [{
|
||||
component: {
|
||||
name: 'OAuthView',
|
||||
passProps: {
|
||||
oAuthUrl
|
||||
},
|
||||
options: {
|
||||
topBar: {
|
||||
title: {
|
||||
text: 'OAuth'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
const { navigation } = this.props;
|
||||
navigation.navigate('OAuthView', { oAuthUrl });
|
||||
}
|
||||
|
||||
login = () => {
|
||||
const { componentId, Site_Name } = this.props;
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
name: 'LoginView',
|
||||
options: {
|
||||
topBar: {
|
||||
title: {
|
||||
text: Site_Name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const { navigation, Site_Name } = this.props;
|
||||
navigation.navigate('LoginView', { title: Site_Name });
|
||||
}
|
||||
|
||||
register = () => {
|
||||
const { componentId, Site_Name } = this.props;
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
name: 'RegisterView',
|
||||
options: {
|
||||
topBar: {
|
||||
title: {
|
||||
text: Site_Name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const { navigation, Site_Name } = this.props;
|
||||
navigation.navigate('RegisterView', { title: Site_Name });
|
||||
}
|
||||
|
||||
transitionServicesTo = (height) => {
|
||||
|
@ -428,6 +362,7 @@ export default class LoginSignupView extends LoggedView {
|
|||
render() {
|
||||
return (
|
||||
<ScrollView style={[sharedStyles.containerScrollView, sharedStyles.container, styles.container]} {...scrollPersistTaps}>
|
||||
<StatusBar />
|
||||
<SafeAreaView testID='welcome-view' forceInset={{ bottom: 'never' }} style={styles.safeArea}>
|
||||
{this.renderServices()}
|
||||
{this.renderServicesSeparator()}
|
||||
|
|
|
@ -5,10 +5,9 @@ import {
|
|||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { Answers } from 'react-native-fabric';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import KeyboardView from '../presentation/KeyboardView';
|
||||
import TextInput from '../containers/TextInput';
|
||||
import Button from '../containers/Button';
|
||||
|
@ -16,9 +15,9 @@ import sharedStyles from './Styles';
|
|||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
import LoggedView from './View';
|
||||
import I18n from '../i18n';
|
||||
import { DARK_HEADER } from '../constants/headerOptions';
|
||||
import { loginRequest as loginRequestAction } from '../actions/login';
|
||||
import Icons from '../lib/Icons';
|
||||
import { LegalButton } from '../containers/HeaderButton';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
buttonsContainer: {
|
||||
|
@ -58,22 +57,16 @@ const styles = StyleSheet.create({
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class LoginView extends LoggedView {
|
||||
static options() {
|
||||
static navigationOptions = ({ navigation }) => {
|
||||
const title = navigation.getParam('title', 'Rocket.Chat');
|
||||
return {
|
||||
...DARK_HEADER,
|
||||
topBar: {
|
||||
...DARK_HEADER.topBar,
|
||||
rightButtons: [{
|
||||
id: 'more',
|
||||
icon: Icons.getSource('more'),
|
||||
testID: 'login-view-more'
|
||||
}]
|
||||
}
|
||||
title,
|
||||
headerRight: <LegalButton navigation={navigation} testID='login-view-more' />
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
loginRequest: PropTypes.func.isRequired,
|
||||
error: PropTypes.object,
|
||||
Site_Name: PropTypes.string,
|
||||
|
@ -91,9 +84,8 @@ export default class LoginView extends LoggedView {
|
|||
code: '',
|
||||
showTOTP: false
|
||||
};
|
||||
Navigation.events().bindComponent(this);
|
||||
const { componentId, Site_Name } = this.props;
|
||||
this.setTitle(componentId, Site_Name);
|
||||
const { Site_Name } = this.props;
|
||||
this.setTitle(Site_Name);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -103,9 +95,9 @@ export default class LoginView extends LoggedView {
|
|||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const { componentId, Site_Name, error } = this.props;
|
||||
const { Site_Name, error } = this.props;
|
||||
if (Site_Name && nextProps.Site_Name !== Site_Name) {
|
||||
this.setTitle(componentId, nextProps.Site_Name);
|
||||
this.setTitle(nextProps.Site_Name);
|
||||
} else if (nextProps.failure && !equal(error, nextProps.error)) {
|
||||
if (nextProps.error && nextProps.error.error === 'totp-required') {
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
|
@ -167,28 +159,9 @@ export default class LoginView extends LoggedView {
|
|||
}
|
||||
}
|
||||
|
||||
setTitle = (componentId, title) => {
|
||||
Navigation.mergeOptions(componentId, {
|
||||
topBar: {
|
||||
title: {
|
||||
text: title
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
navigationButtonPressed = ({ buttonId }) => {
|
||||
if (buttonId === 'more') {
|
||||
Navigation.showModal({
|
||||
stack: {
|
||||
children: [{
|
||||
component: {
|
||||
name: 'LegalView'
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
}
|
||||
setTitle = (title) => {
|
||||
const { navigation } = this.props;
|
||||
navigation.setParams({ title });
|
||||
}
|
||||
|
||||
valid = () => {
|
||||
|
@ -214,35 +187,13 @@ export default class LoginView extends LoggedView {
|
|||
}
|
||||
|
||||
register = () => {
|
||||
const { componentId, Site_Name } = this.props;
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
name: 'RegisterView',
|
||||
options: {
|
||||
topBar: {
|
||||
title: {
|
||||
text: Site_Name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const { navigation, Site_Name } = this.props;
|
||||
navigation.navigate('RegisterView', { title: Site_Name });
|
||||
}
|
||||
|
||||
forgotPassword = () => {
|
||||
const { componentId, Site_Name } = this.props;
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
name: 'ForgotPasswordView',
|
||||
options: {
|
||||
topBar: {
|
||||
title: {
|
||||
text: Site_Name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const { navigation, Site_Name } = this.props;
|
||||
navigation.navigate('ForgotPasswordView', { title: Site_Name });
|
||||
}
|
||||
|
||||
renderTOTP = () => {
|
||||
|
@ -336,6 +287,7 @@ export default class LoginView extends LoggedView {
|
|||
keyboardVerticalOffset={128}
|
||||
key='login-view'
|
||||
>
|
||||
<StatusBar />
|
||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
|
||||
{!showTOTP ? this.renderUserForm() : null}
|
||||
{showTOTP ? this.renderTOTP() : null}
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { FlatList, View, Text } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import LoggedView from '../View';
|
||||
|
@ -11,6 +11,7 @@ import Message from '../../containers/message/Message';
|
|||
import RCActivityIndicator from '../../containers/ActivityIndicator';
|
||||
import I18n from '../../i18n';
|
||||
import RocketChat from '../../lib/rocketchat';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
|
||||
@connect(state => ({
|
||||
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
|
||||
|
@ -24,14 +25,8 @@ import RocketChat from '../../lib/rocketchat';
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class MentionedMessagesView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Mentions')
|
||||
}
|
||||
}
|
||||
};
|
||||
static navigationOptions = {
|
||||
title: I18n.t('Mentions')
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
|
@ -42,7 +37,7 @@ export default class MentionedMessagesView extends LoggedView {
|
|||
}
|
||||
|
||||
constructor(props) {
|
||||
super('StarredMessagesView', props);
|
||||
super('MentionedMessagesView', props);
|
||||
this.state = {
|
||||
loading: false,
|
||||
messages: []
|
||||
|
@ -130,6 +125,7 @@ export default class MentionedMessagesView extends LoggedView {
|
|||
|
||||
return (
|
||||
<SafeAreaView style={styles.list} testID='mentioned-messages-view' forceInset={{ bottom: 'never' }}>
|
||||
<StatusBar />
|
||||
<FlatList
|
||||
data={messages}
|
||||
renderItem={this.renderItem}
|
||||
|
|
|
@ -4,10 +4,9 @@ import {
|
|||
View, StyleSheet, FlatList, Text
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import database from '../lib/realm';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import UserItem from '../presentation/UserItem';
|
||||
|
@ -16,9 +15,11 @@ import LoggedView from './View';
|
|||
import sharedStyles from './Styles';
|
||||
import I18n from '../i18n';
|
||||
import Touch from '../utils/touch';
|
||||
import { isIOS, isAndroid } from '../utils/deviceInfo';
|
||||
import { isIOS } from '../utils/deviceInfo';
|
||||
import SearchBox from '../containers/SearchBox';
|
||||
import Icons, { CustomIcon } from '../lib/Icons';
|
||||
import { CustomIcon } from '../lib/Icons';
|
||||
import { CloseModalButton } from '../containers/HeaderButton';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
safeAreaView: {
|
||||
|
@ -56,22 +57,14 @@ const styles = StyleSheet.create({
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class NewMessageView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
topBar: {
|
||||
leftButtons: [{
|
||||
id: 'cancel',
|
||||
icon: isAndroid ? Icons.getSource('close') : undefined,
|
||||
text: isIOS ? I18n.t('Cancel') : undefined
|
||||
}]
|
||||
}
|
||||
};
|
||||
}
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
headerLeft: <CloseModalButton navigation={navigation} testID='new-message-view-close' />,
|
||||
title: I18n.t('New_Message')
|
||||
})
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
baseUrl: PropTypes.string,
|
||||
onPressItem: PropTypes.func.isRequired,
|
||||
user: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
token: PropTypes.string
|
||||
|
@ -85,7 +78,6 @@ export default class NewMessageView extends LoggedView {
|
|||
search: []
|
||||
};
|
||||
this.data.addListener(this.updateState);
|
||||
Navigation.events().bindComponent(this);
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
|
@ -105,21 +97,15 @@ export default class NewMessageView extends LoggedView {
|
|||
this.search(text);
|
||||
}
|
||||
|
||||
onPressItem = async(item) => {
|
||||
const { onPressItem } = this.props;
|
||||
await this.dismiss();
|
||||
onPressItem = (item) => {
|
||||
const { navigation } = this.props;
|
||||
const onPressItem = navigation.getParam('onPressItem', () => {});
|
||||
onPressItem(item);
|
||||
}
|
||||
|
||||
navigationButtonPressed = ({ buttonId }) => {
|
||||
if (buttonId === 'cancel') {
|
||||
this.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
dismiss = () => {
|
||||
const { componentId } = this.props;
|
||||
return Navigation.dismissModal(componentId);
|
||||
const { navigation } = this.props;
|
||||
return navigation.pop();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
|
@ -135,22 +121,8 @@ export default class NewMessageView extends LoggedView {
|
|||
}
|
||||
|
||||
createChannel = () => {
|
||||
const { componentId } = this.props;
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
name: 'SelectedUsersView',
|
||||
passProps: {
|
||||
nextAction: 'CREATE_CHANNEL'
|
||||
},
|
||||
options: {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Select_Users')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const { navigation } = this.props;
|
||||
navigation.navigate('SelectedUsersViewCreateChannel', { nextActionID: 'CREATE_CHANNEL', title: I18n.t('Select_Users') });
|
||||
}
|
||||
|
||||
renderHeader = () => (
|
||||
|
@ -211,6 +183,7 @@ export default class NewMessageView extends LoggedView {
|
|||
|
||||
render = () => (
|
||||
<SafeAreaView style={styles.safeAreaView} testID='new-message-view' forceInset={{ bottom: 'never' }}>
|
||||
<StatusBar />
|
||||
{this.renderList()}
|
||||
</SafeAreaView>
|
||||
);
|
||||
|
|
|
@ -4,9 +4,8 @@ import {
|
|||
Text, ScrollView, Keyboard, Image, StyleSheet, TouchableOpacity
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import { serverRequest } from '../actions/server';
|
||||
import sharedStyles from './Styles';
|
||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
|
@ -17,8 +16,9 @@ import I18n from '../i18n';
|
|||
import { verticalScale, moderateScale } from '../utils/scaling';
|
||||
import KeyboardView from '../presentation/KeyboardView';
|
||||
import { isIOS, isNotch } from '../utils/deviceInfo';
|
||||
import { LIGHT_HEADER } from '../constants/headerOptions';
|
||||
// import { LIGHT_HEADER } from '../constants/headerOptions';
|
||||
import { CustomIcon } from '../lib/Icons';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
image: {
|
||||
|
@ -64,18 +64,12 @@ const defaultServer = 'https://open.rocket.chat';
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class NewServerView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
...LIGHT_HEADER,
|
||||
topBar: {
|
||||
visible: false,
|
||||
drawBehind: true
|
||||
}
|
||||
};
|
||||
}
|
||||
static navigationOptions = () => ({
|
||||
header: null
|
||||
})
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
server: PropTypes.string,
|
||||
connecting: PropTypes.bool.isRequired,
|
||||
connectServer: PropTypes.func.isRequired
|
||||
|
@ -86,11 +80,11 @@ export default class NewServerView extends LoggedView {
|
|||
this.state = {
|
||||
text: ''
|
||||
};
|
||||
Navigation.events().bindComponent(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { server, connectServer } = this.props;
|
||||
const { navigation, connectServer } = this.props;
|
||||
const server = navigation.getParam('server');
|
||||
if (server) {
|
||||
connectServer(server);
|
||||
this.setState({ text: server });
|
||||
|
@ -153,7 +147,7 @@ export default class NewServerView extends LoggedView {
|
|||
}
|
||||
|
||||
renderBack = () => {
|
||||
const { componentId } = this.props;
|
||||
const { navigation } = this.props;
|
||||
|
||||
let top = 15;
|
||||
if (isIOS) {
|
||||
|
@ -163,7 +157,7 @@ export default class NewServerView extends LoggedView {
|
|||
return (
|
||||
<TouchableOpacity
|
||||
style={[styles.backButton, { top }]}
|
||||
onPress={() => Navigation.pop(componentId)}
|
||||
onPress={() => navigation.pop()}
|
||||
>
|
||||
<CustomIcon
|
||||
name='back'
|
||||
|
@ -183,6 +177,7 @@ export default class NewServerView extends LoggedView {
|
|||
keyboardVerticalOffset={128}
|
||||
key='login-view'
|
||||
>
|
||||
<StatusBar light />
|
||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
|
||||
<SafeAreaView style={sharedStyles.container} testID='new-server-view' forceInset={{ bottom: 'never' }}>
|
||||
<Image style={styles.image} source={{ uri: 'new_server' }} />
|
||||
|
|
|
@ -3,12 +3,10 @@ import PropTypes from 'prop-types';
|
|||
import { WebView } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import I18n from '../i18n';
|
||||
import { DARK_HEADER } from '../constants/headerOptions';
|
||||
import { isIOS, isAndroid } from '../utils/deviceInfo';
|
||||
import Icons from '../lib/Icons';
|
||||
import { isIOS } from '../utils/deviceInfo';
|
||||
import { CloseModalButton } from '../containers/HeaderButton';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
|
||||
const userAgentAndroid = 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1';
|
||||
const userAgent = isIOS ? 'UserAgent' : userAgentAndroid;
|
||||
|
@ -17,23 +15,13 @@ const userAgent = isIOS ? 'UserAgent' : userAgentAndroid;
|
|||
server: state.server.server
|
||||
}))
|
||||
export default class OAuthView extends React.PureComponent {
|
||||
static options() {
|
||||
return {
|
||||
...DARK_HEADER,
|
||||
topBar: {
|
||||
...DARK_HEADER.topBar,
|
||||
leftButtons: [{
|
||||
id: 'cancel',
|
||||
icon: isAndroid ? Icons.getSource('close') : undefined,
|
||||
text: isIOS ? I18n.t('Cancel') : undefined
|
||||
}]
|
||||
}
|
||||
};
|
||||
}
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
headerLeft: <CloseModalButton navigation={navigation} />,
|
||||
title: 'OAuth'
|
||||
})
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
oAuthUrl: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
server: PropTypes.string
|
||||
}
|
||||
|
||||
|
@ -43,18 +31,11 @@ export default class OAuthView extends React.PureComponent {
|
|||
logging: false
|
||||
};
|
||||
this.redirectRegex = new RegExp(`(?=.*(${ props.server }))(?=.*(credentialToken))(?=.*(credentialSecret))`, 'g');
|
||||
Navigation.events().bindComponent(this);
|
||||
}
|
||||
|
||||
navigationButtonPressed = ({ buttonId }) => {
|
||||
if (buttonId === 'cancel') {
|
||||
this.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
dismiss = () => {
|
||||
const { componentId } = this.props;
|
||||
Navigation.dismissModal(componentId);
|
||||
const { navigation } = this.props;
|
||||
navigation.pop();
|
||||
}
|
||||
|
||||
login = async(params) => {
|
||||
|
@ -75,20 +56,24 @@ export default class OAuthView extends React.PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { oAuthUrl } = this.props;
|
||||
const { navigation } = this.props;
|
||||
const oAuthUrl = navigation.getParam('oAuthUrl');
|
||||
return (
|
||||
<WebView
|
||||
source={{ uri: oAuthUrl }}
|
||||
userAgent={userAgent}
|
||||
onNavigationStateChange={(webViewState) => {
|
||||
const url = decodeURIComponent(webViewState.url);
|
||||
if (this.redirectRegex.test(url)) {
|
||||
const parts = url.split('#');
|
||||
const credentials = JSON.parse(parts[1]);
|
||||
this.login({ oauth: { ...credentials } });
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<React.Fragment>
|
||||
<StatusBar />
|
||||
<WebView
|
||||
source={{ uri: oAuthUrl }}
|
||||
userAgent={userAgent}
|
||||
onNavigationStateChange={(webViewState) => {
|
||||
const url = decodeURIComponent(webViewState.url);
|
||||
if (this.redirectRegex.test(url)) {
|
||||
const parts = url.split('#');
|
||||
const credentials = JSON.parse(parts[1]);
|
||||
this.login({ oauth: { ...credentials } });
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,8 @@ import {
|
|||
} from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import Orientation from 'react-native-orientation-locker';
|
||||
|
||||
import { selectServerRequest, serverInitAdd, serverFinishAdd } from '../../actions/server';
|
||||
import { appStart as appStartAction } from '../../actions';
|
||||
|
@ -15,9 +16,8 @@ import styles from './styles';
|
|||
import LoggedView from '../View';
|
||||
import { isIOS, isNotch } from '../../utils/deviceInfo';
|
||||
import EventEmitter from '../../utils/events';
|
||||
import { LIGHT_HEADER } from '../../constants/headerOptions';
|
||||
import Navigation from '../../lib/Navigation';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
|
||||
@connect(state => ({
|
||||
currentServer: state.server.server,
|
||||
|
@ -26,23 +26,16 @@ import { CustomIcon } from '../../lib/Icons';
|
|||
initAdd: () => dispatch(serverInitAdd()),
|
||||
finishAdd: () => dispatch(serverFinishAdd()),
|
||||
selectServer: server => dispatch(selectServerRequest(server)),
|
||||
appStart: () => dispatch(appStartAction())
|
||||
appStart: root => dispatch(appStartAction(root))
|
||||
}))
|
||||
/** @extends React.Component */
|
||||
export default class OnboardingView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
...LIGHT_HEADER,
|
||||
topBar: {
|
||||
visible: false,
|
||||
drawBehind: true
|
||||
}
|
||||
};
|
||||
}
|
||||
static navigationOptions = () => ({
|
||||
header: null
|
||||
})
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
previousServer: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
adding: PropTypes.bool,
|
||||
selectServer: PropTypes.func.isRequired,
|
||||
currentServer: PropTypes.string,
|
||||
|
@ -54,11 +47,13 @@ export default class OnboardingView extends LoggedView {
|
|||
constructor(props) {
|
||||
super('OnboardingView', props);
|
||||
BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
|
||||
this.previousServer = props.navigation.getParam('previousServer');
|
||||
Orientation.lockToPortrait();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { previousServer, initAdd } = this.props;
|
||||
if (previousServer) {
|
||||
const { initAdd } = this.props;
|
||||
if (this.previousServer) {
|
||||
initAdd();
|
||||
}
|
||||
EventEmitter.addEventListener('NewServer', this.handleNewServerEvent);
|
||||
|
@ -70,11 +65,11 @@ export default class OnboardingView extends LoggedView {
|
|||
|
||||
componentWillUnmount() {
|
||||
const {
|
||||
selectServer, previousServer, currentServer, adding, finishAdd
|
||||
selectServer, currentServer, adding, finishAdd
|
||||
} = this.props;
|
||||
if (adding) {
|
||||
if (previousServer !== currentServer) {
|
||||
selectServer(previousServer);
|
||||
if (this.previousServer !== currentServer) {
|
||||
selectServer(this.previousServer);
|
||||
}
|
||||
finishAdd();
|
||||
}
|
||||
|
@ -89,26 +84,13 @@ export default class OnboardingView extends LoggedView {
|
|||
}
|
||||
|
||||
close = () => {
|
||||
const { componentId } = this.props;
|
||||
Navigation.dismissModal(componentId);
|
||||
const { appStart } = this.props;
|
||||
appStart('inside');
|
||||
}
|
||||
|
||||
newServer = (server) => {
|
||||
const { componentId } = this.props;
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
id: 'NewServerView',
|
||||
name: 'NewServerView',
|
||||
passProps: {
|
||||
server
|
||||
},
|
||||
options: {
|
||||
topBar: {
|
||||
visible: false
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const { navigation } = this.props;
|
||||
navigation.navigate('NewServerView', { server });
|
||||
}
|
||||
|
||||
handleNewServerEvent = (event) => {
|
||||
|
@ -129,9 +111,7 @@ export default class OnboardingView extends LoggedView {
|
|||
}
|
||||
|
||||
renderClose = () => {
|
||||
const { previousServer } = this.props;
|
||||
|
||||
if (previousServer) {
|
||||
if (this.previousServer) {
|
||||
let top = 15;
|
||||
if (isIOS) {
|
||||
top = isNotch ? 45 : 30;
|
||||
|
@ -156,6 +136,7 @@ export default class OnboardingView extends LoggedView {
|
|||
render() {
|
||||
return (
|
||||
<SafeAreaView style={styles.container} testID='onboarding-view' forceInset={{ bottom: 'never' }}>
|
||||
<StatusBar light />
|
||||
<Image style={styles.onboarding} source={{ uri: 'onboarding' }} fadeDuration={0} />
|
||||
<Text style={styles.title}>{I18n.t('Welcome_to_RocketChat')}</Text>
|
||||
<Text style={styles.subtitle}>{I18n.t('Open_Source_Communication')}</Text>
|
||||
|
|
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
|||
import { FlatList, View, Text } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import ActionSheet from 'react-native-action-sheet';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import LoggedView from '../View';
|
||||
|
@ -12,6 +12,7 @@ import Message from '../../containers/message/Message';
|
|||
import RCActivityIndicator from '../../containers/ActivityIndicator';
|
||||
import I18n from '../../i18n';
|
||||
import RocketChat from '../../lib/rocketchat';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
|
||||
const PIN_INDEX = 0;
|
||||
const CANCEL_INDEX = 1;
|
||||
|
@ -29,14 +30,8 @@ const options = [I18n.t('Unpin'), I18n.t('Cancel')];
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class PinnedMessagesView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Pinned')
|
||||
}
|
||||
}
|
||||
};
|
||||
static navigationOptions = {
|
||||
title: I18n.t('Pinned')
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
|
@ -169,6 +164,7 @@ export default class PinnedMessagesView extends LoggedView {
|
|||
|
||||
return (
|
||||
<SafeAreaView style={styles.list} testID='pinned-messages-view' forceInset={{ bottom: 'never' }}>
|
||||
<StatusBar />
|
||||
<FlatList
|
||||
data={messages}
|
||||
renderItem={this.renderItem}
|
||||
|
|
|
@ -2,29 +2,20 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { WebView } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
|
||||
import styles from './Styles';
|
||||
import LoggedView from './View';
|
||||
import { DARK_HEADER } from '../constants/headerOptions';
|
||||
import I18n from '../i18n';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
|
||||
@connect(state => ({
|
||||
privacyPolicy: state.settings.Layout_Privacy_Policy
|
||||
}))
|
||||
/** @extends React.Component */
|
||||
export default class PrivacyPolicyView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
...DARK_HEADER,
|
||||
topBar: {
|
||||
...DARK_HEADER.topBar,
|
||||
title: {
|
||||
...DARK_HEADER.topBar.title,
|
||||
text: I18n.t('Privacy_Policy')
|
||||
}
|
||||
}
|
||||
};
|
||||
static navigationOptions = {
|
||||
title: I18n.t('Privacy_Policy')
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
|
@ -40,6 +31,7 @@ export default class PrivacyPolicyView extends LoggedView {
|
|||
|
||||
return (
|
||||
<SafeAreaView style={styles.container} testID='privacy-view'>
|
||||
<StatusBar />
|
||||
<WebView originWhitelist={['*']} source={{ html: privacyPolicy, baseUrl: '' }} />
|
||||
</SafeAreaView>
|
||||
);
|
||||
|
|
|
@ -6,7 +6,7 @@ import Dialog from 'react-native-dialog';
|
|||
import SHA256 from 'js-sha256';
|
||||
import ImagePicker from 'react-native-image-crop-picker';
|
||||
import RNPickerSelect from 'react-native-picker-select';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import LoggedView from '../View';
|
||||
|
@ -24,6 +24,8 @@ import Avatar from '../../containers/Avatar';
|
|||
import Touch from '../../utils/touch';
|
||||
import { setUser as setUserAction } from '../../actions/login';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
import { DrawerButton } from '../../containers/HeaderButton';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
|
||||
@connect(state => ({
|
||||
user: {
|
||||
|
@ -41,15 +43,10 @@ import { CustomIcon } from '../../lib/Icons';
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class ProfileView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Profile')
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
headerLeft: <DrawerButton navigation={navigation} />,
|
||||
title: I18n.t('Profile')
|
||||
})
|
||||
|
||||
static propTypes = {
|
||||
baseUrl: PropTypes.string,
|
||||
|
@ -388,6 +385,7 @@ export default class ProfileView extends LoggedView {
|
|||
contentContainerStyle={sharedStyles.container}
|
||||
keyboardVerticalOffset={128}
|
||||
>
|
||||
<StatusBar />
|
||||
<ScrollView
|
||||
contentContainerStyle={sharedStyles.containerScrollView}
|
||||
testID='profile-view-list'
|
||||
|
|
|
@ -4,9 +4,8 @@ import {
|
|||
Keyboard, Text, ScrollView, Alert
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import TextInput from '../containers/TextInput';
|
||||
import Button from '../containers/Button';
|
||||
import KeyboardView from '../presentation/KeyboardView';
|
||||
|
@ -14,11 +13,11 @@ import sharedStyles from './Styles';
|
|||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
import LoggedView from './View';
|
||||
import I18n from '../i18n';
|
||||
import { DARK_HEADER } from '../constants/headerOptions';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import { loginRequest as loginRequestAction } from '../actions/login';
|
||||
import isValidEmail from '../utils/isValidEmail';
|
||||
import Icons from '../lib/Icons';
|
||||
import { LegalButton } from '../containers/HeaderButton';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
|
||||
const shouldUpdateState = ['name', 'email', 'password', 'username', 'saving'];
|
||||
|
||||
|
@ -27,22 +26,16 @@ const shouldUpdateState = ['name', 'email', 'password', 'username', 'saving'];
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class RegisterView extends LoggedView {
|
||||
static options() {
|
||||
static navigationOptions = ({ navigation }) => {
|
||||
const title = navigation.getParam('title', 'Rocket.Chat');
|
||||
return {
|
||||
...DARK_HEADER,
|
||||
topBar: {
|
||||
...DARK_HEADER.topBar,
|
||||
rightButtons: [{
|
||||
id: 'more',
|
||||
icon: Icons.getSource('more'),
|
||||
testID: 'register-view-more'
|
||||
}]
|
||||
}
|
||||
title,
|
||||
headerRight: <LegalButton testID='register-view-more' navigation={navigation} />
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
loginRequest: PropTypes.func,
|
||||
Site_Name: PropTypes.string
|
||||
}
|
||||
|
@ -56,7 +49,6 @@ export default class RegisterView extends LoggedView {
|
|||
username: '',
|
||||
saving: false
|
||||
};
|
||||
Navigation.events().bindComponent(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -71,9 +63,9 @@ export default class RegisterView extends LoggedView {
|
|||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { componentId, Site_Name } = this.props;
|
||||
const { Site_Name } = this.props;
|
||||
if (Site_Name && prevProps.Site_Name !== Site_Name) {
|
||||
this.setTitle(componentId, Site_Name);
|
||||
this.setTitle(Site_Name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,28 +75,9 @@ export default class RegisterView extends LoggedView {
|
|||
}
|
||||
}
|
||||
|
||||
setTitle = (componentId, title) => {
|
||||
Navigation.mergeOptions(componentId, {
|
||||
topBar: {
|
||||
title: {
|
||||
text: title
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
navigationButtonPressed = ({ buttonId }) => {
|
||||
if (buttonId === 'more') {
|
||||
Navigation.showModal({
|
||||
stack: {
|
||||
children: [{
|
||||
component: {
|
||||
name: 'LegalView'
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
}
|
||||
setTitle = (title) => {
|
||||
const { navigation } = this.props;
|
||||
navigation.setParams({ title });
|
||||
}
|
||||
|
||||
valid = () => {
|
||||
|
@ -137,42 +110,11 @@ export default class RegisterView extends LoggedView {
|
|||
this.setState({ saving: false });
|
||||
}
|
||||
|
||||
termsService = () => {
|
||||
const { componentId } = this.props;
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
name: 'TermsServiceView',
|
||||
options: {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Terms_of_Service')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
privacyPolicy = () => {
|
||||
const { componentId } = this.props;
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
name: 'PrivacyPolicyView',
|
||||
options: {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Privacy_Policy')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { saving } = this.state;
|
||||
return (
|
||||
<KeyboardView contentContainerStyle={sharedStyles.container}>
|
||||
<StatusBar />
|
||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
|
||||
<SafeAreaView style={sharedStyles.container} testID='register-view' forceInset={{ bottom: 'never' }}>
|
||||
<Text style={[sharedStyles.loginTitle, sharedStyles.textBold]}>{I18n.t('Sign_Up')}</Text>
|
||||
|
|
|
@ -4,10 +4,9 @@ import {
|
|||
View, SectionList, Text, Alert
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import Navigation from '../../lib/Navigation';
|
||||
import { leaveRoom as leaveRoomAction } from '../../actions/room';
|
||||
import LoggedView from '../View';
|
||||
import styles from './styles';
|
||||
|
@ -23,6 +22,7 @@ import I18n from '../../i18n';
|
|||
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
import DisclosureIndicator from '../../containers/DisclosureIndicator';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
|
||||
const renderSeparator = () => <View style={styles.separator} />;
|
||||
|
||||
|
@ -38,20 +38,13 @@ const renderSeparator = () => <View style={styles.separator} />;
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class RoomActionsView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Actions')
|
||||
}
|
||||
}
|
||||
};
|
||||
static navigationOptions = {
|
||||
title: I18n.t('Actions')
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
baseUrl: PropTypes.string,
|
||||
rid: PropTypes.string,
|
||||
componentId: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
user: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
token: PropTypes.string
|
||||
|
@ -62,10 +55,10 @@ export default class RoomActionsView extends LoggedView {
|
|||
|
||||
constructor(props) {
|
||||
super('RoomActionsView', props);
|
||||
const { rid, room } = props;
|
||||
this.rooms = database.objects('subscriptions').filtered('rid = $0', rid);
|
||||
this.rid = props.navigation.getParam('rid');
|
||||
this.rooms = database.objects('subscriptions').filtered('rid = $0', this.rid);
|
||||
this.state = {
|
||||
room,
|
||||
room: this.rooms[0] || props.room,
|
||||
membersCount: 0,
|
||||
member: {},
|
||||
joined: false,
|
||||
|
@ -76,9 +69,8 @@ export default class RoomActionsView extends LoggedView {
|
|||
async componentDidMount() {
|
||||
const { room } = this.state;
|
||||
if (room && room.t !== 'd' && this.canViewMembers) {
|
||||
const { rid } = this.props;
|
||||
try {
|
||||
const counters = await RocketChat.getRoomCounters(rid, room.t);
|
||||
const counters = await RocketChat.getRoomCounters(room.rid, room.t);
|
||||
if (counters.success) {
|
||||
this.setState({ membersCount: counters.members, joined: counters.joined });
|
||||
}
|
||||
|
@ -119,14 +111,8 @@ export default class RoomActionsView extends LoggedView {
|
|||
|
||||
onPressTouchable = (item) => {
|
||||
if (item.route) {
|
||||
const { componentId } = this.props;
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
name: item.route,
|
||||
passProps: item.params,
|
||||
options: item.navigationOptions
|
||||
}
|
||||
});
|
||||
const { navigation } = this.props;
|
||||
navigation.navigate(item.route, item.params);
|
||||
}
|
||||
if (item.event) {
|
||||
return item.event();
|
||||
|
@ -181,7 +167,7 @@ export default class RoomActionsView extends LoggedView {
|
|||
const notificationsAction = {
|
||||
icon: notifications ? 'bell' : 'Bell-off',
|
||||
name: I18n.t(`${ notifications ? 'Enable' : 'Disable' }_notifications`),
|
||||
event: () => this.toggleNotifications(),
|
||||
event: this.toggleNotifications,
|
||||
testID: 'room-actions-notifications'
|
||||
};
|
||||
|
||||
|
@ -248,13 +234,6 @@ export default class RoomActionsView extends LoggedView {
|
|||
name: I18n.t('Pinned'),
|
||||
route: 'PinnedMessagesView',
|
||||
testID: 'room-actions-pinned'
|
||||
},
|
||||
{
|
||||
icon: 'code',
|
||||
name: I18n.t('Snippets'),
|
||||
route: 'SnippetedMessagesView',
|
||||
params: { rid },
|
||||
testID: 'room-actions-snippeted'
|
||||
}
|
||||
],
|
||||
renderItem: this.renderItem
|
||||
|
@ -267,7 +246,7 @@ export default class RoomActionsView extends LoggedView {
|
|||
icon: 'ban',
|
||||
name: I18n.t(`${ blocker ? 'Unblock' : 'Block' }_user`),
|
||||
type: 'danger',
|
||||
event: () => this.toggleBlockUser(),
|
||||
event: this.toggleBlockUser,
|
||||
testID: 'room-actions-block-user'
|
||||
}
|
||||
],
|
||||
|
@ -294,15 +273,9 @@ export default class RoomActionsView extends LoggedView {
|
|||
name: I18n.t('Add_user'),
|
||||
route: 'SelectedUsersView',
|
||||
params: {
|
||||
nextAction: 'ADD_USER',
|
||||
rid
|
||||
},
|
||||
navigationOptions: {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Add_user')
|
||||
}
|
||||
}
|
||||
nextActionID: 'ADD_USER',
|
||||
rid,
|
||||
title: I18n.t('Add_user')
|
||||
},
|
||||
testID: 'room-actions-add-user'
|
||||
});
|
||||
|
@ -317,7 +290,7 @@ export default class RoomActionsView extends LoggedView {
|
|||
icon: 'sign-out',
|
||||
name: I18n.t('Leave_channel'),
|
||||
type: 'danger',
|
||||
event: () => this.leaveChannel(),
|
||||
event: this.leaveChannel,
|
||||
testID: 'room-actions-leave-channel'
|
||||
}
|
||||
],
|
||||
|
@ -468,6 +441,7 @@ export default class RoomActionsView extends LoggedView {
|
|||
render() {
|
||||
return (
|
||||
<SafeAreaView style={styles.container} testID='room-actions-view' forceInset={{ bottom: 'never' }}>
|
||||
<StatusBar />
|
||||
<SectionList
|
||||
style={styles.container}
|
||||
stickySectionHeadersEnabled={false}
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { FlatList, View, Text } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import LoggedView from '../View';
|
||||
|
@ -11,6 +11,7 @@ import Message from '../../containers/message/Message';
|
|||
import RCActivityIndicator from '../../containers/ActivityIndicator';
|
||||
import I18n from '../../i18n';
|
||||
import RocketChat from '../../lib/rocketchat';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
|
||||
@connect(state => ({
|
||||
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
|
||||
|
@ -24,14 +25,8 @@ import RocketChat from '../../lib/rocketchat';
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class RoomFilesView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Files')
|
||||
}
|
||||
}
|
||||
};
|
||||
static navigationOptions = {
|
||||
title: I18n.t('Files')
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
|
@ -142,6 +137,7 @@ export default class RoomFilesView extends LoggedView {
|
|||
|
||||
return (
|
||||
<SafeAreaView style={styles.list} testID='room-files-view' forceInset={{ bottom: 'never' }}>
|
||||
<StatusBar />
|
||||
<FlatList
|
||||
data={messages}
|
||||
renderItem={this.renderItem}
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
Text, View, ScrollView, TouchableOpacity, Keyboard, Alert
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import { eraseRoom as eraseRoomAction } from '../../actions/room';
|
||||
|
@ -22,6 +22,7 @@ import SwitchContainer from './SwitchContainer';
|
|||
import random from '../../utils/random';
|
||||
import log from '../../utils/log';
|
||||
import I18n from '../../i18n';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
|
||||
const PERMISSION_SET_READONLY = 'set-readonly';
|
||||
const PERMISSION_SET_REACT_WHEN_READONLY = 'set-react-when-readonly';
|
||||
|
@ -43,24 +44,18 @@ const PERMISSIONS_ARRAY = [
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class RoomInfoEditView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Room_Info_Edit')
|
||||
}
|
||||
}
|
||||
};
|
||||
static navigationOptions = {
|
||||
title: I18n.t('Room_Info_Edit')
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
rid: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
eraseRoom: PropTypes.func
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super('RoomInfoEditView', props);
|
||||
const { rid } = props;
|
||||
const rid = props.navigation.getParam('rid');
|
||||
this.rooms = database.objects('subscriptions').filtered('rid = $0', rid);
|
||||
this.permissions = {};
|
||||
this.state = {
|
||||
|
@ -298,6 +293,7 @@ export default class RoomInfoEditView extends LoggedView {
|
|||
contentContainerStyle={sharedStyles.container}
|
||||
keyboardVerticalOffset={128}
|
||||
>
|
||||
<StatusBar />
|
||||
<ScrollView
|
||||
contentContainerStyle={sharedStyles.containerScrollView}
|
||||
testID='room-info-edit-view-list'
|
||||
|
|
|
@ -3,10 +3,9 @@ import PropTypes from 'prop-types';
|
|||
import { View, Text, ScrollView } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import moment from 'moment';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import Navigation from '../../lib/Navigation';
|
||||
import LoggedView from '../View';
|
||||
import Status from '../../containers/Status';
|
||||
import Avatar from '../../containers/Avatar';
|
||||
|
@ -17,7 +16,8 @@ import RocketChat from '../../lib/rocketchat';
|
|||
import log from '../../utils/log';
|
||||
import RoomTypeIcon from '../../containers/RoomTypeIcon';
|
||||
import I18n from '../../i18n';
|
||||
import Icons from '../../lib/Icons';
|
||||
import { CustomHeaderButtons, Item } from '../../containers/HeaderButton';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
|
||||
const PERMISSION_EDIT_ROOM = 'edit-room';
|
||||
|
||||
|
@ -45,19 +45,23 @@ const getRoomTitle = room => (room.t === 'd'
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class RoomInfoView extends LoggedView {
|
||||
static options() {
|
||||
static navigationOptions = ({ navigation }) => {
|
||||
const showEdit = navigation.getParam('showEdit');
|
||||
const rid = navigation.getParam('rid');
|
||||
return {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Room_Info')
|
||||
}
|
||||
}
|
||||
title: I18n.t('Room_Info'),
|
||||
headerRight: showEdit
|
||||
? (
|
||||
<CustomHeaderButtons>
|
||||
<Item iconName='edit' onPress={() => navigation.navigate('RoomInfoEditView', { rid })} testID='room-info-view-edit-button' />
|
||||
</CustomHeaderButtons>
|
||||
)
|
||||
: null
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
rid: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
user: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
token: PropTypes.string
|
||||
|
@ -65,46 +69,30 @@ export default class RoomInfoView extends LoggedView {
|
|||
baseUrl: PropTypes.string,
|
||||
activeUsers: PropTypes.object,
|
||||
Message_TimeFormat: PropTypes.string,
|
||||
allRoles: PropTypes.object,
|
||||
room: PropTypes.object
|
||||
allRoles: PropTypes.object
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super('RoomInfoView', props);
|
||||
const { rid, room } = props;
|
||||
const rid = props.navigation.getParam('rid');
|
||||
this.rooms = database.objects('subscriptions').filtered('rid = $0', rid);
|
||||
this.sub = {
|
||||
unsubscribe: () => {}
|
||||
};
|
||||
this.state = {
|
||||
room,
|
||||
room: this.rooms[0] || {},
|
||||
roomUser: {},
|
||||
roles: []
|
||||
};
|
||||
Navigation.events().bindComponent(this);
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
this.rooms.addListener(this.updateRoom);
|
||||
|
||||
let room = {};
|
||||
if (this.rooms.length > 0) {
|
||||
room = this.rooms[0]; // eslint-disable-line prefer-destructuring
|
||||
} else {
|
||||
room = this.state.room; // eslint-disable-line
|
||||
}
|
||||
const { componentId } = this.props;
|
||||
const { room } = this.state;
|
||||
const permissions = RocketChat.hasPermission([PERMISSION_EDIT_ROOM], room.rid);
|
||||
if (permissions[PERMISSION_EDIT_ROOM]) {
|
||||
Navigation.mergeOptions(componentId, {
|
||||
topBar: {
|
||||
rightButtons: [{
|
||||
id: 'edit',
|
||||
icon: Icons.getSource('edit'),
|
||||
testID: 'room-info-view-edit-button'
|
||||
}]
|
||||
}
|
||||
});
|
||||
const { navigation } = this.props;
|
||||
navigation.setParams({ showEdit: true });
|
||||
}
|
||||
|
||||
// get user of room
|
||||
|
@ -164,21 +152,6 @@ export default class RoomInfoView extends LoggedView {
|
|||
this.sub.unsubscribe();
|
||||
}
|
||||
|
||||
navigationButtonPressed = ({ buttonId }) => {
|
||||
const { rid, componentId } = this.props;
|
||||
if (buttonId === 'edit') {
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
id: 'RoomInfoEditView',
|
||||
name: 'RoomInfoEditView',
|
||||
passProps: {
|
||||
rid
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getFullUserData = async(username) => {
|
||||
try {
|
||||
const result = await RocketChat.subscribe('fullUserData', username);
|
||||
|
@ -312,6 +285,7 @@ export default class RoomInfoView extends LoggedView {
|
|||
}
|
||||
return (
|
||||
<ScrollView style={styles.scroll}>
|
||||
<StatusBar />
|
||||
<SafeAreaView style={styles.container} testID='room-info-view' forceInset={{ bottom: 'never' }}>
|
||||
<View style={styles.avatarContainer}>
|
||||
{this.renderAvatar(room, roomUser)}
|
||||
|
|
|
@ -3,10 +3,9 @@ import PropTypes from 'prop-types';
|
|||
import { FlatList, View } from 'react-native';
|
||||
import ActionSheet from 'react-native-action-sheet';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import Navigation from '../../lib/Navigation';
|
||||
import LoggedView from '../View';
|
||||
import styles from './styles';
|
||||
import UserItem from '../../presentation/UserItem';
|
||||
|
@ -15,11 +14,12 @@ import RocketChat from '../../lib/rocketchat';
|
|||
import database from '../../lib/realm';
|
||||
import { showToast } from '../../utils/info';
|
||||
import log from '../../utils/log';
|
||||
import { isAndroid } from '../../utils/deviceInfo';
|
||||
import { vibrate } from '../../utils/vibration';
|
||||
import I18n from '../../i18n';
|
||||
import SearchBox from '../../containers/SearchBox';
|
||||
import protectedFunction from '../../lib/methods/helpers/protectedFunction';
|
||||
import { CustomHeaderButtons, Item } from '../../containers/HeaderButton';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
|
||||
@connect(state => ({
|
||||
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
|
||||
|
@ -31,24 +31,22 @@ import protectedFunction from '../../lib/methods/helpers/protectedFunction';
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class RoomMembersView extends LoggedView {
|
||||
static options() {
|
||||
static navigationOptions = ({ navigation }) => {
|
||||
const toggleStatus = navigation.getParam('toggleStatus', () => {});
|
||||
const allUsers = navigation.getParam('allUsers');
|
||||
const toggleText = allUsers ? I18n.t('Online') : I18n.t('All');
|
||||
return {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Members')
|
||||
},
|
||||
rightButtons: [{
|
||||
id: 'toggleOnline',
|
||||
text: I18n.t('Online'),
|
||||
testID: 'room-members-view-toggle-status',
|
||||
color: isAndroid ? '#FFF' : undefined
|
||||
}]
|
||||
}
|
||||
title: I18n.t('Members'),
|
||||
headerRight: (
|
||||
<CustomHeaderButtons>
|
||||
<Item title={toggleText} onPress={toggleStatus} testID='room-members-view-toggle-status' />
|
||||
</CustomHeaderButtons>
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
rid: PropTypes.string,
|
||||
members: PropTypes.array,
|
||||
baseUrl: PropTypes.string,
|
||||
|
@ -65,7 +63,7 @@ export default class RoomMembersView extends LoggedView {
|
|||
this.CANCEL_INDEX = 0;
|
||||
this.MUTE_INDEX = 1;
|
||||
this.actionSheetOptions = [''];
|
||||
const { rid, members, room } = props;
|
||||
const { rid, members } = props.navigation.state.params;
|
||||
this.rooms = database.objects('subscriptions').filtered('rid = $0', rid);
|
||||
this.permissions = RocketChat.hasPermission(['mute-user'], rid);
|
||||
this.state = {
|
||||
|
@ -75,15 +73,17 @@ export default class RoomMembersView extends LoggedView {
|
|||
members,
|
||||
membersFiltered: [],
|
||||
userLongPressed: {},
|
||||
room,
|
||||
room: this.rooms[0] || {},
|
||||
options: []
|
||||
};
|
||||
Navigation.events().bindComponent(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchMembers();
|
||||
this.rooms.addListener(this.updateRoom);
|
||||
|
||||
const { navigation } = this.props;
|
||||
navigation.setParams({ toggleStatus: this.toggleStatus });
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
|
@ -128,29 +128,6 @@ export default class RoomMembersView extends LoggedView {
|
|||
this.setState({ filtering: !!text, membersFiltered });
|
||||
})
|
||||
|
||||
navigationButtonPressed = ({ buttonId }) => {
|
||||
const { allUsers } = this.state;
|
||||
const { componentId } = this.props;
|
||||
|
||||
if (buttonId === 'toggleOnline') {
|
||||
try {
|
||||
Navigation.mergeOptions(componentId, {
|
||||
topBar: {
|
||||
rightButtons: [{
|
||||
id: 'toggleOnline',
|
||||
text: allUsers ? I18n.t('Online') : I18n.t('All'),
|
||||
testID: 'room-members-view-toggle-status',
|
||||
color: isAndroid ? '#FFF' : undefined
|
||||
}]
|
||||
}
|
||||
});
|
||||
this.fetchMembers(!allUsers);
|
||||
} catch (e) {
|
||||
log('RoomMembers.onNavigationButtonPressed', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onPressUser = async(item) => {
|
||||
try {
|
||||
const subscriptions = database.objects('subscriptions').filtered('name = $0', item.username);
|
||||
|
@ -187,6 +164,15 @@ export default class RoomMembersView extends LoggedView {
|
|||
this.showActionSheet();
|
||||
}
|
||||
|
||||
toggleStatus = () => {
|
||||
try {
|
||||
const { allUsers } = this.state;
|
||||
this.fetchMembers(!allUsers);
|
||||
} catch (e) {
|
||||
log('RoomMembers.toggleStatus', e);
|
||||
}
|
||||
}
|
||||
|
||||
showActionSheet = () => {
|
||||
ActionSheet.showActionSheetWithOptions({
|
||||
options: this.actionSheetOptions,
|
||||
|
@ -199,9 +185,11 @@ export default class RoomMembersView extends LoggedView {
|
|||
|
||||
fetchMembers = async(status) => {
|
||||
const { rid } = this.state;
|
||||
const { navigation } = this.props;
|
||||
const membersResult = await RocketChat.getRoomMembers(rid, status);
|
||||
const members = membersResult.records;
|
||||
this.setState({ allUsers: status, members });
|
||||
navigation.setParams({ allUsers: status });
|
||||
}
|
||||
|
||||
updateRoom = () => {
|
||||
|
@ -212,16 +200,9 @@ export default class RoomMembersView extends LoggedView {
|
|||
}
|
||||
|
||||
goRoom = async({ rid, name }) => {
|
||||
const { componentId } = this.props;
|
||||
await Navigation.popToRoot(componentId);
|
||||
Navigation.push('RoomsListView', {
|
||||
component: {
|
||||
name: 'RoomView',
|
||||
passProps: {
|
||||
rid, name, t: 'd'
|
||||
}
|
||||
}
|
||||
});
|
||||
const { navigation } = this.props;
|
||||
await navigation.popToTop();
|
||||
navigation.navigate('RoomView', { rid, name, t: 'd' });
|
||||
}
|
||||
|
||||
handleMute = async() => {
|
||||
|
@ -272,6 +253,7 @@ export default class RoomMembersView extends LoggedView {
|
|||
} = this.state;
|
||||
return (
|
||||
<SafeAreaView style={styles.list} testID='room-members-view' forceInset={{ bottom: 'never' }}>
|
||||
<StatusBar />
|
||||
<FlatList
|
||||
data={filtering ? membersFiltered : members}
|
||||
renderItem={this.renderItem}
|
||||
|
|
|
@ -18,9 +18,7 @@ const TITLE_SIZE = 18;
|
|||
const ICON_SIZE = 18;
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
backgroundColor: isIOS ? 'transparent' : '#2F343D'
|
||||
flex: 1
|
||||
},
|
||||
titleContainer: {
|
||||
flexDirection: 'row',
|
||||
|
@ -175,25 +173,16 @@ export default class RoomHeaderView extends Component {
|
|||
window, title, usersTyping
|
||||
} = this.props;
|
||||
const portrait = window.height > window.width;
|
||||
let height = isIOS ? 44 : 60;
|
||||
let scale = 1;
|
||||
|
||||
if (!portrait) {
|
||||
if (isIOS) {
|
||||
height = 32;
|
||||
}
|
||||
if (usersTyping.length > 0) {
|
||||
scale = 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
{ width: window.width - 150, height }
|
||||
]}
|
||||
>
|
||||
<View style={styles.container}>
|
||||
<View style={styles.titleContainer}>
|
||||
{this.renderIcon()}
|
||||
<Text style={[styles.title, { fontSize: TITLE_SIZE * scale }]} numberOfLines={1}>{title}</Text>
|
||||
|
|
|
@ -5,10 +5,9 @@ import {
|
|||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { RectButton } from 'react-native-gesture-handler';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import Navigation from '../../lib/Navigation';
|
||||
import { openRoom as openRoomAction, closeRoom as closeRoomAction, setLastOpen as setLastOpenAction } from '../../actions/room';
|
||||
import { toggleReactionPicker as toggleReactionPickerAction, actionsShow as actionsShowAction } from '../../actions/messages';
|
||||
import LoggedView from '../View';
|
||||
|
@ -25,8 +24,10 @@ import styles from './styles';
|
|||
import log from '../../utils/log';
|
||||
import { isIOS } from '../../utils/deviceInfo';
|
||||
import I18n from '../../i18n';
|
||||
import Icons from '../../lib/Icons';
|
||||
import ConnectionBadge from '../../containers/ConnectionBadge';
|
||||
import { CustomHeaderButtons, Item } from '../../containers/HeaderButton';
|
||||
import RoomHeaderView from './Header';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
|
||||
@connect(state => ({
|
||||
user: {
|
||||
|
@ -47,31 +48,27 @@ import ConnectionBadge from '../../containers/ConnectionBadge';
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class RoomView extends LoggedView {
|
||||
static options() {
|
||||
static navigationOptions = ({ navigation }) => {
|
||||
const rid = navigation.getParam('rid');
|
||||
const t = navigation.getParam('t');
|
||||
const f = navigation.getParam('f');
|
||||
const toggleFav = navigation.getParam('toggleFav', () => {});
|
||||
const starIcon = f ? 'Star-filled' : 'star';
|
||||
return {
|
||||
topBar: {
|
||||
title: {
|
||||
component: {
|
||||
name: 'RoomHeaderView',
|
||||
alignment: 'left'
|
||||
}
|
||||
},
|
||||
rightButtons: [{
|
||||
id: 'more',
|
||||
testID: 'room-view-header-actions',
|
||||
icon: Icons.getSource('more')
|
||||
}, {
|
||||
id: 'star',
|
||||
testID: 'room-view-header-star',
|
||||
icon: Icons.getSource('starOutline')
|
||||
}]
|
||||
},
|
||||
blurOnUnmount: true
|
||||
headerTitle: <RoomHeaderView />,
|
||||
headerRight: t === 'l'
|
||||
? null
|
||||
: (
|
||||
<CustomHeaderButtons>
|
||||
<Item title='star' iconName={starIcon} onPress={toggleFav} testID='room-view-header-star' />
|
||||
<Item title='more' iconName='menu' onPress={() => navigation.navigate('RoomActionsView', { rid })} testID='room-view-header-actions' />
|
||||
</CustomHeaderButtons>
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
openRoom: PropTypes.func.isRequired,
|
||||
setLastOpen: PropTypes.func.isRequired,
|
||||
user: PropTypes.shape({
|
||||
|
@ -79,9 +76,6 @@ export default class RoomView extends LoggedView {
|
|||
username: PropTypes.string.isRequired,
|
||||
token: PropTypes.string.isRequired
|
||||
}),
|
||||
rid: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
t: PropTypes.string,
|
||||
showActions: PropTypes.bool,
|
||||
showErrorActions: PropTypes.bool,
|
||||
actionMessage: PropTypes.object,
|
||||
|
@ -93,7 +87,7 @@ export default class RoomView extends LoggedView {
|
|||
|
||||
constructor(props) {
|
||||
super('RoomView', props);
|
||||
this.rid = props.rid;
|
||||
this.rid = props.navigation.getParam('rid');
|
||||
this.rooms = database.objects('subscriptions').filtered('rid = $0', this.rid);
|
||||
this.state = {
|
||||
loaded: false,
|
||||
|
@ -101,12 +95,14 @@ export default class RoomView extends LoggedView {
|
|||
room: {}
|
||||
};
|
||||
this.onReactionPress = this.onReactionPress.bind(this);
|
||||
Navigation.events().bindComponent(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { navigation } = this.props;
|
||||
navigation.setParams({ toggleFav: this.toggleFav });
|
||||
|
||||
if (this.rooms.length === 0 && this.rid) {
|
||||
const { rid, name, t } = this.props;
|
||||
const { rid, name, t } = navigation.state.params;
|
||||
this.setState(
|
||||
{ room: { rid, name, t } },
|
||||
() => this.updateRoom()
|
||||
|
@ -150,26 +146,10 @@ export default class RoomView extends LoggedView {
|
|||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
const { room } = this.state;
|
||||
const { componentId, appState } = this.props;
|
||||
const { appState, navigation } = this.props;
|
||||
|
||||
if (prevState.room.f !== room.f) {
|
||||
const rightButtons = [{
|
||||
id: 'star',
|
||||
testID: 'room-view-header-star',
|
||||
icon: room.f ? Icons.getSource('star') : Icons.getSource('starOutline')
|
||||
}];
|
||||
if (room.t !== 'l') {
|
||||
rightButtons.unshift({
|
||||
id: 'more',
|
||||
testID: 'room-view-header-actions',
|
||||
icon: Icons.getSource('more')
|
||||
});
|
||||
}
|
||||
Navigation.mergeOptions(componentId, {
|
||||
topBar: {
|
||||
rightButtons
|
||||
}
|
||||
});
|
||||
navigation.setParams({ f: room.f });
|
||||
} else if (appState === 'foreground' && appState !== prevProps.appState) {
|
||||
RocketChat.loadMissedMessages(room).catch(e => console.log(e));
|
||||
RocketChat.readMessages(room.rid).catch(e => console.log(e));
|
||||
|
@ -207,30 +187,6 @@ export default class RoomView extends LoggedView {
|
|||
this.setState(...args);
|
||||
}
|
||||
|
||||
navigationButtonPressed = ({ buttonId }) => {
|
||||
const { room } = this.state;
|
||||
const { rid, f } = room;
|
||||
const { componentId } = this.props;
|
||||
|
||||
if (buttonId === 'more') {
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
id: 'RoomActionsView',
|
||||
name: 'RoomActionsView',
|
||||
passProps: {
|
||||
rid
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (buttonId === 'star') {
|
||||
try {
|
||||
RocketChat.toggleFavorite(rid, !f);
|
||||
} catch (e) {
|
||||
log('toggleFavorite', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
updateRoom = () => {
|
||||
const { openRoom, setLastOpen } = this.props;
|
||||
|
@ -259,6 +215,16 @@ export default class RoomView extends LoggedView {
|
|||
}
|
||||
}
|
||||
|
||||
toggleFav = () => {
|
||||
try {
|
||||
const { room } = this.state;
|
||||
const { rid, f } = room;
|
||||
RocketChat.toggleFavorite(rid, !f);
|
||||
} catch (e) {
|
||||
log('toggleFavorite', e);
|
||||
}
|
||||
}
|
||||
|
||||
sendMessage = (message) => {
|
||||
const { setLastOpen } = this.props;
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
|
@ -268,9 +234,8 @@ export default class RoomView extends LoggedView {
|
|||
};
|
||||
|
||||
joinRoom = async() => {
|
||||
const { rid } = this.props;
|
||||
try {
|
||||
const result = await RocketChat.joinRoom(rid);
|
||||
const result = await RocketChat.joinRoom(this.rid);
|
||||
if (result.success) {
|
||||
this.internalSetState({
|
||||
joined: true
|
||||
|
@ -388,6 +353,7 @@ export default class RoomView extends LoggedView {
|
|||
|
||||
return (
|
||||
<SafeAreaView style={styles.container} testID='room-view' forceInset={{ bottom: 'never' }}>
|
||||
<StatusBar />
|
||||
{this.renderList()}
|
||||
{room._id && showActions
|
||||
? <MessageActions room={room} user={user} />
|
||||
|
|
|
@ -39,7 +39,7 @@ const styles = StyleSheet.create({
|
|||
});
|
||||
|
||||
const Header = ({
|
||||
isFetching, serverName, showServerDropdown, width, setSearchInputRef, showSearchHeader, onSearchChangeText, onPress
|
||||
isFetching, serverName, showServerDropdown, setSearchInputRef, showSearchHeader, onSearchChangeText, onPress
|
||||
}) => {
|
||||
if (showSearchHeader) {
|
||||
return (
|
||||
|
@ -55,7 +55,7 @@ const Header = ({
|
|||
);
|
||||
}
|
||||
return (
|
||||
<View style={[styles.container, { width: width - 150 }]}>
|
||||
<View style={styles.container}>
|
||||
<TouchableOpacity onPress={onPress} testID='rooms-list-header-server-dropdown-button'>
|
||||
{isFetching ? <Text style={styles.updating}>{I18n.t('Updating')}</Text> : null}
|
||||
<View style={styles.button}>
|
||||
|
@ -74,8 +74,7 @@ Header.propTypes = {
|
|||
onSearchChangeText: PropTypes.func.isRequired,
|
||||
setSearchInputRef: PropTypes.func.isRequired,
|
||||
isFetching: PropTypes.bool,
|
||||
serverName: PropTypes.string,
|
||||
width: PropTypes.number
|
||||
serverName: PropTypes.string
|
||||
};
|
||||
|
||||
Header.defaultProps = {
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
import React, { PureComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { responsive } from 'react-native-responsive-ui';
|
||||
|
||||
import {
|
||||
toggleServerDropdown, closeServerDropdown, closeSortDropdown, setSearch as setSearchAction
|
||||
} from '../../../actions/rooms';
|
||||
import Header from './Header';
|
||||
|
||||
@responsive
|
||||
@connect(state => ({
|
||||
showServerDropdown: state.rooms.showServerDropdown,
|
||||
showSortDropdown: state.rooms.showSortDropdown,
|
||||
|
@ -31,8 +29,7 @@ export default class RoomsListHeaderView extends PureComponent {
|
|||
open: PropTypes.func,
|
||||
close: PropTypes.func,
|
||||
closeSort: PropTypes.func,
|
||||
setSearch: PropTypes.func,
|
||||
window: PropTypes.object
|
||||
setSearch: PropTypes.func
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
|
@ -69,10 +66,9 @@ export default class RoomsListHeaderView extends PureComponent {
|
|||
this.searchInputRef = ref;
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const {
|
||||
serverName, showServerDropdown, showSearchHeader, isFetching, window: { width }
|
||||
serverName, showServerDropdown, showSearchHeader, isFetching
|
||||
} = this.props;
|
||||
return (
|
||||
<Header
|
||||
|
@ -80,7 +76,6 @@ export default class RoomsListHeaderView extends PureComponent {
|
|||
showServerDropdown={showServerDropdown}
|
||||
showSearchHeader={showSearchHeader}
|
||||
isFetching={isFetching}
|
||||
width={width}
|
||||
setSearchInputRef={this.setSearchInputRef}
|
||||
onPress={this.onPress}
|
||||
onSearchChangeText={text => this.onSearchChangeText(text)}
|
||||
|
|
|
@ -5,8 +5,8 @@ import {
|
|||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import equal from 'deep-equal';
|
||||
import { withNavigation } from 'react-navigation';
|
||||
|
||||
import Navigation from '../../lib/Navigation';
|
||||
import { toggleServerDropdown as toggleServerDropdownAction } from '../../actions/rooms';
|
||||
import { selectServerRequest as selectServerRequestAction } from '../../actions/server';
|
||||
import { appStart as appStartAction } from '../../actions';
|
||||
|
@ -29,8 +29,9 @@ const ANIMATION_DURATION = 200;
|
|||
selectServerRequest: server => dispatch(selectServerRequestAction(server)),
|
||||
appStart: () => dispatch(appStartAction('outside'))
|
||||
}))
|
||||
export default class ServerDropdown extends Component {
|
||||
class ServerDropdown extends Component {
|
||||
static propTypes = {
|
||||
navigation: PropTypes.object,
|
||||
closeServerDropdown: PropTypes.bool,
|
||||
server: PropTypes.string,
|
||||
toggleServerDropdown: PropTypes.func,
|
||||
|
@ -108,30 +109,11 @@ export default class ServerDropdown extends Component {
|
|||
}
|
||||
|
||||
addServer = () => {
|
||||
const { server } = this.props;
|
||||
const { server, navigation } = this.props;
|
||||
|
||||
this.close();
|
||||
setTimeout(() => {
|
||||
Navigation.showModal({
|
||||
stack: {
|
||||
children: [{
|
||||
component: {
|
||||
name: 'OnboardingView',
|
||||
passProps: {
|
||||
previousServer: server
|
||||
},
|
||||
options: {
|
||||
topBar: {
|
||||
visible: false
|
||||
},
|
||||
layout: {
|
||||
orientation: 'portrait'
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
navigation.navigate('OnboardingView', { previousServer: server });
|
||||
}, ANIMATION_DURATION);
|
||||
}
|
||||
|
||||
|
@ -228,3 +210,4 @@ export default class ServerDropdown extends Component {
|
|||
);
|
||||
}
|
||||
}
|
||||
export default withNavigation(ServerDropdown);
|
||||
|
|
|
@ -5,9 +5,9 @@ import {
|
|||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { isEqual } from 'lodash';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView, NavigationEvents } from 'react-navigation';
|
||||
import Orientation from 'react-native-orientation-locker';
|
||||
|
||||
import Navigation from '../../lib/Navigation';
|
||||
import SearchBox from '../../containers/SearchBox';
|
||||
import ConnectionBadge from '../../containers/ConnectionBadge';
|
||||
import database from '../../lib/realm';
|
||||
|
@ -23,13 +23,16 @@ import Touch from '../../utils/touch';
|
|||
import {
|
||||
toggleSortDropdown as toggleSortDropdownAction,
|
||||
openSearchHeader as openSearchHeaderAction,
|
||||
closeSearchHeader as closeSearchHeaderAction,
|
||||
roomsRequest as roomsRequestAction
|
||||
closeSearchHeader as closeSearchHeaderAction
|
||||
// roomsRequest as roomsRequestAction
|
||||
} from '../../actions/rooms';
|
||||
import { appStart as appStartAction } from '../../actions';
|
||||
import debounce from '../../utils/debounce';
|
||||
import { isIOS, isAndroid } from '../../utils/deviceInfo';
|
||||
import Icons, { CustomIcon } from '../../lib/Icons';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
import RoomsListHeaderView from './Header';
|
||||
import { DrawerButton, CustomHeaderButtons, Item } from '../../containers/HeaderButton';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
|
||||
const ROW_HEIGHT = 70;
|
||||
const SCROLL_OFFSET = 56;
|
||||
|
@ -38,24 +41,6 @@ const shouldUpdateProps = ['searchText', 'loadingServer', 'showServerDropdown',
|
|||
const getItemLayout = (data, index) => ({ length: ROW_HEIGHT, offset: ROW_HEIGHT * index, index });
|
||||
const keyExtractor = item => item.rid;
|
||||
|
||||
const leftButtons = [{
|
||||
id: 'settings',
|
||||
icon: Icons.getSource('settings'),
|
||||
testID: 'rooms-list-view-sidebar'
|
||||
}];
|
||||
const rightButtons = [{
|
||||
id: 'newMessage',
|
||||
icon: Icons.getSource('new_channel'),
|
||||
testID: 'rooms-list-view-create-channel'
|
||||
}];
|
||||
|
||||
if (isAndroid) {
|
||||
rightButtons.push({
|
||||
id: 'search',
|
||||
icon: Icons.getSource('search')
|
||||
});
|
||||
}
|
||||
|
||||
@connect(state => ({
|
||||
userId: state.login.user && state.login.user.id,
|
||||
server: state.server.server,
|
||||
|
@ -74,36 +59,43 @@ if (isAndroid) {
|
|||
toggleSortDropdown: () => dispatch(toggleSortDropdownAction()),
|
||||
openSearchHeader: () => dispatch(openSearchHeaderAction()),
|
||||
closeSearchHeader: () => dispatch(closeSearchHeaderAction()),
|
||||
appStart: () => dispatch(appStartAction()),
|
||||
roomsRequest: () => dispatch(roomsRequestAction())
|
||||
appStart: () => dispatch(appStartAction())
|
||||
// roomsRequest: () => dispatch(roomsRequestAction())
|
||||
}))
|
||||
/** @extends React.Component */
|
||||
export default class RoomsListView extends LoggedView {
|
||||
static options() {
|
||||
static navigationOptions = ({ navigation }) => {
|
||||
const searching = navigation.getParam('searching');
|
||||
const cancelSearchingAndroid = navigation.getParam('cancelSearchingAndroid');
|
||||
const onPressItem = navigation.getParam('onPressItem', () => {});
|
||||
const initSearchingAndroid = navigation.getParam('initSearchingAndroid', () => {});
|
||||
|
||||
return {
|
||||
topBar: {
|
||||
leftButtons,
|
||||
rightButtons,
|
||||
title: {
|
||||
component: {
|
||||
name: 'RoomsListHeaderView',
|
||||
alignment: isAndroid ? 'left' : 'fill'
|
||||
}
|
||||
}
|
||||
},
|
||||
sideMenu: {
|
||||
left: {
|
||||
enabled: true
|
||||
},
|
||||
right: {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
blurOnUnmount: true
|
||||
headerLeft: (
|
||||
searching
|
||||
? (
|
||||
<CustomHeaderButtons left>
|
||||
<Item title='cancel' iconName='cross' onPress={cancelSearchingAndroid} />
|
||||
</CustomHeaderButtons>
|
||||
)
|
||||
: <DrawerButton navigation={navigation} testID='rooms-list-view-sidebar' />
|
||||
),
|
||||
headerTitle: <RoomsListHeaderView />,
|
||||
headerRight: (
|
||||
searching
|
||||
? null
|
||||
: (
|
||||
<CustomHeaderButtons>
|
||||
{isAndroid ? <Item title='search' iconName='magnifier' onPress={initSearchingAndroid} /> : null}
|
||||
<Item title='new' iconName='edit-rounded' onPress={() => navigation.navigate('NewMessageView', { onPressItem })} testID='rooms-list-view-create-channel' />
|
||||
</CustomHeaderButtons>
|
||||
)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
navigation: PropTypes.object,
|
||||
userId: PropTypes.string,
|
||||
baseUrl: PropTypes.string,
|
||||
server: PropTypes.string,
|
||||
|
@ -116,12 +108,12 @@ export default class RoomsListView extends LoggedView {
|
|||
showFavorites: PropTypes.bool,
|
||||
showUnread: PropTypes.bool,
|
||||
useRealName: PropTypes.bool,
|
||||
appState: PropTypes.string,
|
||||
// appState: PropTypes.string,
|
||||
toggleSortDropdown: PropTypes.func,
|
||||
openSearchHeader: PropTypes.func,
|
||||
closeSearchHeader: PropTypes.func,
|
||||
appStart: PropTypes.func,
|
||||
roomsRequest: PropTypes.func
|
||||
appStart: PropTypes.func
|
||||
// roomsRequest: PropTypes.func
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
|
@ -140,12 +132,15 @@ export default class RoomsListView extends LoggedView {
|
|||
direct: [],
|
||||
livechat: []
|
||||
};
|
||||
Navigation.events().bindComponent(this);
|
||||
BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
|
||||
Orientation.unlockAllOrientations();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getSubscriptions();
|
||||
const { navigation } = this.props;
|
||||
navigation.setParams({
|
||||
onPressItem: this._onPressItem, initSearchingAndroid: this.initSearchingAndroid, cancelSearchingAndroid: this.cancelSearchingAndroid
|
||||
});
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
|
@ -222,7 +217,7 @@ export default class RoomsListView extends LoggedView {
|
|||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
sortBy, groupByType, showFavorites, showUnread, appState, roomsRequest
|
||||
sortBy, groupByType, showFavorites, showUnread
|
||||
} = this.props;
|
||||
|
||||
if (!(
|
||||
|
@ -232,9 +227,11 @@ export default class RoomsListView extends LoggedView {
|
|||
&& (prevProps.showUnread === showUnread)
|
||||
)) {
|
||||
this.getSubscriptions();
|
||||
} else if (appState === 'foreground' && appState !== prevProps.appState) {
|
||||
roomsRequest();
|
||||
}
|
||||
// removed for now... we may not need it anymore
|
||||
// else if (appState === 'foreground' && appState !== prevProps.appState) {
|
||||
// // roomsRequest();
|
||||
// }
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -245,52 +242,6 @@ export default class RoomsListView extends LoggedView {
|
|||
this.removeListener(this.privateGroup);
|
||||
this.removeListener(this.direct);
|
||||
this.removeListener(this.livechat);
|
||||
BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
|
||||
}
|
||||
|
||||
navigationButtonPressed = ({ buttonId }) => {
|
||||
if (buttonId === 'newMessage') {
|
||||
Navigation.showModal({
|
||||
stack: {
|
||||
children: [{
|
||||
component: {
|
||||
name: 'NewMessageView',
|
||||
passProps: {
|
||||
onPressItem: this._onPressItem
|
||||
},
|
||||
options: {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('New_Message')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
} else if (buttonId === 'settings') {
|
||||
Navigation.showModal({
|
||||
stack: {
|
||||
children: [{
|
||||
component: {
|
||||
name: 'SidebarView',
|
||||
options: {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Settings')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
} else if (buttonId === 'search') {
|
||||
this.initSearchingAndroid();
|
||||
} else if (buttonId === 'back') {
|
||||
this.cancelSearchingAndroid();
|
||||
}
|
||||
}
|
||||
|
||||
internalSetState = (...args) => {
|
||||
|
@ -394,32 +345,18 @@ export default class RoomsListView extends LoggedView {
|
|||
}
|
||||
|
||||
initSearchingAndroid = () => {
|
||||
const { openSearchHeader } = this.props;
|
||||
const { openSearchHeader, navigation } = this.props;
|
||||
this.setState({ searching: true });
|
||||
navigation.setParams({ searching: true });
|
||||
openSearchHeader();
|
||||
Navigation.mergeOptions('RoomsListView', {
|
||||
topBar: {
|
||||
leftButtons: [{
|
||||
id: 'back',
|
||||
icon: Icons.getSource('close'),
|
||||
testID: 'rooms-list-view-cancel-search'
|
||||
}],
|
||||
rightButtons: []
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
cancelSearchingAndroid = () => {
|
||||
if (isAndroid) {
|
||||
const { closeSearchHeader } = this.props;
|
||||
const { closeSearchHeader, navigation } = this.props;
|
||||
this.setState({ searching: false });
|
||||
navigation.setParams({ searching: false });
|
||||
closeSearchHeader();
|
||||
Navigation.mergeOptions('RoomsListView', {
|
||||
topBar: {
|
||||
leftButtons,
|
||||
rightButtons
|
||||
}
|
||||
});
|
||||
this.internalSetState({ search: [] });
|
||||
Keyboard.dismiss();
|
||||
}
|
||||
|
@ -450,14 +387,8 @@ export default class RoomsListView extends LoggedView {
|
|||
|
||||
goRoom = ({ rid, name, t }) => {
|
||||
this.cancelSearchingAndroid();
|
||||
Navigation.push('RoomsListView', {
|
||||
component: {
|
||||
name: 'RoomView',
|
||||
passProps: {
|
||||
rid, name, t
|
||||
}
|
||||
}
|
||||
});
|
||||
const { navigation } = this.props;
|
||||
navigation.navigate('RoomView', { rid, name, t });
|
||||
}
|
||||
|
||||
_onPressItem = async(item = {}) => {
|
||||
|
@ -690,6 +621,7 @@ export default class RoomsListView extends LoggedView {
|
|||
|
||||
return (
|
||||
<SafeAreaView style={styles.container} testID='rooms-list-view' forceInset={{ bottom: 'never' }}>
|
||||
<StatusBar />
|
||||
{this.renderScroll()}
|
||||
{showSortDropdown
|
||||
? (
|
||||
|
@ -705,9 +637,11 @@ export default class RoomsListView extends LoggedView {
|
|||
}
|
||||
{showServerDropdown ? <ServerDropdown navigator={navigator} /> : null}
|
||||
<ConnectionBadge />
|
||||
<NavigationEvents
|
||||
onDidFocus={() => BackHandler.addEventListener('hardwareBackPress', this.handleBackPress)}
|
||||
onWillBlur={() => BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress)}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
console.disableYellowBox = true;
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { View, FlatList, Text } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import LoggedView from '../View';
|
||||
|
@ -15,6 +15,7 @@ import RocketChat from '../../lib/rocketchat';
|
|||
import Message from '../../containers/message/Message';
|
||||
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
||||
import I18n from '../../i18n';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
|
||||
@connect(state => ({
|
||||
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
|
||||
|
@ -27,18 +28,12 @@ import I18n from '../../i18n';
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class SearchMessagesView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Search')
|
||||
}
|
||||
}
|
||||
};
|
||||
static navigationOptions = {
|
||||
title: I18n.t('Search')
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
rid: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
user: PropTypes.object,
|
||||
baseUrl: PropTypes.string,
|
||||
customEmojis: PropTypes.object
|
||||
|
@ -77,7 +72,8 @@ export default class SearchMessagesView extends LoggedView {
|
|||
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
search = debounce(async(searchText) => {
|
||||
const { rid } = this.props;
|
||||
const { navigation } = this.props;
|
||||
const rid = navigation.getParam('rid');
|
||||
this.setState({ searchText, loading: true, messages: [] });
|
||||
|
||||
try {
|
||||
|
@ -142,6 +138,7 @@ export default class SearchMessagesView extends LoggedView {
|
|||
render() {
|
||||
return (
|
||||
<SafeAreaView style={styles.container} testID='search-messages-view' forceInset={{ bottom: 'never' }}>
|
||||
<StatusBar />
|
||||
<View style={styles.searchContainer}>
|
||||
<RCTextInput
|
||||
inputRef={(e) => { this.name = e; }}
|
||||
|
|
|
@ -4,10 +4,9 @@ import {
|
|||
View, StyleSheet, FlatList, LayoutAnimation
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import {
|
||||
addUser as addUserAction, removeUser as removeUserAction, reset as resetAction, setLoading as setLoadingAction
|
||||
} from '../actions/selectedUsers';
|
||||
|
@ -19,9 +18,11 @@ import debounce from '../utils/debounce';
|
|||
import LoggedView from './View';
|
||||
import I18n from '../i18n';
|
||||
import log from '../utils/log';
|
||||
import { isIOS, isAndroid } from '../utils/deviceInfo';
|
||||
import { isIOS } from '../utils/deviceInfo';
|
||||
import SearchBox from '../containers/SearchBox';
|
||||
import sharedStyles from './Styles';
|
||||
import { Item, CustomHeaderButtons } from '../containers/HeaderButton';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
safeAreaView: {
|
||||
|
@ -52,23 +53,21 @@ const styles = StyleSheet.create({
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class SelectedUsersView extends LoggedView {
|
||||
static options() {
|
||||
static navigationOptions = ({ navigation }) => {
|
||||
const title = navigation.getParam('title');
|
||||
const nextAction = navigation.getParam('nextAction', () => {});
|
||||
return {
|
||||
topBar: {
|
||||
rightButtons: [{
|
||||
id: 'create',
|
||||
text: I18n.t('Next'),
|
||||
testID: 'selected-users-view-submit',
|
||||
color: isAndroid ? '#FFF' : undefined
|
||||
}]
|
||||
}
|
||||
title,
|
||||
headerRight: (
|
||||
<CustomHeaderButtons>
|
||||
<Item title={I18n.t('Next')} onPress={nextAction} testID='selected-users-view-submit' />
|
||||
</CustomHeaderButtons>
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
rid: PropTypes.string,
|
||||
nextAction: PropTypes.string.isRequired,
|
||||
navigation: PropTypes.object,
|
||||
baseUrl: PropTypes.string,
|
||||
addUser: PropTypes.func.isRequired,
|
||||
removeUser: PropTypes.func.isRequired,
|
||||
|
@ -89,7 +88,11 @@ export default class SelectedUsersView extends LoggedView {
|
|||
search: []
|
||||
};
|
||||
this.data.addListener(this.updateState);
|
||||
Navigation.events().bindComponent(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { navigation } = this.props;
|
||||
navigation.setParams({ nextAction: this.nextAction });
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
|
@ -118,27 +121,22 @@ export default class SelectedUsersView extends LoggedView {
|
|||
this.search(text);
|
||||
}
|
||||
|
||||
navigationButtonPressed = async({ buttonId }) => {
|
||||
if (buttonId === 'create') {
|
||||
const { nextAction, setLoadingInvite } = this.props;
|
||||
if (nextAction === 'CREATE_CHANNEL') {
|
||||
const { componentId } = this.props;
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
name: 'CreateChannelView'
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const { rid, componentId } = this.props;
|
||||
try {
|
||||
setLoadingInvite(true);
|
||||
await RocketChat.addUsersToRoom(rid);
|
||||
Navigation.pop(componentId);
|
||||
} catch (e) {
|
||||
log('RoomActions Add User', e);
|
||||
} finally {
|
||||
setLoadingInvite(false);
|
||||
}
|
||||
nextAction = async() => {
|
||||
const { navigation, setLoadingInvite } = this.props;
|
||||
const nextActionID = navigation.getParam('nextActionID');
|
||||
if (nextActionID === 'CREATE_CHANNEL') {
|
||||
navigation.navigate('CreateChannelView');
|
||||
} else {
|
||||
const rid = navigation.getParam('rid');
|
||||
try {
|
||||
setLoadingInvite(true);
|
||||
await RocketChat.addUsersToRoom(rid);
|
||||
navigation.pop();
|
||||
// Navigation.pop(componentId);
|
||||
} catch (e) {
|
||||
log('RoomActions Add User', e);
|
||||
} finally {
|
||||
setLoadingInvite(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -275,6 +273,7 @@ export default class SelectedUsersView extends LoggedView {
|
|||
const { loading } = this.props;
|
||||
return (
|
||||
<SafeAreaView style={styles.safeAreaView} testID='select-users-view' forceInset={{ bottom: 'never' }}>
|
||||
<StatusBar />
|
||||
{this.renderList()}
|
||||
<Loading visible={loading} />
|
||||
</SafeAreaView>
|
||||
|
|
|
@ -4,9 +4,9 @@ import {
|
|||
Text, ScrollView, StyleSheet
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import Orientation from 'react-native-orientation-locker';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import { loginRequest as loginRequestAction } from '../actions/login';
|
||||
import TextInput from '../containers/TextInput';
|
||||
import Button from '../containers/Button';
|
||||
|
@ -15,8 +15,8 @@ import sharedStyles from './Styles';
|
|||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
import LoggedView from './View';
|
||||
import I18n from '../i18n';
|
||||
import { DARK_HEADER } from '../constants/headerOptions';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
loginTitle: {
|
||||
|
@ -33,14 +33,15 @@ const styles = StyleSheet.create({
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class SetUsernameView extends LoggedView {
|
||||
static options() {
|
||||
static navigationOptions = ({ navigation }) => {
|
||||
const title = navigation.getParam('title');
|
||||
return {
|
||||
...DARK_HEADER
|
||||
title
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
server: PropTypes.string,
|
||||
userId: PropTypes.string,
|
||||
loginRequest: PropTypes.func,
|
||||
|
@ -53,14 +54,9 @@ export default class SetUsernameView extends LoggedView {
|
|||
username: '',
|
||||
saving: false
|
||||
};
|
||||
const { componentId, server } = this.props;
|
||||
Navigation.mergeOptions(componentId, {
|
||||
topBar: {
|
||||
title: {
|
||||
text: server
|
||||
}
|
||||
}
|
||||
});
|
||||
const { server } = this.props;
|
||||
props.navigation.setParams({ title: server });
|
||||
Orientation.lockToPortrait();
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
|
@ -112,6 +108,7 @@ export default class SetUsernameView extends LoggedView {
|
|||
const { username, saving } = this.state;
|
||||
return (
|
||||
<KeyboardView contentContainerStyle={sharedStyles.container}>
|
||||
<StatusBar />
|
||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
|
||||
<SafeAreaView style={sharedStyles.container} testID='set-username-view' forceInset={{ bottom: 'never' }}>
|
||||
<Text style={[sharedStyles.loginTitle, sharedStyles.textBold, styles.loginTitle]}>{I18n.t('Username')}</Text>
|
||||
|
@ -120,7 +117,7 @@ export default class SetUsernameView extends LoggedView {
|
|||
inputRef={e => this.usernameInput = e}
|
||||
placeholder={I18n.t('Username')}
|
||||
returnKeyType='send'
|
||||
iconLeft='mention'
|
||||
iconLeft='at'
|
||||
onChangeText={value => this.setState({ username: value })}
|
||||
value={username}
|
||||
onSubmitEditing={this.submit}
|
||||
|
|
|
@ -3,9 +3,8 @@ import PropTypes from 'prop-types';
|
|||
import { View, ScrollView } from 'react-native';
|
||||
import RNPickerSelect from 'react-native-picker-select';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
|
||||
import Navigation from '../../lib/Navigation';
|
||||
import LoggedView from '../View';
|
||||
import RocketChat from '../../lib/rocketchat';
|
||||
import KeyboardView from '../../presentation/KeyboardView';
|
||||
|
@ -18,6 +17,8 @@ import Loading from '../../containers/Loading';
|
|||
import { showErrorAlert, showToast } from '../../utils/info';
|
||||
import log from '../../utils/log';
|
||||
import { setUser as setUserAction } from '../../actions/login';
|
||||
import { DrawerButton } from '../../containers/HeaderButton';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
|
||||
@connect(state => ({
|
||||
userLanguage: state.login.user && state.login.user.language
|
||||
|
@ -26,15 +27,10 @@ import { setUser as setUserAction } from '../../actions/login';
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class SettingsView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Settings')
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
headerLeft: <DrawerButton navigation={navigation} />,
|
||||
title: I18n.t('Settings')
|
||||
})
|
||||
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
|
@ -124,17 +120,6 @@ export default class SettingsView extends LoggedView {
|
|||
this.setState({ saving: false });
|
||||
setTimeout(() => {
|
||||
showToast(I18n.t('Preferences_saved'));
|
||||
|
||||
if (params.language) {
|
||||
const { componentId } = this.props;
|
||||
Navigation.mergeOptions(componentId, {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Settings')
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 300);
|
||||
} catch (e) {
|
||||
this.setState({ saving: false });
|
||||
|
@ -154,6 +139,7 @@ export default class SettingsView extends LoggedView {
|
|||
contentContainerStyle={sharedStyles.container}
|
||||
keyboardVerticalOffset={128}
|
||||
>
|
||||
<StatusBar />
|
||||
<ScrollView
|
||||
contentContainerStyle={sharedStyles.containerScrollView}
|
||||
testID='settings-view-list'
|
||||
|
|
|
@ -1,366 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
ScrollView, Text, View, StyleSheet, FlatList, LayoutAnimation, SafeAreaView, Image
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import { logout as logoutAction } from '../actions/login';
|
||||
import Avatar from '../containers/Avatar';
|
||||
import StatusContainer from '../containers/Status';
|
||||
import Status from '../containers/Status/Status';
|
||||
import Touch from '../utils/touch';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import log from '../utils/log';
|
||||
import I18n from '../i18n';
|
||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
import { getReadableVersion, isIOS, isAndroid } from '../utils/deviceInfo';
|
||||
import Icons, { CustomIcon } from '../lib/Icons';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#fff'
|
||||
},
|
||||
item: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
},
|
||||
itemLeft: {
|
||||
marginHorizontal: 10,
|
||||
width: 30,
|
||||
alignItems: 'center'
|
||||
},
|
||||
itemCenter: {
|
||||
flex: 1
|
||||
},
|
||||
itemText: {
|
||||
marginVertical: 16,
|
||||
fontWeight: 'bold',
|
||||
color: '#292E35'
|
||||
},
|
||||
separator: {
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#ddd',
|
||||
marginVertical: 4
|
||||
},
|
||||
header: {
|
||||
paddingVertical: 16,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
},
|
||||
headerTextContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start'
|
||||
},
|
||||
headerUsername: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
},
|
||||
avatar: {
|
||||
marginHorizontal: 10
|
||||
},
|
||||
status: {
|
||||
marginRight: 5
|
||||
},
|
||||
currentServerText: {
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
version: {
|
||||
marginHorizontal: 5,
|
||||
marginBottom: 5,
|
||||
fontWeight: '600',
|
||||
color: '#292E35',
|
||||
fontSize: 13
|
||||
},
|
||||
disclosureContainer: {
|
||||
marginLeft: 6,
|
||||
marginRight: 9,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
disclosureIndicator: {
|
||||
width: 20,
|
||||
height: 20
|
||||
}
|
||||
});
|
||||
const keyExtractor = item => item.id;
|
||||
|
||||
@connect(state => ({
|
||||
Site_Name: state.settings.Site_Name,
|
||||
user: {
|
||||
id: state.login.user && state.login.user.id,
|
||||
language: state.login.user && state.login.user.language,
|
||||
status: state.login.user && state.login.user.status,
|
||||
username: state.login.user && state.login.user.username,
|
||||
token: state.login.user && state.login.user.token
|
||||
},
|
||||
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
|
||||
}), dispatch => ({
|
||||
logout: () => dispatch(logoutAction())
|
||||
}))
|
||||
export default class Sidebar extends Component {
|
||||
static options() {
|
||||
return {
|
||||
topBar: {
|
||||
leftButtons: [{
|
||||
id: 'cancel',
|
||||
icon: isAndroid ? Icons.getSource('close', false) : undefined,
|
||||
systemItem: 'cancel'
|
||||
}]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
baseUrl: PropTypes.string,
|
||||
componentId: PropTypes.string,
|
||||
Site_Name: PropTypes.string.isRequired,
|
||||
user: PropTypes.object,
|
||||
logout: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
showStatus: false,
|
||||
status: []
|
||||
};
|
||||
Navigation.events().bindComponent(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setStatus();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const { user } = this.props;
|
||||
if (nextProps.user && user && user.language !== nextProps.user.language) {
|
||||
this.setStatus();
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
const { status, showStatus } = this.state;
|
||||
const { Site_Name, user, baseUrl } = this.props;
|
||||
if (nextState.showStatus !== showStatus) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.Site_Name !== Site_Name) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.Site_Name !== Site_Name) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.baseUrl !== baseUrl) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.user && user) {
|
||||
if (nextProps.user.language !== user.language) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.user.status !== user.status) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.user.username !== user.username) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!equal(nextState.status, status)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
navigationButtonPressed = ({ buttonId }) => {
|
||||
if (buttonId === 'cancel') {
|
||||
const { componentId } = this.props;
|
||||
Navigation.dismissModal(componentId);
|
||||
}
|
||||
}
|
||||
|
||||
setStatus = () => {
|
||||
this.setState({
|
||||
status: [{
|
||||
id: 'online',
|
||||
name: I18n.t('Online')
|
||||
}, {
|
||||
id: 'busy',
|
||||
name: I18n.t('Busy')
|
||||
}, {
|
||||
id: 'away',
|
||||
name: I18n.t('Away')
|
||||
}, {
|
||||
id: 'offline',
|
||||
name: I18n.t('Invisible')
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
toggleStatus = () => {
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
this.setState(prevState => ({ showStatus: !prevState.showStatus }));
|
||||
}
|
||||
|
||||
sidebarNavigate = (route) => {
|
||||
const { componentId } = this.props;
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
name: route
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
logout = () => {
|
||||
const { componentId, logout } = this.props;
|
||||
Navigation.dismissModal(componentId);
|
||||
logout();
|
||||
}
|
||||
|
||||
renderSeparator = key => <View key={key} style={styles.separator} />;
|
||||
|
||||
renderItem = ({
|
||||
text, left, onPress, testID, disclosure
|
||||
}) => (
|
||||
<Touch
|
||||
key={text}
|
||||
onPress={onPress}
|
||||
underlayColor='rgba(255, 255, 255, 0.5)'
|
||||
activeOpacity={0.3}
|
||||
testID={testID}
|
||||
>
|
||||
<View style={styles.item}>
|
||||
<View style={styles.itemLeft}>
|
||||
{left}
|
||||
</View>
|
||||
<View style={styles.itemCenter}>
|
||||
<Text style={styles.itemText}>
|
||||
{text}
|
||||
</Text>
|
||||
</View>
|
||||
{disclosure ? this.renderDisclosure() : null}
|
||||
</View>
|
||||
</Touch>
|
||||
)
|
||||
|
||||
renderStatusItem = ({ item }) => {
|
||||
const { user } = this.props;
|
||||
return (
|
||||
this.renderItem({
|
||||
text: item.name,
|
||||
left: <Status style={styles.status} size={12} status={item.id} />,
|
||||
current: user.status === item.id,
|
||||
onPress: () => {
|
||||
this.toggleStatus();
|
||||
if (user.status !== item.id) {
|
||||
try {
|
||||
RocketChat.setUserPresenceDefaultStatus(item.id);
|
||||
} catch (e) {
|
||||
log('setUserPresenceDefaultStatus', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Remove it after https://github.com/RocketChat/Rocket.Chat.ReactNative/pull/643
|
||||
renderDisclosure = () => {
|
||||
if (isIOS) {
|
||||
return (
|
||||
<View style={styles.disclosureContainer}>
|
||||
<Image source={{ uri: 'disclosure_indicator' }} style={styles.disclosureIndicator} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
renderNavigation = () => (
|
||||
[
|
||||
this.renderItem({
|
||||
text: I18n.t('Profile'),
|
||||
left: <CustomIcon name='user' size={20} color='#292E35' />,
|
||||
onPress: () => this.sidebarNavigate('ProfileView'),
|
||||
testID: 'sidebar-profile',
|
||||
disclosure: true
|
||||
}),
|
||||
this.renderItem({
|
||||
text: I18n.t('Settings'),
|
||||
left: <CustomIcon name='cog' size={20} color='#292E35' />,
|
||||
onPress: () => this.sidebarNavigate('SettingsView'),
|
||||
testID: 'sidebar-settings',
|
||||
disclosure: true
|
||||
}),
|
||||
this.renderSeparator('separator-logout'),
|
||||
this.renderItem({
|
||||
text: I18n.t('Logout'),
|
||||
left: <CustomIcon name='sign-out' size={20} color='#292E35' />,
|
||||
onPress: () => this.logout(),
|
||||
testID: 'sidebar-logout'
|
||||
})
|
||||
]
|
||||
)
|
||||
|
||||
renderStatus = () => {
|
||||
const { status } = this.state;
|
||||
const { user } = this.props;
|
||||
return (
|
||||
<FlatList
|
||||
key='status-list'
|
||||
data={status}
|
||||
extraData={user}
|
||||
renderItem={this.renderStatusItem}
|
||||
keyExtractor={keyExtractor}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { showStatus } = this.state;
|
||||
const { user, Site_Name, baseUrl } = this.props;
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<SafeAreaView testID='sidebar-view' style={styles.container}>
|
||||
<ScrollView style={styles.container} {...scrollPersistTaps}>
|
||||
<Touch
|
||||
onPress={() => this.toggleStatus()}
|
||||
underlayColor='rgba(255, 255, 255, 0.5)'
|
||||
activeOpacity={0.3}
|
||||
testID='sidebar-toggle-status'
|
||||
>
|
||||
<View style={styles.header}>
|
||||
<Avatar
|
||||
text={user.username}
|
||||
size={30}
|
||||
style={styles.avatar}
|
||||
baseUrl={baseUrl}
|
||||
user={user}
|
||||
/>
|
||||
<View style={styles.headerTextContainer}>
|
||||
<View style={styles.headerUsername}>
|
||||
<StatusContainer style={styles.status} size={12} id={user.id} />
|
||||
<Text numberOfLines={1}>{user.username}</Text>
|
||||
</View>
|
||||
<Text style={styles.currentServerText} numberOfLines={1}>{Site_Name}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</Touch>
|
||||
|
||||
{this.renderSeparator('separator-header')}
|
||||
|
||||
{!showStatus ? this.renderNavigation() : null}
|
||||
{showStatus ? this.renderStatus() : null}
|
||||
</ScrollView>
|
||||
<Text style={styles.version}>
|
||||
{getReadableVersion}
|
||||
</Text>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import React from 'react';
|
||||
import { View, Text } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import { RectButton } from 'react-native-gesture-handler';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
const Item = React.memo(({
|
||||
left, text, onPress, testID, current
|
||||
}) => (
|
||||
<RectButton
|
||||
key={testID}
|
||||
testID={testID}
|
||||
onPress={onPress}
|
||||
underlayColor='#292E35'
|
||||
activeOpacity={0.1}
|
||||
style={[styles.item, current && styles.itemCurrent]}
|
||||
>
|
||||
<View style={styles.itemLeft}>
|
||||
{left}
|
||||
</View>
|
||||
<View style={styles.itemCenter}>
|
||||
<Text style={styles.itemText}>
|
||||
{text}
|
||||
</Text>
|
||||
</View>
|
||||
</RectButton>
|
||||
));
|
||||
|
||||
Item.propTypes = {
|
||||
left: PropTypes.element,
|
||||
text: PropTypes.string,
|
||||
current: PropTypes.bool,
|
||||
onPress: PropTypes.func,
|
||||
testID: PropTypes.string
|
||||
};
|
||||
|
||||
export default Item;
|
|
@ -0,0 +1,255 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
ScrollView, Text, View, FlatList, LayoutAnimation, SafeAreaView
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import equal from 'deep-equal';
|
||||
import { RectButton } from 'react-native-gesture-handler';
|
||||
|
||||
import { logout as logoutAction } from '../../actions/login';
|
||||
import Avatar from '../../containers/Avatar';
|
||||
import StatusContainer from '../../containers/Status';
|
||||
import Status from '../../containers/Status/Status';
|
||||
import RocketChat from '../../lib/rocketchat';
|
||||
import log from '../../utils/log';
|
||||
import I18n from '../../i18n';
|
||||
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
||||
import { getReadableVersion } from '../../utils/deviceInfo';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
import styles from './styles';
|
||||
import SidebarItem from './SidebarItem';
|
||||
|
||||
const keyExtractor = item => item.id;
|
||||
|
||||
const Separator = React.memo(() => <View style={styles.separator} />);
|
||||
|
||||
@connect(state => ({
|
||||
Site_Name: state.settings.Site_Name,
|
||||
user: {
|
||||
id: state.login.user && state.login.user.id,
|
||||
language: state.login.user && state.login.user.language,
|
||||
status: state.login.user && state.login.user.status,
|
||||
username: state.login.user && state.login.user.username,
|
||||
token: state.login.user && state.login.user.token
|
||||
},
|
||||
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
|
||||
}), dispatch => ({
|
||||
logout: () => dispatch(logoutAction())
|
||||
}))
|
||||
export default class Sidebar extends Component {
|
||||
static propTypes = {
|
||||
baseUrl: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
Site_Name: PropTypes.string.isRequired,
|
||||
user: PropTypes.object,
|
||||
logout: PropTypes.func.isRequired,
|
||||
activeItemKey: PropTypes.string
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
showStatus: false,
|
||||
status: []
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setStatus();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const { user } = this.props;
|
||||
if (nextProps.user && user && user.language !== nextProps.user.language) {
|
||||
this.setStatus();
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
const { status, showStatus } = this.state;
|
||||
const {
|
||||
Site_Name, user, baseUrl, activeItemKey
|
||||
} = this.props;
|
||||
if (nextState.showStatus !== showStatus) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.Site_Name !== Site_Name) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.Site_Name !== Site_Name) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.baseUrl !== baseUrl) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.activeItemKey !== activeItemKey) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.user && user) {
|
||||
if (nextProps.user.language !== user.language) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.user.status !== user.status) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.user.username !== user.username) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!equal(nextState.status, status)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
setStatus = () => {
|
||||
this.setState({
|
||||
status: [{
|
||||
id: 'online',
|
||||
name: I18n.t('Online')
|
||||
}, {
|
||||
id: 'busy',
|
||||
name: I18n.t('Busy')
|
||||
}, {
|
||||
id: 'away',
|
||||
name: I18n.t('Away')
|
||||
}, {
|
||||
id: 'offline',
|
||||
name: I18n.t('Invisible')
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
toggleStatus = () => {
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
this.setState(prevState => ({ showStatus: !prevState.showStatus }));
|
||||
}
|
||||
|
||||
sidebarNavigate = (route) => {
|
||||
const { navigation } = this.props;
|
||||
navigation.navigate(route);
|
||||
}
|
||||
|
||||
logout = () => {
|
||||
const { logout } = this.props;
|
||||
logout();
|
||||
}
|
||||
|
||||
renderStatusItem = ({ item }) => {
|
||||
const { user } = this.props;
|
||||
return (
|
||||
<SidebarItem
|
||||
text={item.name}
|
||||
left={<Status style={styles.status} size={12} status={item.id} />}
|
||||
current={user.status === item.id}
|
||||
onPress={() => {
|
||||
this.toggleStatus();
|
||||
if (user.status !== item.id) {
|
||||
try {
|
||||
RocketChat.setUserPresenceDefaultStatus(item.id);
|
||||
} catch (e) {
|
||||
log('setUserPresenceDefaultStatus', e);
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderNavigation = () => {
|
||||
const { activeItemKey } = this.props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<SidebarItem
|
||||
text={I18n.t('Chats')}
|
||||
left={<CustomIcon name='chat' size={20} color='#292E35' />}
|
||||
onPress={() => this.sidebarNavigate('RoomsListView')}
|
||||
testID='sidebar-chats'
|
||||
current={activeItemKey === 'ChatsStack'}
|
||||
/>
|
||||
<SidebarItem
|
||||
text={I18n.t('Profile')}
|
||||
left={<CustomIcon name='user' size={20} color='#292E35' />}
|
||||
onPress={() => this.sidebarNavigate('ProfileView')}
|
||||
testID='sidebar-profile'
|
||||
current={activeItemKey === 'ProfileStack'}
|
||||
/>
|
||||
<SidebarItem
|
||||
text={I18n.t('Settings')}
|
||||
left={<CustomIcon name='cog' size={20} color='#292E35' />}
|
||||
onPress={() => this.sidebarNavigate('SettingsView')}
|
||||
testID='sidebar-settings'
|
||||
current={activeItemKey === 'SettingsStack'}
|
||||
/>
|
||||
<Separator key='separator-logout' />
|
||||
<SidebarItem
|
||||
text={I18n.t('Logout')}
|
||||
left={<CustomIcon name='sign-out' size={20} color='#292E35' />}
|
||||
onPress={this.logout}
|
||||
testID='sidebar-logout'
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
renderStatus = () => {
|
||||
const { status } = this.state;
|
||||
const { user } = this.props;
|
||||
return (
|
||||
<FlatList
|
||||
key='status-list'
|
||||
data={status}
|
||||
extraData={user}
|
||||
renderItem={this.renderStatusItem}
|
||||
keyExtractor={keyExtractor}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { showStatus } = this.state;
|
||||
const { user, Site_Name, baseUrl } = this.props;
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<SafeAreaView testID='sidebar-view' style={styles.container}>
|
||||
<ScrollView style={styles.container} {...scrollPersistTaps}>
|
||||
<RectButton
|
||||
onPress={this.toggleStatus}
|
||||
underlayColor='#292E35'
|
||||
activeOpacity={0.1}
|
||||
testID='sidebar-toggle-status'
|
||||
style={styles.header}
|
||||
>
|
||||
<Avatar
|
||||
text={user.username}
|
||||
size={30}
|
||||
style={styles.avatar}
|
||||
baseUrl={baseUrl}
|
||||
user={user}
|
||||
/>
|
||||
<View style={styles.headerTextContainer}>
|
||||
<View style={styles.headerUsername}>
|
||||
<StatusContainer style={styles.status} size={12} id={user.id} />
|
||||
<Text numberOfLines={1}>{user.username}</Text>
|
||||
</View>
|
||||
<Text style={styles.currentServerText} numberOfLines={1}>{Site_Name}</Text>
|
||||
</View>
|
||||
<CustomIcon name='arrow-down' size={20} style={[styles.headerIcon, showStatus && styles.inverted]} />
|
||||
</RectButton>
|
||||
|
||||
<Separator key='separator-header' />
|
||||
|
||||
{!showStatus ? this.renderNavigation() : null}
|
||||
{showStatus ? this.renderStatus() : null}
|
||||
</ScrollView>
|
||||
<Text style={styles.version}>
|
||||
{getReadableVersion}
|
||||
</Text>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
export default StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#fff'
|
||||
},
|
||||
item: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
},
|
||||
itemCurrent: {
|
||||
backgroundColor: '#E1E5E8'
|
||||
},
|
||||
itemLeft: {
|
||||
marginHorizontal: 10,
|
||||
width: 30,
|
||||
alignItems: 'center'
|
||||
},
|
||||
itemCenter: {
|
||||
flex: 1
|
||||
},
|
||||
itemText: {
|
||||
marginVertical: 16,
|
||||
fontWeight: 'bold',
|
||||
color: '#292E35'
|
||||
},
|
||||
separator: {
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#E1E5E8',
|
||||
marginVertical: 4
|
||||
},
|
||||
header: {
|
||||
paddingVertical: 16,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
},
|
||||
headerTextContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start'
|
||||
},
|
||||
headerUsername: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
},
|
||||
headerIcon: {
|
||||
paddingHorizontal: 10,
|
||||
color: '#292E35'
|
||||
},
|
||||
avatar: {
|
||||
marginHorizontal: 10
|
||||
},
|
||||
status: {
|
||||
marginRight: 5
|
||||
},
|
||||
currentServerText: {
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
version: {
|
||||
marginHorizontal: 5,
|
||||
marginBottom: 5,
|
||||
fontWeight: '600',
|
||||
color: '#292E35',
|
||||
fontSize: 13
|
||||
},
|
||||
inverted: {
|
||||
transform: [{ scaleY: -1 }]
|
||||
}
|
||||
});
|
|
@ -1,150 +0,0 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FlatList, View, Text } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import { openSnippetedMessages as openSnippetedMessagesAction, closeSnippetedMessages as closeSnippetedMessagesAction } from '../../actions/snippetedMessages';
|
||||
import LoggedView from '../View';
|
||||
import styles from './styles';
|
||||
import Message from '../../containers/message';
|
||||
import RCActivityIndicator from '../../containers/ActivityIndicator';
|
||||
import I18n from '../../i18n';
|
||||
|
||||
@connect(state => ({
|
||||
messages: state.snippetedMessages.messages,
|
||||
ready: state.snippetedMessages.ready,
|
||||
user: {
|
||||
id: state.login.user && state.login.user.id,
|
||||
username: state.login.user && state.login.user.username,
|
||||
token: state.login.user && state.login.user.token
|
||||
}
|
||||
}), dispatch => ({
|
||||
openSnippetedMessages: (rid, limit) => dispatch(openSnippetedMessagesAction(rid, limit)),
|
||||
closeSnippetedMessages: () => dispatch(closeSnippetedMessagesAction())
|
||||
}))
|
||||
/** @extends React.Component */
|
||||
export default class SnippetedMessagesView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Snippets')
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
rid: PropTypes.string,
|
||||
messages: PropTypes.array,
|
||||
ready: PropTypes.bool,
|
||||
user: PropTypes.object,
|
||||
openSnippetedMessages: PropTypes.func,
|
||||
closeSnippetedMessages: PropTypes.func
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super('SnippetedMessagesView', props);
|
||||
this.state = {
|
||||
loading: true,
|
||||
loadingMore: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.limit = 20;
|
||||
this.load();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const { ready } = this.props;
|
||||
if (nextProps.ready && nextProps.ready !== ready) {
|
||||
this.setState({ loading: false, loadingMore: false });
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
const { loading, loadingMore } = this.state;
|
||||
const { messages, ready } = this.props;
|
||||
if (nextState.loading !== loading) {
|
||||
return true;
|
||||
}
|
||||
if (nextState.loadingMore !== loadingMore) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.ready !== ready) {
|
||||
return true;
|
||||
}
|
||||
if (!equal(nextState.messages, messages)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const { closeSnippetedMessages } = this.props;
|
||||
closeSnippetedMessages();
|
||||
}
|
||||
|
||||
load = () => {
|
||||
const { rid, openSnippetedMessages } = this.props;
|
||||
openSnippetedMessages(rid, this.limit);
|
||||
}
|
||||
|
||||
moreData = () => {
|
||||
const { loadingMore } = this.state;
|
||||
const { messages } = this.props;
|
||||
if (messages.length < this.limit) {
|
||||
return;
|
||||
}
|
||||
if (!loadingMore) {
|
||||
this.setState({ loadingMore: true });
|
||||
this.limit += 20;
|
||||
this.load();
|
||||
}
|
||||
}
|
||||
|
||||
renderEmpty = () => (
|
||||
<View style={styles.listEmptyContainer} testID='snippeted-messages-view'>
|
||||
<Text>{I18n.t('No_snippeted_messages')}</Text>
|
||||
</View>
|
||||
)
|
||||
|
||||
renderItem = ({ item }) => {
|
||||
const { user } = this.props;
|
||||
return (
|
||||
<Message
|
||||
item={item}
|
||||
style={styles.message}
|
||||
reactions={item.reactions}
|
||||
user={user}
|
||||
customTimeFormat='MMM Do YYYY, h:mm:ss a'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { loading, loadingMore } = this.state;
|
||||
const { messages, ready } = this.props;
|
||||
|
||||
if (ready && messages.length === 0) {
|
||||
return this.renderEmpty();
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.list} testID='snippeted-messages-view' forceInset={{ bottom: 'never' }}>
|
||||
<FlatList
|
||||
data={messages}
|
||||
renderItem={this.renderItem}
|
||||
style={styles.list}
|
||||
keyExtractor={item => item._id}
|
||||
onEndReached={this.moreData}
|
||||
ListHeaderComponent={loading ? <RCActivityIndicator /> : null}
|
||||
ListFooterComponent={loadingMore ? <RCActivityIndicator /> : null}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
export default StyleSheet.create({
|
||||
list: {
|
||||
flex: 1,
|
||||
backgroundColor: '#ffffff'
|
||||
},
|
||||
message: {
|
||||
transform: [{ scaleY: 1 }]
|
||||
},
|
||||
listEmptyContainer: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: '#ffffff'
|
||||
}
|
||||
});
|
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
|||
import { FlatList, View, Text } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import ActionSheet from 'react-native-action-sheet';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import LoggedView from '../View';
|
||||
|
@ -12,6 +12,7 @@ import Message from '../../containers/message/Message';
|
|||
import RCActivityIndicator from '../../containers/ActivityIndicator';
|
||||
import I18n from '../../i18n';
|
||||
import RocketChat from '../../lib/rocketchat';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
|
||||
const STAR_INDEX = 0;
|
||||
const CANCEL_INDEX = 1;
|
||||
|
@ -29,14 +30,8 @@ const options = [I18n.t('Unstar'), I18n.t('Cancel')];
|
|||
}))
|
||||
/** @extends React.Component */
|
||||
export default class StarredMessagesView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Starred')
|
||||
}
|
||||
}
|
||||
};
|
||||
static navigationOptions = {
|
||||
title: I18n.t('Starred')
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
|
@ -175,6 +170,7 @@ export default class StarredMessagesView extends LoggedView {
|
|||
|
||||
return (
|
||||
<SafeAreaView style={styles.list} testID='starred-messages-view' forceInset={{ bottom: 'never' }}>
|
||||
<StatusBar />
|
||||
<FlatList
|
||||
data={messages}
|
||||
renderItem={this.renderItem}
|
||||
|
|
|
@ -2,29 +2,20 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { WebView } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
|
||||
import styles from './Styles';
|
||||
import LoggedView from './View';
|
||||
import { DARK_HEADER } from '../constants/headerOptions';
|
||||
import I18n from '../i18n';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
|
||||
@connect(state => ({
|
||||
termsService: state.settings.Layout_Terms_of_Service
|
||||
}))
|
||||
/** @extends React.Component */
|
||||
export default class TermsServiceView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
...DARK_HEADER,
|
||||
topBar: {
|
||||
...DARK_HEADER.topBar,
|
||||
title: {
|
||||
...DARK_HEADER.topBar.title,
|
||||
text: I18n.t('Terms_of_Service')
|
||||
}
|
||||
}
|
||||
};
|
||||
static navigationOptions = {
|
||||
title: I18n.t('Terms_of_Service')
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
|
@ -39,6 +30,7 @@ export default class TermsServiceView extends LoggedView {
|
|||
const { termsService } = this.props;
|
||||
return (
|
||||
<SafeAreaView style={styles.container} testID='terms-view'>
|
||||
<StatusBar />
|
||||
<WebView originWhitelist={['*']} source={{ html: termsService, baseUrl: '' }} />
|
||||
</SafeAreaView>
|
||||
);
|
||||
|
|
|
@ -32,7 +32,7 @@ describe('Create room screen', () => {
|
|||
|
||||
describe('Usage', async() => {
|
||||
it('should back to rooms list', async() => {
|
||||
await element(by.text('Cancel')).tap();
|
||||
await element(by.id('new-message-view-close')).tap();
|
||||
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
||||
await element(by.id('rooms-list-view-create-channel')).tap();
|
||||
|
|
|
@ -86,11 +86,6 @@ describe('Room actions screen', () => {
|
|||
await expect(element(by.id('room-actions-pinned'))).toBeVisible();
|
||||
});
|
||||
|
||||
it('should have snippeted', async() => {
|
||||
await waitFor(element(by.id('room-actions-snippeted'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||
await expect(element(by.id('room-actions-snippeted'))).toBeVisible();
|
||||
});
|
||||
|
||||
it('should have notifications', async() => {
|
||||
await waitFor(element(by.id('room-actions-notifications'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||
await expect(element(by.id('room-actions-notifications'))).toBeVisible();
|
||||
|
@ -161,11 +156,6 @@ describe('Room actions screen', () => {
|
|||
await expect(element(by.id('room-actions-pinned'))).toBeVisible();
|
||||
});
|
||||
|
||||
it('should have snippeted', async() => {
|
||||
await waitFor(element(by.id('room-actions-snippeted'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||
await expect(element(by.id('room-actions-snippeted'))).toBeVisible();
|
||||
});
|
||||
|
||||
it('should have notifications', async() => {
|
||||
await waitFor(element(by.id('room-actions-notifications'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||
await expect(element(by.id('room-actions-notifications'))).toBeVisible();
|
||||
|
|
|
@ -122,10 +122,6 @@ describe('Join public room', () => {
|
|||
await expect(element(by.id('room-actions-pinned'))).toBeVisible();
|
||||
});
|
||||
|
||||
it('should have snippeted', async() => {
|
||||
await expect(element(by.id('room-actions-snippeted'))).toBeVisible();
|
||||
});
|
||||
|
||||
it('should not have notifications', async() => {
|
||||
await expect(element(by.id('room-actions-notifications'))).toBeNotVisible();
|
||||
});
|
||||
|
@ -172,7 +168,6 @@ describe('Join public room', () => {
|
|||
await element(by.id('room-actions-list')).swipe('up');
|
||||
await expect(element(by.id('room-actions-share'))).toBeVisible();
|
||||
await expect(element(by.id('room-actions-pinned'))).toBeVisible();
|
||||
await expect(element(by.id('room-actions-snippeted'))).toBeVisible();
|
||||
await expect(element(by.id('room-actions-notifications'))).toBeVisible();
|
||||
await expect(element(by.id('room-actions-leave-channel'))).toBeVisible();
|
||||
});
|
||||
|
|
|
@ -44,7 +44,7 @@ async function logout() {
|
|||
}
|
||||
|
||||
async function tapBack() {
|
||||
await element(by.type('_UIModernBarButton').withAncestor(by.type('_UIBackButtonContainerView'))).tap();
|
||||
await element(by.id('header-back')).atIndex(0).tap();
|
||||
}
|
||||
|
||||
async function sleep(ms) {
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
import './app/ReactotronConfig';
|
||||
import './app/push';
|
||||
import App from './app/index';
|
||||
|
||||
// eslint-disable-next-line
|
||||
const app = new App();
|
|
@ -1,6 +0,0 @@
|
|||
import './app/ReactotronConfig';
|
||||
import './app/push';
|
||||
import App from './app/index';
|
||||
|
||||
// eslint-disable-next-line
|
||||
const app = new App();
|
|
@ -0,0 +1,9 @@
|
|||
import './app/ReactotronConfig';
|
||||
import { AppRegistry } from 'react-native';
|
||||
import App from './app/index';
|
||||
import { name as appName } from './app.json';
|
||||
|
||||
AppRegistry.registerComponent(appName, () => App);
|
||||
|
||||
// For storybook, comment everything above and uncomment below
|
||||
// import './storybook';
|
|
@ -26,6 +26,12 @@ target 'RocketChatRN' do
|
|||
pod 'RNImageCropPicker', :path => '../node_modules/react-native-image-crop-picker'
|
||||
pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info'
|
||||
|
||||
pod 'RNScreens', :path => '../node_modules/react-native-screens'
|
||||
|
||||
pod 'react-native-splash-screen', :path => '../node_modules/react-native-splash-screen'
|
||||
|
||||
pod 'react-native-orientation-locker', :path => '../node_modules/react-native-orientation-locker'
|
||||
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
|
|
|
@ -2,6 +2,10 @@ PODS:
|
|||
- QBImagePickerController (3.4.0)
|
||||
- React (0.58.6):
|
||||
- React/Core (= 0.58.6)
|
||||
- react-native-orientation-locker (1.1.3):
|
||||
- React
|
||||
- react-native-splash-screen (3.2.0):
|
||||
- React
|
||||
- React/Core (0.58.6):
|
||||
- yoga (= 0.58.6.React)
|
||||
- React/fishhook (0.58.6)
|
||||
|
@ -36,10 +40,14 @@ PODS:
|
|||
- QBImagePickerController
|
||||
- React/Core
|
||||
- RSKImageCropper
|
||||
- RNScreens (1.0.0-alpha.22):
|
||||
- React
|
||||
- RSKImageCropper (2.2.1)
|
||||
- yoga (0.58.6.React)
|
||||
|
||||
DEPENDENCIES:
|
||||
- react-native-orientation-locker (from `../node_modules/react-native-orientation-locker`)
|
||||
- react-native-splash-screen (from `../node_modules/react-native-splash-screen`)
|
||||
- React/Core (from `../node_modules/react-native`)
|
||||
- React/RCTActionSheet (from `../node_modules/react-native`)
|
||||
- React/RCTAnimation (from `../node_modules/react-native`)
|
||||
|
@ -53,6 +61,7 @@ DEPENDENCIES:
|
|||
- React/RCTWebSocket (from `../node_modules/react-native`)
|
||||
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
|
||||
- RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`)
|
||||
- RNScreens (from `../node_modules/react-native-screens`)
|
||||
- yoga (from `../node_modules/react-native/ReactCommon/yoga/yoga.podspec`)
|
||||
|
||||
SPEC REPOS:
|
||||
|
@ -63,21 +72,30 @@ SPEC REPOS:
|
|||
EXTERNAL SOURCES:
|
||||
React:
|
||||
:path: "../node_modules/react-native"
|
||||
react-native-orientation-locker:
|
||||
:path: "../node_modules/react-native-orientation-locker"
|
||||
react-native-splash-screen:
|
||||
:path: "../node_modules/react-native-splash-screen"
|
||||
RNDeviceInfo:
|
||||
:path: "../node_modules/react-native-device-info"
|
||||
RNImageCropPicker:
|
||||
:path: "../node_modules/react-native-image-crop-picker"
|
||||
RNScreens:
|
||||
:path: "../node_modules/react-native-screens"
|
||||
yoga:
|
||||
:path: "../node_modules/react-native/ReactCommon/yoga/yoga.podspec"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022
|
||||
React: 130b87b2d5e2baac646954282cab87be986d98fc
|
||||
react-native-orientation-locker: 8878845713f8d52f2a520ec3c3b0c9348e08e32c
|
||||
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
|
||||
RNDeviceInfo: e7c5fcde13d40e161d8a27f6c5dc69c638936002
|
||||
RNImageCropPicker: e608efe182652dc8690268cb99cb5a201f2b5ea3
|
||||
RNScreens: 720a9e6968beb73e8196239801e887d8401f86ed
|
||||
RSKImageCropper: 98296ad26b41753f796b6898d015509598f13d97
|
||||
yoga: 32d7ef1081951e9a35a4c72a7be797598b138a48
|
||||
|
||||
PODFILE CHECKSUM: da5e520837501713de2c32adbff219ab7fc5c0fa
|
||||
PODFILE CHECKSUM: ad284b28235f7bcda110a24095b5e2b5718cf7e2
|
||||
|
||||
COCOAPODS: 1.6.0
|
||||
|
|