...
 
Commits (2)
......@@ -6,17 +6,7 @@
* @flow
*/
import React, {
Component,
} from 'react';
import {
Provider,
} from 'mobx-react/native'; // import from mobx-react/native instead of mobx-react fix test
import NavigationService from './src/navigation/NavigationService';
import RNBootSplash from "react-native-bootsplash";
import React, { Component } from 'react';
import {
BackHandler,
Platform,
......@@ -26,10 +16,13 @@ import {
Alert,
Clipboard,
StatusBar,
UIManager,
} from 'react-native';
import { Provider, observer } from 'mobx-react/native';
import RNBootSplash from 'react-native-bootsplash';
import FlashMessage from 'react-native-flash-message';
import NavigationService from './src/navigation/NavigationService';
import KeychainModalScreen from './src/keychain/KeychainModalScreen';
import BlockchainTransactionModalScreen from './src/blockchain/transaction-modal/BlockchainTransactionModalScreen';
import NavigationStack from './src/navigation/NavigationStack';
......@@ -38,13 +31,10 @@ import './AppErrors';
import './src/common/services/socket.service';
import pushService from './src/common/services/push.service';
import mindsService from './src/common/services/minds.service';
import featureService from './src/common/services/features.service';
import receiveShare from './src/common/services/receive-share.service';
import sessionService from './src/common/services/session.service';
import deeplinkService from './src/common/services/deeplinks-router.service';
import badgeService from './src/common/services/badge.service';
import authService from './src/auth/AuthService';
import NotificationsService from './src/notifications/NotificationsService';
import getMaches from './src/common/helpers/getMatches';
import { GOOGLE_PLAY_STORE } from './src/config/Config';
import updateService from './src/common/services/update.service';
......@@ -63,6 +53,7 @@ import * as Sentry from '@sentry/react-native';
import apiService from './src/common/services/api.service';
import boostedContentService from './src/common/services/boosted-content.service';
import translationService from './src/common/services/translation.service';
import ThemedStyles from './src/styles/ThemedStyles';
let deepLinkUrl = '';
......@@ -74,8 +65,10 @@ pushService.init();
// fire sqlite init
sqliteStorageProviderService.get();
// clear old cookies
apiService.clearCookies();
// init settings loading
const mindsSettingsPromise = mindsService.getSettings();
// On app login (runs if the user login or if it is already logged in)
......@@ -158,22 +151,31 @@ sessionService.onLogout(() => {
// disable yellow boxes
console.disableYellowBox = true;
type State = {
appState: string
if (
Platform.OS === 'android' &&
UIManager.setLayoutAnimationEnabledExperimental
) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
type Props = {
type State = {
appState: string,
};
}
type Props = {};
/**
* App
*/
export default class App extends Component<Props, State> {
export default
@observer
class App extends Component<Props, State> {
/**
* State
*/
state = {
appState: AppState.currentState || ''
}
appState: AppState.currentState || '',
};
/**
* Handle app state changes
......@@ -206,9 +208,8 @@ export default class App extends Component<Props, State> {
*/
async componentDidMount() {
try {
// load app setting before start
const results = await Promise.all([settingsStore.init(), await Linking.getInitialURL()]);
const results = await Promise.all([settingsStore.init(), Linking.getInitialURL()]);
deepLinkUrl = results[1];
......@@ -229,7 +230,7 @@ export default class App extends Component<Props, State> {
logService.info('[App] session initialized');
}
}
} catch(err) {
} catch (err) {
logService.exception('[App] Error initializing the app', err);
Alert.alert(
'Error',
......@@ -245,7 +246,10 @@ export default class App extends Component<Props, State> {
*/
handlePasswordResetDeepLink() {
try {
if (deepLinkUrl && deeplinkService.cleanUrl(deepLinkUrl).startsWith('forgot-password')) {
if (
deepLinkUrl &&
deeplinkService.cleanUrl(deepLinkUrl).startsWith('forgot-password')
) {
const regex = /;username=(.*);code=(.*)/g;
const params = getMaches(deepLinkUrl.replace(/%3B/g, ';'), regex);
......@@ -255,7 +259,7 @@ export default class App extends Component<Props, State> {
deepLinkUrl = '';
return true;
}
} catch(err) {
} catch (err) {
logService.exception('[App] Error checking for password reset deep link', err);
}
return false;
......@@ -284,24 +288,34 @@ export default class App extends Component<Props, State> {
*/
handleOpenURL = (event) => {
deepLinkUrl = event.url;
if (deepLinkUrl) this.handlePasswordResetDeepLink();
if (deepLinkUrl) {
setTimeout(() => {
deeplinkService.navigate(deepLinkUrl);
deepLinkUrl = '';
}, 100);
this.handlePasswordResetDeepLink();
// the var can be cleaned so we check again
if (deepLinkUrl) {
setTimeout(() => {
deeplinkService.navigate(deepLinkUrl);
deepLinkUrl = '';
}, 100);
}
}
}
};
/**
* Render
*/
render() {
// App not shown until the theme is loaded
if (ThemedStyles.theme === -1) {
return null;
}
const app = (
<Provider key="app" {...stores}>
<ErrorBoundary message="An error occurred" containerStyle={CS.centered}>
<StatusBar barStyle={statusBarStyle} />
<NavigationStack
screenProps={ThemedStyles.theme} // force screen re-render when theme change
ref={navigatorRef => {
NavigationService.setTopLevelNavigator(navigatorRef);
}}
......@@ -319,15 +333,20 @@ export default class App extends Component<Props, State> {
<BlockchainTransactionModalScreen key="blockchainTransactionModal" blockchainTransaction={ stores.blockchainTransaction } />
);
const tosModal = (
<TosModal user={stores.user} key="tosModal" />
)
const tosModal = <TosModal user={stores.user} key="tosModal" />;
return [ app, keychainModal, blockchainTransactionModal, tosModal];
return [app, keychainModal, blockchainTransactionModal, tosModal];
}
renderNotification = () => {
if (!stores.notifications.last) return null;
return <Notification entity={stores.notifications.last} navigation={NavigationService} />
}
if (!stores.notifications.last) {
return null;
}
return (
<Notification
entity={stores.notifications.last}
navigation={NavigationService}
/>
);
};
}
......@@ -2,7 +2,6 @@ import 'react-native';
import React from 'react';
import { Text, TouchableOpacity } from "react-native";
import { shallow } from 'enzyme';
import featuresService from '../../src/common/services/features.service';
import LoginScreen from '../../src/auth/LoginScreen';
......@@ -17,7 +16,7 @@ import renderer from 'react-test-renderer';
describe('LoginScreen component', () => {
beforeEach(() => {
featuresService.features = {'homepage-december-2019': false};
});
it('should renders correctly', () => {
......
......@@ -3,30 +3,14 @@
exports[`ForgotPassword component should renders correctly 1`] = `
<RCTSafeAreaView
emulateUnlessSupported={true}
style={
Object {
"flex": 1,
}
}
>
<Text
style={
Array [
Object {
"fontFamily": "Roboto",
"fontSize": 28,
"fontWeight": "bold",
"lineHeight": 44,
},
Object {
"color": "#4F4F50",
},
Object {
"marginTop": 15,
},
Object {
"marginBottom": 15,
},
undefined,
undefined,
undefined,
undefined,
]
}
>
......@@ -35,31 +19,16 @@ exports[`ForgotPassword component should renders correctly 1`] = `
<Text
style={
Array [
Object {
"fontFamily": "Roboto",
"fontSize": 17,
"fontWeight": "500",
"lineHeight": 23,
},
Object {
"color": "#4F4F50",
},
undefined,
Object {
"marginBottom": 15,
},
undefined,
undefined,
undefined,
]
}
>
To request a new password, enter your username
</Text>
<View
style={
Object {
"marginBottom": 10,
}
}
>
<View>
<View
style={
Array [
......@@ -67,9 +36,6 @@ exports[`ForgotPassword component should renders correctly 1`] = `
"flexDirection": "row",
"justifyContent": "space-between",
},
Object {
"marginBottom": 5,
},
]
}
>
......@@ -87,7 +53,9 @@ exports[`ForgotPassword component should renders correctly 1`] = `
Object {
"color": "#AEB0B8",
"fontFamily": "Roboto",
"fontSize": 14,
"fontSize": 16,
"fontWeight": "600",
"marginBottom": 5,
},
]
}
......@@ -107,18 +75,7 @@ exports[`ForgotPassword component should renders correctly 1`] = `
returnKeyType="done"
style={
Array [
Object {
"backgroundColor": "transparent",
"borderColor": "#D8D8D8",
"borderRadius": 2,
"borderWidth": 1,
"color": "#4F4F50",
"fontFamily": "Roboto",
"fontSize": 16,
"height": 50,
"lineHeight": 21,
"padding": 10,
},
undefined,
undefined,
]
}
......@@ -129,13 +86,8 @@ exports[`ForgotPassword component should renders correctly 1`] = `
<View
style={
Array [
Object {
"flexDirection": "row",
"justifyContent": "flex-end",
},
Object {
"marginTop": 20,
},
undefined,
undefined,
]
}
>
......@@ -153,16 +105,13 @@ exports[`ForgotPassword component should renders correctly 1`] = `
style={
Object {
"alignItems": "center",
"backgroundColor": "#5DBAC0",
"borderColor": "#5DBAC0",
"borderRadius": 2,
"backgroundColor": "white",
"borderColor": "#4690D6",
"borderRadius": 20,
"borderWidth": 1,
"flexDirection": "row",
"height": 60,
"justifyContent": "center",
"margin": 4,
"marginLeft": 0,
"marginRight": 10,
"opacity": 1,
"padding": 4,
}
......@@ -174,16 +123,12 @@ exports[`ForgotPassword component should renders correctly 1`] = `
Object {
"color": "#4690D6",
},
Object {
"color": "white",
"fontSize": 20,
"fontWeight": "500",
},
undefined,
]
}
>
GO BACK
Go back
</Text>
</View>
......@@ -201,16 +146,13 @@ exports[`ForgotPassword component should renders correctly 1`] = `
style={
Object {
"alignItems": "center",
"backgroundColor": "#5DBAC0",
"borderColor": "#5DBAC0",
"borderRadius": 2,
"backgroundColor": "white",
"borderColor": "#4690D6",
"borderRadius": 20,
"borderWidth": 1,
"flexDirection": "row",
"height": 60,
"justifyContent": "center",
"margin": 4,
"marginLeft": 0,
"marginRight": 0,
"opacity": 1,
"padding": 4,
}
......@@ -222,16 +164,12 @@ exports[`ForgotPassword component should renders correctly 1`] = `
Object {
"color": "#4690D6",
},
Object {
"color": "white",
"fontSize": 20,
"fontWeight": "500",
},
undefined,
]
}
>
CONTINUE
Continue
</Text>
</View>
......
......@@ -6,12 +6,8 @@ exports[`ForgotScreen component should renders correctly 1`] = `
style={
Array [
Array [
Object {
"flex": 1,
},
Object {
"backgroundColor": "#F5F5F5",
},
undefined,
undefined,
],
Object {
"paddingBottom": 0,
......@@ -22,41 +18,21 @@ exports[`ForgotScreen component should renders correctly 1`] = `
<View
style={
Array [
Object {
"flex": 1,
},
Object {
"padding": 10,
},
undefined,
undefined,
]
}
>
<RCTSafeAreaView
emulateUnlessSupported={true}
style={
Object {
"flex": 1,
}
}
>
<Text
style={
Array [
Object {
"fontFamily": "Roboto",
"fontSize": 28,
"fontWeight": "bold",
"lineHeight": 44,
},
Object {
"color": "#4F4F50",
},
Object {
"marginTop": 15,
},
Object {
"marginBottom": 15,
},
undefined,
undefined,
undefined,
undefined,
]
}
>
......@@ -65,31 +41,16 @@ exports[`ForgotScreen component should renders correctly 1`] = `
<Text
style={
Array [
Object {
"fontFamily": "Roboto",
"fontSize": 17,
"fontWeight": "500",
"lineHeight": 23,
},
Object {
"color": "#4F4F50",
},
undefined,
Object {
"marginBottom": 15,
},
undefined,
undefined,
undefined,
]
}
>
To request a new password, enter your username
</Text>
<View
style={
Object {
"marginBottom": 10,
}
}
>
<View>
<View
style={
Array [
......@@ -97,9 +58,6 @@ exports[`ForgotScreen component should renders correctly 1`] = `
"flexDirection": "row",
"justifyContent": "space-between",
},
Object {
"marginBottom": 5,
},
]
}
>
......@@ -117,7 +75,9 @@ exports[`ForgotScreen component should renders correctly 1`] = `
Object {
"color": "#AEB0B8",
"fontFamily": "Roboto",
"fontSize": 14,
"fontSize": 16,
"fontWeight": "600",
"marginBottom": 5,
},
]
}
......@@ -137,18 +97,7 @@ exports[`ForgotScreen component should renders correctly 1`] = `
returnKeyType="done"
style={
Array [
Object {
"backgroundColor": "transparent",
"borderColor": "#D8D8D8",
"borderRadius": 2,
"borderWidth": 1,
"color": "#4F4F50",
"fontFamily": "Roboto",
"fontSize": 16,
"height": 50,
"lineHeight": 21,
"padding": 10,
},
undefined,
undefined,
]
}
......@@ -159,13 +108,8 @@ exports[`ForgotScreen component should renders correctly 1`] = `
<View
style={
Array [
Object {
"flexDirection": "row",
"justifyContent": "flex-end",
},
Object {
"marginTop": 20,
},
undefined,
undefined,
]
}
>
......@@ -183,16 +127,13 @@ exports[`ForgotScreen component should renders correctly 1`] = `
style={
Object {
"alignItems": "center",
"backgroundColor": "#5DBAC0",
"borderColor": "#5DBAC0",
"borderRadius": 2,
"backgroundColor": "white",
"borderColor": "#4690D6",
"borderRadius": 20,
"borderWidth": 1,
"flexDirection": "row",
"height": 60,
"justifyContent": "center",
"margin": 4,
"marginLeft": 0,
"marginRight": 10,
"opacity": 1,
"padding": 4,
}
......@@ -204,16 +145,12 @@ exports[`ForgotScreen component should renders correctly 1`] = `
Object {
"color": "#4690D6",
},
Object {
"color": "white",
"fontSize": 20,
"fontWeight": "500",
},
undefined,
]
}
>
GO BACK
Go back
</Text>
</View>
......@@ -231,16 +168,13 @@ exports[`ForgotScreen component should renders correctly 1`] = `
style={
Object {
"alignItems": "center",
"backgroundColor": "#5DBAC0",
"borderColor": "#5DBAC0",
"borderRadius": 2,
"backgroundColor": "white",
"borderColor": "#4690D6",
"borderRadius": 20,
"borderWidth": 1,
"flexDirection": "row",
"height": 60,
"justifyContent": "center",
"margin": 4,
"marginLeft": 0,
"marginRight": 0,
"opacity": 1,
"padding": 4,
}
......@@ -252,16 +186,12 @@ exports[`ForgotScreen component should renders correctly 1`] = `
Object {
"color": "#4690D6",
},
Object {
"color": "white",
"fontSize": 20,
"fontWeight": "500",
},
undefined,
]
}
>
CONTINUE
Continue
</Text>
</View>
......
......@@ -2,79 +2,69 @@
exports[`LoginScreen component should renders correctly 1`] = `
<View
onLayout={[Function]}
style={
Array [
Array [
undefined,
undefined,
],
Object {
"flex": 1,
"justifyContent": "center",
"paddingBottom": 0,
},
]
}
>
<View
<RCTSafeAreaView
emulateUnlessSupported={true}
style={
Array [
Object {
"flex": 10,
"flexDirection": "row",
"justifyContent": "center",
"paddingBottom": 10,
"paddingHorizontal": 20,
"paddingTop": 20,
},
Object {
"backgroundColor": "#F5F5F5",
},
]
}
>
<View
style={
Array [
Object {
"flex": 1,
},
Object {
"paddingTop": 10,
},
]
}
>
<Image
source={
Object {
"testUri": "../../../src/assets/logos/bulb.png",
}
}
style={
Object {
"alignSelf": "center",
"height": 59.51,
"marginTop": 10,
"width": 34.72,
<RCTScrollView>
<View>
<View
style={
Array [
undefined,
undefined,
]
}
}
/>
<LoginForm
onForgot={[Function]}
onLogin={[Function]}
/>
</View>
</View>
>
<Image
resizeMode="contain"
source={
Object {
"testUri": "../../../src/assets/logos/bulb.png",
}
}
style={
Object {
"alignSelf": "center",
"height": 80,
"marginTop": 10,
"width": 40,
}
}
/>
<LoginForm
onForgot={[Function]}
onLogin={[Function]}
/>
</View>
</View>
</RCTScrollView>
</RCTSafeAreaView>
<View
style={
Array [
Object {
"flex": 2,
"flexDirection": "row",
"justifyContent": "center",
"paddingBottom": 20,
"paddingHorizontal": 20,
"paddingTop": 20,
},
Object {
"backgroundColor": "#EFEFEF",
},
undefined,
undefined,
undefined,
]
}
>
......@@ -96,29 +86,12 @@ exports[`LoginScreen component should renders correctly 1`] = `
}
testID="registerButton"
>
<View
style={
Object {
"alignContent": "center",
"alignItems": "center",
"flex": 1,
"flexDirection": "column",
"justifyContent": "center",
}
}
>
<View>
<Text
style={
Array [
Object {
"fontFamily": "Roboto",
"fontSize": 17,
"fontWeight": "500",
"lineHeight": 23,
},
Object {
"color": "#939397",
},
undefined,
undefined,
]
}
>
......@@ -127,15 +100,8 @@ exports[`LoginScreen component should renders correctly 1`] = `
<Text
style={
Array [
Object {
"fontFamily": "Roboto",
"fontSize": 28,
"fontWeight": "bold",
"lineHeight": 44,
},
Object {
"color": "#4F4F50",
},
undefined,
undefined,
]
}
>
......
......@@ -4,9 +4,7 @@ exports[`RegisterScreen component should renders correctly 1`] = `
<View
style={
Array [
Object {
"flex": 1,
},
undefined,
]
}
>
......
......@@ -30,7 +30,7 @@
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:windowSoftInputMode="adjustResize"
android:windowSoftInputMode="stateVisible"
android:theme="@style/AppTheme"
android:largeHeap="true">
<activity
......@@ -40,7 +40,7 @@
android:label="@string/app_name"
android:screenOrientation="portrait"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize"
android:windowSoftInputMode="stateVisible"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
......
......@@ -481,7 +481,8 @@
"confirmDeleteKeychain1":"This will delete your Ethereum keychain from this phone. Ensure you backed up the private keys. If you didn't you can lose access to all your funds. There's NO UNDO!",
"pushNotification":"Push Notifications",
"regenerateKey":"Regenerate messenger keys",
"deleteBlockchain":"Delete blockchain keychain"
"deleteBlockchain":"Delete blockchain keychain",
"darkMode":"Dark mode"
},
"comingSoon":{
"try":"Try the canary app at",
......@@ -691,7 +692,7 @@
"tapCopyError":"Tap to copy the error",
"save":"Save",
"edit":"Edit",
"goback":"GO BACK",
"goback":"Go back",
"copy":"Copy",
"language":"Language",
"categories":"Categories",
......
......@@ -20,9 +20,9 @@
"scheduled": "Esta actividad esta agendada para mostrarse en"
},
"auth": {
"login": "INGRESAR",
"login": "Ingresar",
"create": "CREAR UN CANAL",
"forgot": "OLVIDÉ MI CLAVE",
"forgot": "Olvidé mi clave",
"email": "Email",
"username": "Usuario",
"password": "Clave",
......
......@@ -3,12 +3,11 @@ import React, { PureComponent } from 'react';
import { View, Text, SafeAreaView } from 'react-native';
import authService from './AuthService';
import { CommonStyle as CS } from '../styles/Common';
import { ComponentsStyle } from '../styles/Components';
import i18n from '../common/services/i18n.service';
import logService from '../common/services/log.service';
import Button from '../common/components/Button';
import Input from '../common/components/Input';
import ThemedStyles from '../styles/ThemedStyles';
/**
* Forgot Password Form
......@@ -31,10 +30,27 @@ export default class ForgotPassword extends PureComponent {
* Render
*/
render() {
const CS = ThemedStyles.style;
return (
<SafeAreaView style={CS.flexContainer}>
<Text style={[CS.titleText, CS.colorPrimaryText, CS.marginTop3x, CS.marginBottom3x]}>{i18n.t('auth.forgot')}</Text>
<Text style={[CS.subTitleText, CS.colorPrimaryText, CS.marginTop1x, CS.marginBottom3x]}>{this.state.msg}</Text>
<Text
style={[
CS.titleText,
CS.colorPrimaryText,
CS.marginTop3x,
CS.marginBottom3x,
]}>
{i18n.t('auth.forgot')}
</Text>
<Text
style={[
CS.subTitleText,
CS.colorPrimaryText,
CS.marginTop1x,
CS.marginBottom3x,
]}>
{this.state.msg}
</Text>
{!this.state.sent && <Input
placeholder={i18n.t('auth.username')}
returnKeyType={'done'}
......@@ -46,17 +62,17 @@ export default class ForgotPassword extends PureComponent {
<Button
onPress={() => this.onPressBack()}
text={i18n.t('goback')}
containerStyle={[ComponentsStyle.loginButtonNew, CS.marginRight2x]}
textStyle={ComponentsStyle.loginButtonTextNew}
containerStyle={[CS.button, CS.marginRight2x]}
textStyle={CS.buttonText}
/>
{!this.state.sent && <Button
onPress={() => this.onContinuePress()}
text={i18n.t('continue').toUpperCase()}
text={i18n.t('continue')}
loading={this.state.sending}
loadingRight={true}
disable={this.state.sending || this.state.sent}
containerStyle={ComponentsStyle.loginButtonNew}
textStyle={ComponentsStyle.loginButtonTextNew}
containerStyle={CS.button}
textStyle={CS.buttonText}
/>}
</View>
</SafeAreaView>
......@@ -89,4 +105,4 @@ export default class ForgotPassword extends PureComponent {
}
}
}
}
\ No newline at end of file
}
import React, {
Component
} from 'react';
import React, { Component } from 'react';
import {
View,
KeyboardAvoidingView,
Platform,
} from 'react-native';
import { View, KeyboardAvoidingView, Platform } from 'react-native';
import ForgotPassword from './ForgotPassword';
import ResetPassword from './ResetPassword';
import { CommonStyle as CS } from '../styles/Common';
import ThemedStyles from '../styles/ThemedStyles';
/**
* Forgot screen
......@@ -31,9 +24,10 @@ export default class ForgotScreen extends Component {
const code =
this.props.navigation.state.params &&
this.props.navigation.state.params.code;
const CS = ThemedStyles.style;
return (
<KeyboardAvoidingView style={[CS.flexContainer, CS.backgroundThemePrimary]} behavior={ Platform.OS == 'ios' ? 'padding' : null }>
<KeyboardAvoidingView style={[CS.flexContainer, CS.backgroundPrimary]} behavior={ Platform.OS == 'ios' ? 'padding' : null }>
<View style={[CS.flexContainer, CS.padding2x]}>
{code ? <ResetPassword
onBack={this.onForgotBack}
......
import React, {
Component
Component,
} from 'react';
import * as Animatable from 'react-native-animatable';
......@@ -7,20 +7,19 @@ import * as Animatable from 'react-native-animatable';
import {
View,
Text,
ScrollView,
LayoutAnimation,
// TextInput,
} from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
import authService from './AuthService';
import { CommonStyle as CS } from '../styles/Common';
import { ComponentsStyle } from '../styles/Components';
import i18n from '../common/services/i18n.service';
import logService from '../common/services/log.service';
import Input from '../common/components/Input';
import Button from '../common/components/Button';
import ThemedStyles from '../styles/ThemedStyles';
/**
* Login Form
......@@ -52,59 +51,62 @@ export default class LoginForm extends Component {
* Render
*/
render() {
const CS = ThemedStyles.style;
const msg = this.state.msg ? (
<Animatable.Text animation="bounceInLeft" style={[CS.subTitleText, CS.colorSecondaryText, { textAlign: 'center' }]} testID="loginMsg">{this.state.msg}</Animatable.Text>
<Animatable.Text
animation="bounceInLeft"
useNativeDriver
style={[CS.subTitleText, CS.colorSecondaryText, CS.textCenter]}
testID="loginMsg">
{this.state.msg}
</Animatable.Text>
) : null;
return (
<View
style={[CS.flexContainer]}>
<ScrollView style={[CS.flexContainer]}>
<View style={{flex:6}}>
<Text style={[CS.titleText, CS.colorPrimaryText]}>
{i18n.t('auth.login')}
</Text>
{msg}
<View style={[CS.flexContainer, CS.marginTop6x]}>
<Text style={[CS.titleText, CS.colorPrimaryText, CS.marginBottom2x]}>
{i18n.t('auth.login')}
</Text>
{msg}
<Input
placeholder={i18n.t('auth.username')}
onChangeText={this.setUsername}
value={this.state.username}
style={CS.marginBottom2x}
testID="usernameInput"
/>
<View>
<Input
placeholder={i18n.t('auth.username')}
onChangeText={this.setUsername}
value={this.state.username}
testID="usernameInput"
placeholder={i18n.t('auth.password')}
secureTextEntry={this.state.hidePassword}
onChangeText={this.setPassword}
value={this.state.password}
style={CS.marginBottom2x}
testID="userPasswordInput"
/>
<View>
<Input
placeholder={i18n.t('auth.password')}
secureTextEntry={this.state.hidePassword}
onChangeText={this.setPassword}
value={this.state.password}
testID="userPasswordInput"
/>
<Icon
name={this.state.hidePassword ? 'md-eye' : 'md-eye-off'}
size={25}
onPress={this.toggleHidePassword}
style={ComponentsStyle.loginInputIconNew}
/>
</View>
</View>
<View style={[{flex:6, marginTop: 30}]}>
<Button
onPress={() => this.onLoginPress()}
text={i18n.t('auth.login')}
containerStyle={ComponentsStyle.loginButtonNew}
textStyle={ComponentsStyle.loginButtonTextNew}
key={1}
loading={this.state.inProgress}
loadingRight={true}
disabled={this.state.inProgress}
disabledStyle={CS.backgroundTransparent}
testID="loginButton"
<Icon
name={this.state.hidePassword ? 'md-eye' : 'md-eye-off'}
size={25}
onPress={this.toggleHidePassword}
style={CS.inputIcon}
/>
<View style={CS.marginTop4x}>
<Text style={[ComponentsStyle.linkNew]} onPress={this.onForgotPress}>{i18n.t('auth.forgot')}</Text>
</View>
</View>
</ScrollView>
<Button
onPress={() => this.onLoginPress()}
text={i18n.t('auth.login')}
containerStyle={CS.button}
textStyle={CS.buttonText}
key={1}
loading={this.state.inProgress}
loadingRight={true}
disabled={this.state.inProgress}
disabledStyle={CS.backgroundTransparent}
testID="loginButton"
/>
<View style={CS.marginTop4x}>
<Text style={[CS.link, CS.fontL]} onPress={this.onForgotPress}>{i18n.t('auth.forgot')}</Text>
</View>
</View>
);
}
......@@ -193,6 +195,7 @@ export default class LoginForm extends Component {
this.props.onLogin();
})
.catch(errJson => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
if (errJson.error === 'invalid_grant' || errJson.error === 'invalid_client') {
this.setState({ msg: i18n.t('auth.invalidGrant'), inProgress: false });
return;
......
......@@ -6,19 +6,22 @@ import {
Keyboard,
Animated,
Text,
Image,
TouchableOpacity,
SafeAreaView,
ScrollView,
Platform,
KeyboardAvoidingView,
} from 'react-native';
import LoginForm from './LoginForm';
import { CommonStyle as CS } from '../styles/Common';
import logService from '../common/services/log.service';
import featuresService from '../common/services/features.service';
import i18nService from '../common/services/i18n.service';
import sessionService from '../common/services/session.service';
const LOGO_HEIGHT = 100;
const LOGO_HEIGHT_SMALL = 50;
import ThemedStyles from '../styles/ThemedStyles';
const LOGO_HEIGHT = 80;
const LOGO_HEIGHT_SMALL = 40;
/**
* Login screen
......@@ -31,20 +34,21 @@ export default class LoginScreen extends Component {
header: null
}
state = {
keyboard: false,
}
constructor(props) {
super(props);
this.logoHeight = new Animated.Value(LOGO_HEIGHT);
}
componentDidMount() {
// Setting this here because if user register, then onboarding then logout and login again, will go to onboarding again
sessionService.setInitialScreen('Tabs');
this.setState({ loading:true });
}
componentWillMount () {
this.keyboardWillShowSub = Keyboard.addListener('keyboardWillShow', this.keyboardWillShow);
this.keyboardWillHideSub = Keyboard.addListener('keyboardWillHide', this.keyboardWillHide);
this.keyboardWillShowSub = Keyboard.addListener('keyboardDidShow', this.keyboardWillShow);
this.keyboardWillHideSub = Keyboard.addListener('keyboardDidHide', this.keyboardWillHide);
}
componentWillUnmount() {
......@@ -54,59 +58,56 @@ export default class LoginScreen extends Component {
keyboardWillShow = (event) => {
Animated.timing(this.logoHeight, {
duration: event.duration,
duration: 500,
toValue: LOGO_HEIGHT_SMALL,
}).start();
// this.setState({keyboard: true});
// LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
};
keyboardWillHide = (event) => {
Animated.timing(this.logoHeight, {
duration: event.duration,
duration: 500,
toValue: LOGO_HEIGHT,
}).start();
};
getLoginBody = () => {
return (
<View style={[CS.flexContainer, CS.paddingTop2x]}>
<Image
source={require('./../assets/logos/bulb.png')}
style={styles.bulb}
/>
<LoginForm
onLogin={() => this.login()}
onForgot={this.onPressForgot}
/>
</View>
);
};
getLoginFooter = () => {
return (
<TouchableOpacity onPress={this.onPressRegister} testID="registerButton">
<View style={CS.flexColumnCentered}>
<Text style={[CS.subTitleText, CS.colorSecondaryText]}>{i18nService.t('auth.haveAccount')}</Text>
<Text style={[CS.titleText, CS.colorPrimaryText]}>{i18nService.t('auth.createChannel')}</Text>
</View>
</TouchableOpacity>
);
// this.setState({keyboard: false});
// LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
};
/**
* Render
*/
render() {
const resizeMode = 'center';
const CS = ThemedStyles.style;
return (
<View style={[CS.flexContainerCenter]}>
<View style={[CS.mindsLayoutBody, CS.backgroundThemePrimary]}>
{this.getLoginBody()}
<KeyboardAvoidingView style={[CS.flexColumnStretch, CS.backgroundPrimary]} behavior={Platform.OS == 'ios' ? 'padding' : null} >
<SafeAreaView style={[styles.flex10]}>
<ScrollView style={CS.flexContainer}>
<View style={[CS.paddingHorizontal4x, CS.flexColumnStretch]}>
<Animated.Image
resizeMode="contain"
source={require('./../assets/logos/bulb.png')}
style={[styles.bulb, { height: this.logoHeight }]}
/>
<LoginForm
onLogin={() => this.login()}
onForgot={this.onPressForgot}
/>
</View>
</ScrollView>
</SafeAreaView>
<View style={[CS.paddingVertical2x, CS.backgroundSecondary, CS.mindsLayoutFooter]}>
<TouchableOpacity onPress={this.onPressRegister} testID="registerButton">
<View style={CS.flexColumnCentered}>
<Text style={[CS.subTitleText, CS.colorSecondaryText]}>{i18nService.t('auth.haveAccount')}</Text>
<Text style={[CS.titleText, CS.colorPrimaryText]}>{i18nService.t('auth.createChannel')}</Text>
</View>
</TouchableOpacity>
</View>
<View style={[CS.mindsLayoutFooter, CS.backgroundThemeSecondary]}>
{this.getLoginFooter()}
</View>
</View>
</KeyboardAvoidingView>
);
}
......@@ -133,15 +134,12 @@ export default class LoginScreen extends Component {
}
const styles = StyleSheet.create({
logo: {
width: 200,
height: 84,
marginBottom: 30,
alignSelf: 'center',
flex10: {
flex: 10,
},
bulb: {
width: 34.72,
height: 59.51,
width: 40,
height: 67,
alignSelf: 'center',
marginTop: 10
},
......
......@@ -4,19 +4,15 @@ import React, {
import {
Text,
TextInput,
KeyboardAvoidingView,
View,
ScrollView,
Linking,
Alert,
StyleSheet,
TouchableOpacity
TouchableOpacity,
SafeAreaView
} from 'react-native';
import authService from '../auth/AuthService';
import { CommonStyle as CS} from '../styles/Common';
import { ComponentsStyle } from '../styles/Components';
import { observer, inject } from 'mobx-react/native';
......@@ -30,13 +26,15 @@ import Input from '../common/components/Input';
import Icon from 'react-native-vector-icons/MaterialIcons';
import Button from '../common/components/Button';
import { DISABLE_PASSWORD_INPUTS } from '../config/Config';
import ThemedStyles from '../styles/ThemedStyles';
/**
* Register Form
*/
export default
@inject('user')
@observer
export default class RegisterForm extends Component {
class RegisterForm extends Component {
state = {
error: {},
password: '',
......@@ -74,57 +72,87 @@ export default class RegisterForm extends Component {
setConfirmPassword = confirmPassword => this.setState({confirmPassword});
getFormBody = () => {
const CS = ThemedStyles.style;
return (
<ScrollView style={[CS.flexContainer, CS.marginTop2x]}>
<TouchableOpacity onPress={this.props.onBack} style={CS.marginBottom3x}>
<Icon size={34} name="keyboard-arrow-left" style={CS.colorSecondaryText} />
</TouchableOpacity>
<Text style={[CS.marginBottom3x, CS.textCenter, CS.titleText, CS.colorPrimaryText]}>
{i18n.t('auth.join')}
</Text>
<Text style={{color: '#F00', textAlign: 'center', paddingTop:4, paddingLeft:4}}>
{this.state.error.termsAcceptedError}
</Text>
<Input
placeholder={i18n.t('auth.username')}
onChangeText={this.setUsername}
value={this.state.username}
editable={!this.state.inProgress}
testID="registerUsernameInput"
/>
<Input
placeholder={i18n.t('auth.email')}
onChangeText={this.setEmail}
value={this.state.email}
editable={!this.state.inProgress}
testID="registerEmailInput"
/>
<Input
placeholder={i18n.t('auth.password')}
secureTextEntry={!DISABLE_PASSWORD_INPUTS} // e2e workaround
onChangeText={this.setPassword}
value={this.state.password}
editable={!this.state.inProgress}
testID="registerPasswordInput"
/>
{ this.state.password ?
<ScrollView style={[CS.flexContainer, CS.marginTop2x]} contentContainerStyle={CS.paddingHorizontal4x}>
<SafeAreaView style={CS.flexContainer}>
<TouchableOpacity onPress={this.props.onBack} style={CS.marginBottom3x}>
<Icon size={34} name="keyboard-arrow-left" style={CS.colorSecondaryText} />
</TouchableOpacity>
<Text style={[CS.marginBottom3x, CS.textCenter, CS.titleText, CS.colorPrimaryText]}>
{i18n.t('auth.join')}
</Text>
<Text style={{color: '#F00', textAlign: 'center', paddingTop:4, paddingLeft:4}}>
{this.state.error.termsAcceptedError}
</Text>
<Input
placeholder={i18n.t('auth.confirmpassword')}
style={CS.marginBottom2x}
placeholder={i18n.t('auth.username')}
onChangeText={this.setUsername}
value={this.state.username}
editable={!this.state.inProgress}
testID="registerUsernameInput"
/>
<Input
style={CS.marginBottom2x}
placeholder={i18n.t('auth.email')}
onChangeText={this.setEmail}
value={this.state.email}
editable={!this.state.inProgress}
testID="registerEmailInput"
/>
<Input
style={CS.marginBottom2x}
placeholder={i18n.t('auth.password')}
secureTextEntry={!DISABLE_PASSWORD_INPUTS} // e2e workaround
onChangeText={this.setConfirmPassword}
value={this.state.confirmPassword}
onChangeText={this.setPassword}
value={this.state.password}
editable={!this.state.inProgress}
testID="registerPasswordConfirmInput"
/> : null }
<CheckBox
containerStyle={ComponentsStyle.registerCheckboxNew}
title={<Text style={ComponentsStyle.termsNew}>{i18n.t('auth.accept')} <Text style={ComponentsStyle.linkNew} onPress={ ()=> Linking.openURL('https://www.minds.com/p/terms') }>{i18n.t('auth.termsAndConditions')}</Text></Text>}
checked={this.state.termsAccepted}
// textStyle={ComponentsStyle.registerCheckboxTextNew}
onPress={this.check}
disabled={this.state.inProgress}
testID="checkbox"
/>
testID="registerPasswordInput"
/>
{ this.state.password ?
<Input
placeholder={i18n.t('auth.confirmpassword')}
secureTextEntry={!DISABLE_PASSWORD_INPUTS} // e2e workaround
onChangeText={this.setConfirmPassword}
value={this.state.confirmPassword}
editable={!this.state.inProgress}
testID="registerPasswordConfirmInput"
/> : null }
<CheckBox
containerStyle={CS.checkbox}
title={<Text style={[CS.colorSecondaryText, CS.fontL]}>{i18n.t('auth.accept')} <Text style={CS.link} onPress={ ()=> Linking.openURL('https://www.minds.com/p/terms') }>{i18n.t('auth.termsAndConditions')}</Text></Text>}
checked={this.state.termsAccepted}
onPress={this.check}
disabled={this.state.inProgress}
testID="checkbox"
/>
<View style={CS.flexContainer, CS.paddingTop2x}>
<Button
onPress={() => this.onPressRegister()}
borderRadius={2}
containerStyle={CS.button}
textStyle={CS.buttonText}
loading={this.state.inProgress}
loadingRight={true}
disabled={this.state.inProgress}
text={i18n.t('auth.createChannel')}
testID="registerCreateButton"
/>
<Text style={[CS.subTitleText, CS.colorSecondaryText, CS.centered, CS.marginTop2x]}>
{i18n.to('auth.alreadyHaveAccount', null, {
login: (
<Text style={[CS.link, CS.fontL]} onPress={this.props.onBack}>
{i18n.t('auth.login')}
</Text>
),
})}
</Text>
</View>
</SafeAreaView>
</ScrollView>
);
};
......@@ -133,43 +161,11 @@ export default class RegisterForm extends Component {
this.setState({ termsAccepted: !this.state.termsAccepted })
};
getFormFooter = () => {
return (
<View style={CS.flexContainer}>
<Button
onPress={() => this.onPressRegister()}
borderRadius={2}
containerStyle={ComponentsStyle.loginButtonNew}
loading={this.state.inProgress}
loadingRight={true}
disabled={this.state.inProgress}
text={''}
testID="registerCreateButton"
>
<Text style={ComponentsStyle.loginButtonTextNew}>{i18n.t('auth.createChannel')}</Text>
</Button>
<Text style={[CS.subTitleText, CS.colorSecondaryText, CS.centered, CS.marginTop2x]}>
{i18n.to('auth.alreadyHaveAccount', null, {
login: (
<Text style={[ComponentsStyle.linkNew, CS.fontL]} onPress={this.props.onBack}>
{i18n.t('auth.login')}
</Text>
),
})}
</Text>
</View>
);
};
render() {
const CS = ThemedStyles.style;
return (
<View style={[CS.flexContainerCenter]}>
<View style={[CS.mindsLayoutBody, CS.backgroundThemePrimary]}>
{this.getFormBody()}
</View>
<View style={[CS.mindsLayoutFooter, CS.backgroundThemePrimary]}>
{this.getFormFooter()}
</View>
<View style={[CS.flexContainerCenter, CS.backgroundPrimary]}>
{this.getFormBody()}
</View>
);
}
......
......@@ -3,8 +3,8 @@ import React, { Component } from 'react';
import { View } from 'react-native';
import RegisterForm from './RegisterForm';
import { CommonStyle } from '../styles/Common';
import logService from '../common/services/log.service';
import ThemedStyles from '../styles/ThemedStyles';
/**
* Register screen
......@@ -22,7 +22,7 @@ export default class RegisterScreen extends Component {
*/
render() {
return (
<View style={[CommonStyle.flexContainer]}>
<View style={[ThemedStyles.style.flexContainer]}>
<RegisterForm onRegister={this.onRegister} onBack={this.onPressBack} />
</View>
);
......
import React, { Component } from 'react';
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
import { ComponentsStyle } from '../../styles/Components';
import { CommonStyle as CS } from '../../styles/Common';
import DateTimePicker from 'react-native-modal-datetime-picker';
import InfoPopup from './InfoPopup';
import PhoneValidationComponent from './PhoneValidationComponent';
import TextInput from './TextInput';
import ThemedStyles from '../../styles/ThemedStyles';
/**
* Form input
......@@ -45,10 +45,14 @@ export default class Input extends Component {
* Text input
*/
textInput = () => {
const CS = ThemedStyles.style;
return (
<TextInput
{...this.props}
style={[ComponentsStyle.loginInputNew, this.props.style]}
style={[
CS.input,
this.props.style,
]}
placeholderTextColor="#444"
returnKeyType={'done'}
autoCapitalize={'none'}
......@@ -62,10 +66,11 @@ export default class Input extends Component {
* Phone input
*/
phoneInput = () => {
const CS = ThemedStyles.style;
return (
<PhoneValidationComponent
style={[ComponentsStyle.loginInputNew, this.props.style]}
textStyle={CS.colorWhite}
style={[CS.input, this.props.style]}
textStyle={CS.colorPrimaryText}
onFocus={this.props.onFocus}
onBlur={this.props.onBlur}
/>
......@@ -76,11 +81,12 @@ export default class Input extends Component {
* Date input
*/
dateInput = () => {
const CS = ThemedStyles.style;
return (
<View>
<TouchableOpacity
{...this.props}
style={[ComponentsStyle.loginInputNew, this.props.style]}
style={[CS.input, this.props.style]}
placeholderTextColor="#444"
returnKeyType={'done'}
autoCapitalize={'none'}
......@@ -122,13 +128,14 @@ export default class Input extends Component {
* Render
*/
render() {
const CS = ThemedStyles.style;
const optional = this.props.optional ? (
<Text style={[styles.optional]}>{'Optional'}</Text>
) : null;
return (
<View style={CS.marginBottom2x}>
<View style={[styles.row, CS.marginBottom]}>
<View style={[styles.row]}>
<View style={styles.row}>
<Text style={[styles.label]}>{this.props.placeholder}</Text>
{this.props.info && <InfoPopup info={this.props.info} />}
......@@ -148,7 +155,9 @@ const styles = StyleSheet.create({
},
label: {
color: '#AEB0B8',
fontSize: 14,
fontSize: 16,
fontWeight: '600',
marginBottom:5 ,
fontFamily: 'Roboto',
},
optional: {
......
......@@ -133,7 +133,7 @@ export default class OnboardingScreenNew extends Component {
}
return (
<SafeAreaView style={[CS.flexContainer, CS.backgroundThemePrimary]}>
<SafeAreaView style={[CS.flexContainer, CS.backgroundPrimary]}>
<KeyboardAvoidingView style={[CS.flexContainer]} behavior={ Platform.OS == 'ios' ? 'padding' : null }>
<Wizard steps={steps} onFinish={this.onFinish} ref={this.handleWizarRef}></Wizard>
</KeyboardAvoidingView>
......
......@@ -21,7 +21,7 @@ export default class AllDoneStep extends Component {
<View
style={[
CS.flexContainerCenter,
CS.backgroundThemePrimary,
CS.backgroundPrimary,
CS.centered,
]}>
<Text style={[CS.onboardingTitle]}>{i18n.t('boosts.tabNewsfeed')}</Text>
......
......@@ -45,7 +45,7 @@ export default class ChannelSetupStepNew extends Component {
constructor(props) {
super(props);
this.store = this.props.channel.store(sessionService.guid);
this.store = this.props.channel.store(sessionService.guid);
}
changeAvatarAction = async () => {
......@@ -84,7 +84,7 @@ export default class ChannelSetupStepNew extends Component {
if (this.store.isUploading) throw new UserError('Avatar is uploading, please wait');
const {phoneNumber, city, dob} = this.state;
const payload = {
phoneNumber,
city,
......@@ -192,10 +192,10 @@ export default class ChannelSetupStepNew extends Component {
render() {
return (
<View style={[CS.flexContainerCenter]}>
<View style={[CS.mindsLayoutBody, CS.backgroundThemePrimary]}>
<View style={[CS.mindsLayoutBody, CS.backgroundPrimary]}>
{this.getBody()}
</View>
{ this.state.showFooter && <View style={[CS.mindsLayoutFooter, CS.backgroundThemePrimary]}>
{ this.state.showFooter && <View style={[CS.mindsLayoutFooter, CS.backgroundPrimary]}>
{this.getFooter()}
</View>}
</View>
......
......@@ -60,10 +60,10 @@ export default class HashtagsStepNew extends Component {
render() {
return (
<View style={[CS.flexContainerCenter]}>
<View style={[CS.mindsLayoutBody, CS.backgroundThemePrimary]}>
<View style={[CS.mindsLayoutBody, CS.backgroundPrimary]}>
{this.getBody()}
</View>
<View style={[CS.mindsLayoutFooter, CS.backgroundThemePrimary]}>
<View style={[CS.mindsLayoutFooter, CS.backgroundPrimary]}>
{this.getFooter()}
</View>
</View>
......
......@@ -34,7 +34,7 @@ export default class SuggestedChannelsStepNew extends Component {
* Component did mount
*/
componentDidMount() {
}
/**
......@@ -83,10 +83,10 @@ export default class SuggestedChannelsStepNew extends Component {
render() {
return (
<View style={[CS.flexContainerCenter]}>
<View style={[CS.mindsLayoutBody, CS.backgroundThemePrimary]}>
<View style={[CS.mindsLayoutBody, CS.backgroundPrimary]}>
{this.getBody()}
</View>
<View style={[CS.mindsLayoutFooter, CS.backgroundThemePrimary]}>
<View style={[CS.mindsLayoutFooter, CS.backgroundPrimary]}>
{this.getFooter()}
</View>
</View>
......
......@@ -25,7 +25,7 @@ export default class SuggestedGroupsStepNew extends Component {
this.props.discovery.init();
}
componentDidMount() {
this.props.hashtag.setAll(false);
this.props.discovery.filters.setType('groups');
......@@ -68,10 +68,10 @@ export default class SuggestedGroupsStepNew extends Component {
render() {
return (
<View style={[CS.flexContainerCenter]}>
<View style={[CS.mindsLayoutBody, CS.backgroundThemePrimary]}>
<View style={[CS.mindsLayoutBody, CS.backgroundPrimary]}>
{this.getBody()}
</View>
<View style={[CS.mindsLayoutFooter, CS.backgroundThemePrimary]}>
<View style={[CS.mindsLayoutFooter, CS.backgroundPrimary]}>
{this.getFooter()}
</View>
</View>
......
......@@ -67,10 +67,10 @@ export default class WelcomeStep extends Component {
render() {
return (
<View style={[CS.flexContainerCenter]} testID="artTestID">
<View style={[CS.mindsLayoutBody, CS.backgroundThemePrimary]}>
<View style={[CS.mindsLayoutBody, CS.backgroundPrimary]}>
{this.getBody()}
</View>
<View style={[CS.mindsLayoutFooter, CS.backgroundThemePrimary]}>
<View style={[CS.mindsLayoutFooter, CS.backgroundPrimary]}>
{this.getFooter()}
</View>
</View>
......
......@@ -31,11 +31,14 @@ import logService from '../common/services/log.service';
import storageService from '../common/services/storage.service';
import { observer } from 'mobx-react/native';
import ModalPicker from '../common/components/ModalPicker';
import ThemedStyles from '../styles/ThemedStyles';
import featuresService from '../common/services/features.service';
const ICON_SIZE = 24;
export default
@observer
export default class SettingsScreen extends Component {
class SettingsScreen extends Component {
static navigationOptions = {
title: 'Settings',
......@@ -61,6 +64,14 @@ export default class SettingsScreen extends Component {
settingsStore.setLeftHanded(!settingsStore.leftHanded);
}
setDarkMode = () => {
if (ThemedStyles.theme) {
ThemedStyles.setLight();
} else {
ThemedStyles.setDark();
}
}
wipeEthereumKeychainAction = () => {
const _confirm3 = async (confirmation) => {
await new Promise(r => setTimeout(r, 500)); // Modals have a "cooldown"
......@@ -96,54 +107,55 @@ export default class SettingsScreen extends Component {
};
render() {
const CS = ThemedStyles.style;
const languages = i18n.getSupportedLocales();
const list = [
{
name: i18n.t('language')+` (${i18n.getCurrentLocale()})`,
icon: (<Icon name='flag' size={ICON_SIZE} style={ styles.icon }/>),
icon: (<Icon name='flag' size={ICON_SIZE} style={[styles.icon, CS.colorPrimaryText]}/>),
onPress: () => {
this.showLanguages();
}
},
{
name: i18n.t('auth.password'),
icon: (<Icon name='security' size={ICON_SIZE} style={ styles.icon }/>),
icon: (<Icon name='security' size={ICON_SIZE} style={[styles.icon, CS.colorPrimaryText]}/>),
onPress: () => {
this.props.navigation.navigate('SettingsPassword');
}
},
{
name: i18n.t('auth.email'),
icon: (<Icon name='email' size={ICON_SIZE} style={ styles.icon }/>),
icon: (<Icon name='email' size={ICON_SIZE} style={[styles.icon, CS.colorPrimaryText]}/>),
onPress: () => {
this.props.navigation.navigate('SettingsEmail');
}
},
{
name: i18n.t('settings.pushNotification'),
icon: (<Icon name='notifications' size={ICON_SIZE} style={ styles.icon }/>),
icon: (<Icon name='notifications' size={ICON_SIZE} style={[styles.icon, CS.colorPrimaryText]}/>),
onPress: () => {
this.props.navigation.navigate('NotificationsSettings');
}
},
{
name: i18n.t('settings.blockedChannels'),
icon: (<Icon name='block' size={ICON_SIZE} style={ styles.icon }/>),
icon: (<Icon name='block' size={ICON_SIZE} style={[styles.icon, CS.colorPrimaryText]}/>),
onPress: () => {
this.props.navigation.navigate('SettingsBlockedChannels');
}
},
{
name: i18n.t('settings.regenerateKey'),
icon: (<Icon name='vpn-key' size={ICON_SIZE} style={ styles.icon }/>),
icon: (<Icon name='vpn-key' size={ICON_SIZE} style={[styles.icon, CS.colorPrimaryText]}/>),
onPress: () => {
this.props.navigation.navigate('SettingsRekey');
}
},
{
name: i18n.t('settings.logout'),
icon: (<Icon name='power-settings-new' size={ICON_SIZE} style={ styles.icon } />),
icon: (<Icon name='power-settings-new' size={ICON_SIZE} style={[styles.icon, CS.colorPrimaryText]} />),
onPress: () => {
authService.logout();
......@@ -152,78 +164,76 @@ export default class SettingsScreen extends Component {
},
{
name: i18n.t('settings.deactivate'),
icon: (<Icon name='warning' size={ICON_SIZE} style={ styles.icon } />),
icon: (<Icon name='warning' size={ICON_SIZE} style={[styles.icon, CS.colorPrimaryText]} />),
onPress: () => {
this.props.navigation.push('DeleteChannel');
}
},
{
name: i18n.t('settings.deleteBlockchain'),
icon: (<Icon name='warning' size={ICON_SIZE} style={ styles.icon } />),
icon: (<Icon name='warning' size={ICON_SIZE} style={[styles.icon, CS.colorPrimaryText]} />),
onPress: this.wipeEthereumKeychainAction
},
// ListView used by log package is deprecated
// {
// name: i18n.t('settings.logs'),
// icon: (<Icon name='list' size={ICON_SIZE} style={ styles.icon }/>),
// icon: (<Icon name='list' size={ICON_SIZE} style={[styles.icon, CS.colorPrimaryText]}/>),
// onPress: () => {
// this.props.navigation.push('Logs');
// }
// },
{
name: i18n.t('settings.logOnlyErrors'),
icon: (<Icon name='list' size={ICON_SIZE} style={ styles.icon }/>),
switchButton: true,
icon: (<Icon name='list' size={ICON_SIZE} style={[styles.icon, CS.colorPrimaryText]}/>),
switch: {value: !settingsStore.appLog, onValueChange: this.appLogActivate},
hideChevron: true,
switched: !settingsStore.appLog,
onSwitch: this.appLogActivate
},
{
name: i18n.t('settings.leftHandedMode'),
icon: (<MaterialCommunityIcons name='hand' size={ICON_SIZE} style={ styles.icon }/>),
switchButton: true,
icon: (<MaterialCommunityIcons name='hand' size={ICON_SIZE} style={[styles.icon, CS.colorPrimaryText]}/>),
switch: {value: settingsStore.leftHanded, onValueChange: this.leftHandedActivate},
hideChevron: true,
switched: settingsStore.leftHanded,
onSwitch: this.leftHandedActivate
},
];
if (featuresService.has('dark-mode')) {
list.push({
name: i18n.t('settings.darkMode'),
icon: (<MaterialCommunityIcons name='hand' size={ICON_SIZE} style={[styles.icon, CS.colorPrimaryText]}/>),
switch: {value: !!ThemedStyles.theme, onValueChange: this.setDarkMode},
hideChevron: true,
});
}
return (
<ScrollView style={styles.scrollView}>
<ModalPicker
onSelect={this.languageSelected}
onCancel={this.cancel}
show={this.state.showLanguages}
title={i18n.t('language')}
valueField="value"
labelField="name"
value={this.state.language}
items={languages}
/>
<View style={styles.scrollViewContainer}>
<View style={styles.container}>
{
list.map((l, i) => (
<ListItem
key={i}
title={l.name}
titleStyle={styles.listTitle}
containerStyle={styles.listItem}
subtitle={l.subtitle}
switchButton={l.switchButton}
hideChevron ={l.hideChevron}
onSwitch={l.onSwitch}
switched={l.switched}
leftIcon={l.icon}
onPress= {l.onPress}
noBorder
/>
))
}
</View>
</View>
</ScrollView>
<ScrollView style={[styles.scrollView, CS.backgroundPrimary]}>
<ModalPicker
onSelect={this.languageSelected}
onCancel={this.cancel}
show={this.state.showLanguages}
title={i18n.t('language')}
valueField="value"
labelField="name"
value={this.state.language}
items={languages}
/>
{
list.map((l, i) => (
<ListItem
key={i}
title={l.name}
titleStyle={[CS.fontL, CS.colorPrimaryText, CS.paddingVertical2x]}
containerStyle={styles.listItem}
subtitle={l.subtitle}
hideChevron ={l.hideChevron}
switch={l.switch}
leftIcon={l.icon}
onPress= {l.onPress}
/>
))
}
</ScrollView>
);
}
......@@ -246,10 +256,8 @@ export default class SettingsScreen extends Component {
const styles = StyleSheet.create({
scrollView: {
backgroundColor: '#FFF',
flexDirection: 'column',
},
scrollViewContainer: {
flex:1
},
container: {
flex: 1,
......@@ -258,10 +266,7 @@ const styles = StyleSheet.create({
borderBottomWidth: 0,
},
listItem: {
borderBottomWidth: 1,
borderBottomColor: '#ddd',
paddingTop: 8,
paddingBottom: 8,
backgroundColor: 'transparent'
//height:20
},
listTitle: {
......@@ -269,7 +274,6 @@ const styles = StyleSheet.create({
fontFamily: 'Roboto',
},
icon: {
color: '#455a64',
alignSelf: 'center',
},
......@@ -278,7 +282,7 @@ const styles = StyleSheet.create({
paddingTop: 8,
paddingBottom: 8,
textAlignVertical: 'center',
backgroundColor: '#f4f4f4',
// backgroundColor: '#f4f4f4',
width: '100%',
//height: 40,
borderTopWidth: StyleSheet.hairlineWidth,
......
import { observable, action } from 'mobx'
import { observable, action } from 'mobx';
import logService from '../common/services/log.service';
import storageService from '../common/services/storage.service';
import appStore from '../../AppStores';
import ThemedStyles from '../styles/ThemedStyles';
/**
* Store for the values held in Settings.
......@@ -22,8 +22,25 @@ class SettingsStore {
*/
@action.bound
async init() {
const data = await storageService.multiGet(['LeftHanded', 'AppLog', 'CreatorNsfw', 'ConsumerNsfw', 'UseHashtags']);
if (!data) return;
const data = await storageService.multiGet([
'LeftHanded',
'AppLog',
'CreatorNsfw',
'ConsumerNsfw',
'UseHashtags',
'Theme',
]);
// store theme changes
ThemedStyles.onThemeChange((value) => {
this.setTheme(value);
});
if (!data) {
ThemedStyles.theme = 0;
ThemedStyles.init();
return;
}
this.leftHanded = data[0][1];
this.appLog = data[1][1];
this.creatorNsfw = data[2][1] || [];
......@@ -33,9 +50,21 @@ class SettingsStore {
// set the initial value for hashtag
appStore.hashtag.setAll(!this.useHashtags);
// theme
ThemedStyles.theme = data[5][1] || 0;
ThemedStyles.init();
return this;
}
/**
* Set the theme in the stored values
* @param {numeric} value
*/
setTheme(value) {
storageService.setItem('Theme', value);
}
/**
* Sets in local store and changes this class variable
*/
......
......@@ -23,6 +23,7 @@ export const LIGHT_THEME = {
button_border: '#D8D8D8',
done: '#4C92A4',
action: '#A5A5A5',
link: '#0091FF',
};
export const DARK_THEME = {
......@@ -35,4 +36,5 @@ export const DARK_THEME = {
button_border: '#404A4E',
done: '#4C92A4',
action: '#A5A5A5',
link: '#0091FF',
};
export const CommonStyled = {
textTitle: `
font-family: Roboto;
font-size: 28px;
font-weight: bold;
line-height: 44px;
`,
textSubTitle: `
font-family: Roboto;
font-size: 17px;
font-weight: 500;
line-height: 23px;
`,
flexColumnCentered: `
flex: 1;
flex-direction: column;
align-items: center;
justify-content: center;
align-content: center;
`,
};
import { StyleSheet } from 'react-native';
import { observable, action, reaction } from 'mobx';
import { DARK_THEME, LIGHT_THEME } from './Colors';
const repetitions = 8;
const step = 5;
const dynamicStyles = {};
for (let index = 0; index < repetitions; index++) {
let value = step * index;
const post = index === 1 ? '' : `${index}x`;
dynamicStyles[`margin${post}`] = { margin: value };
dynamicStyles[`marginVertical${post}`] = { marginVertical: value };
dynamicStyles[`marginTop${post}`] = { marginTop: value };
dynamicStyles[`marginLeft${post}`] = { marginLeft: value };
dynamicStyles[`marginRight${post}`] = { marginRight: value };
dynamicStyles[`marginBottom${post}`] = { marginBottom: value };
dynamicStyles[`marginHorizontal${post}`] = { marginHorizontal: value };
dynamicStyles[`padding${post}`] = { padding: value };
dynamicStyles[`paddingVertical${post}`] = { paddingVertical: value };
dynamicStyles[`paddingTop${post}`] = { paddingTop: value };
dynamicStyles[`paddingLeft${post}`] = { paddingLeft: value };
dynamicStyles[`paddingRight${post}`] = { paddingRight: value };
dynamicStyles[`paddingBottom${post}`] = { paddingBottom: value };
dynamicStyles[`paddingHorizontal${post}`] = { paddingHorizontal: value };
}
/**
* ThemedStylesStore
*/
class ThemedStylesStore {
/**
* Theme observable
* 1 Dark
* 0 Light
* -1 Not loaded
* @property {Observable<numeric>}
*/
@observable theme = -1;
/**
* Style
*/
style = {};
/**
* Initialice themed styles
*/
async init() {
// load stored theme value here
this.generateStyle();
}
@action
setDark() {
this.theme = 1;
this.generateStyle();
}
@action
setLight() {
this.theme = 0;
this.generateStyle();
}
onThemeChange(fn) {
return reaction(() => [this.theme], async args => await fn(...args), {
fireImmediately: false,
});
}
/**
* Generates the current theme
*/
generateStyle() {
const theme = this.theme ? DARK_THEME : LIGHT_THEME;
this.style = StyleSheet.create({
...dynamicStyles,
// containers
flexContainer: {
flex: 1,
},
flexContainerCenter: {
flex: 1,
justifyContent: 'center',
},
flexColumn: {
flex: 1,
flexDirection: 'column',
},
flexColumnStretch: {
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'stretch'
},
flexColumnCentered: {
flex: 1,
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
alignContent: 'center',
},
rowJustifyEnd: {
flexDirection: 'row',
justifyContent: 'flex-end'
},
rowJustifyCenter: {
flexDirection: 'row',
justifyContent: 'center'
},
rowJustifySpaceEvenly: {
flexDirection: 'row',
justifyContent: 'space-evenly'
},
rowJustifyStart: {
flexDirection: 'row',
justifyContent: 'flex-start'
},
centered: {
alignContent: 'center',
alignItems: 'center',
alignSelf: 'center',
justifyContent: 'center',
},
colorWhite: {
color: '#FFFFFF'
},
colorBlack: {
color: '#000000'
},
colorPrimaryText: {
color: theme.primary_text
},
colorSecondaryText: {
color: theme.secondary_text
},
colorLink: {
color: theme.link
},
colorButton: {
color: theme.button_border
},
colorDone: {
color: theme.done
},
colorActionNew: {
color: theme.action
},
// backgrounds
backgroundWhite: {
backgroundColor: 'white'
},
backgroundBlack: {
backgroundColor: 'black'
},
backgroundPrimary: {
backgroundColor: theme.primary_background,
},
backgroundSecondary: {
backgroundColor: theme.secondary_background,
},
// fonts
fontXS: {
fontSize: 10
},
fontS: {
fontSize: 12
},
fontM: {
fontSize: 14
},
fontL: {
fontSize: 16
},
fontXL: {
fontSize: 18
},
fontXXL: {
fontSize: 24
},
fontXXXL: {
fontSize: 30
},
// text align
textRight: {
textAlign: 'right'
},
textLeft: {
textAlign: 'left'
},
textCenter: {
textAlign: 'center'
},
textJustify: {
textAlign: 'justify'
},
fullWidth: {
width: '100%'
},
halfWidth: {
width: '50%'
},
bold: {
fontWeight: '700'
},
extraBold: {
// fontWeight: '800'
fontFamily: 'Roboto-Black', // workaround android ignoring >= 800
},
fontThin: {
fontWeight: '200'
},
fontHairline: {
fontWeight: '100'
},
fontLight: {
fontWeight: '300'
},
fontNormal: {
fontWeight: '400'
},
fontMedium: {
fontWeight: '500'
},
fontSemibold: {
fontWeight: '600'
},
// onboarding
onboardingTitle: {
color: '#AEB0B8',
fontSize: 13,
lineHeight: 18,
letterSpacing: 2,
},
onboardingSubtitle: {
color: '#4A4A4A',
fontSize: 26,
lineHeight: 37,
fontWeight: '600',
},
onboardingSteps: {
color: '#A2A2A2',
fontSize: 11,
lineHeight: 15,
},
linkNew: {
color: '#9B9B9B',
fontSize: 13,
lineHeight: 20
},
mindsLayoutBody: {
flex: 10,
flexDirection: 'row',
justifyContent: 'center',
paddingHorizontal: 20,
paddingTop: 20,
paddingBottom: 10,
},
mindsLayoutFooter: {
flex: 2,
flexDirection: 'row',
justifyContent: 'center',
paddingHorizontal: 20,
paddingTop: 20,
paddingBottom: 20,
},
titleText: {
fontFamily: 'Roboto',
fontSize: 28,
fontWeight: 'bold',
lineHeight: 44,
},
subTitleText: {
fontFamily: 'Roboto',
fontSize: 17,
fontWeight: '500',
lineHeight: 23,
},
// inputs
input: {
color: theme.primary_text,
fontSize: 16,
padding: 10,
fontFamily: 'Roboto',
backgroundColor: 'transparent',
height: 50,
borderRadius: 2,
borderColor: theme.button_border,
borderWidth: 1,
lineHeight: 21,
},
link: {
color: theme.link,
textDecorationLine: 'underline',
},
inputIcon: {
position: 'absolute',
right:8,
top: Platform.OS === 'ios' ? 36 : 40,
color: theme.primary_text,
},
button: {
marginRight: 0,
marginLeft: 0,
backgroundColor: '#5DBAC0',
borderColor: '#5DBAC0',
borderWidth: 1,
borderRadius: 2,
height: 60,
},
buttonText: {
// fontFamily: 'Roboto',
fontSize: 20,
fontWeight: '500',
color: 'white',
},
checkbox: {
backgroundColor: 'transparent',
marginLeft: 0,
paddingLeft: 0,
borderWidth: 0,
marginTop: 15,
},
});
}
}
export default new ThemedStylesStore();