Página da disciplina de pos (Programação Orientada a Serviços) do curso técnico integrado de Informática para Internet.
Objetivos:
cd CurrencyConverter
yarn start
dados
color: string
Parte 1: app/actions/theme.js : criar o arquivo
touch app/actions/theme.js
Parte 2: app/actions/theme.js : adicionar ação de mudança de cor
export const CHANGE_PRIMARY_COLOR = 'CHANGE_PRIMARY_COLOR';
export const changePrimaryColor = color => ({
type: CHANGE_PRIMARY_COLOR,
color,
});
Parte 3: app/screens/Themes.js : disparar a ação de mudança de cor ao clicar na cor
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { ScrollView, StatusBar } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet';
import { connect } from 'react-redux';
import { ListItem, Separator } from '../components/List';
import { changePrimaryColor } from '../actions/theme';
const styles = EStyleSheet.create({
$blue: '$primaryBlue',
$orange: '$primaryOrange',
$green: '$primaryGreen',
$purple: '$primaryPurple',
});
class Themes extends Component {
static propTypes = {
navigation: PropTypes.object,
dispatch: PropTypes.func,
};
handlePressTheme = (color) => {
this.props.dispatch(changePrimaryColor(color));
this.props.navigation.goBack();
};
render() {
return (
<ScrollView>
<StatusBar translucent={false} barStyle="default" />
<ListItem
text="Blue"
onPress={() => this.handlePressTheme(styles.$blue)}
selected
checkmark={false}
iconBackground={styles.$blue}
/>
<Separator />
<ListItem
text="Orange"
onPress={() => this.handlePressTheme(styles.$orange)}
selected
checkmark={false}
iconBackground={styles.$orange}
/>
<Separator />
<ListItem
text="Green"
onPress={() => this.handlePressTheme(styles.$green)}
selected
checkmark={false}
iconBackground={styles.$green}
/>
<Separator />
<ListItem
text="Purple"
onPress={() => this.handlePressTheme(styles.$purple)}
selected
checkmark={false}
iconBackground={styles.$purple}
/>
<Separator />
</ScrollView>
);
}
}
export default connect()(Themes);
Parte 1: app/reducers/theme.js : criar o arquivo
touch app/reducers/theme.js
Parte 2: app/reducers/theme.js : adicionar redutor para o estado cor
import { CHANGE_PRIMARY_COLOR } from '../actions/theme';
const initialState = {
primaryColor: '#4F6D7A',
};
export default (state = initialState, action) => {
switch (action.type) {
case CHANGE_PRIMARY_COLOR:
return {
...state,
primaryColor: action.color,
};
default:
return state;
}
};
Parte 3: app/reducers/index.js : atualizar a lista de redutores a ser exportados
import { combineReducers } from 'redux';
import currencies from './currencies';
import theme from './theme';
export default combineReducers({
currencies,
theme,
});
Parte 1: app/screens/CurrencyList.js : incluir o estado color na tela
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { FlatList, StatusBar, View } from 'react-native';
import { connect } from 'react-redux';
import currencies from '../data/currencies';
import { ListItem } from '../components/List';
import { changeBaseCurrency, changeQuoteCurrency } from '../actions/currencies';
class CurrencyList extends Component {
static propTypes = {
navigation: PropTypes.object,
dispatch: PropTypes.func,
baseCurrency: PropTypes.string,
quoteCurrency: PropTypes.string,
primaryColor: PropTypes.string,
};
handlePress = (currency) => {
const { type } = this.props.navigation.state.params;
if (type === 'base') {
this.props.dispatch(changeBaseCurrency(currency));
} else if (type === 'quote') {
this.props.dispatch(changeQuoteCurrency(currency));
}
this.props.navigation.goBack(null);
};
render() {
let comparisonCurrency = this.props.baseCurrency;
if (this.props.navigation.state.params.type === 'quote') {
comparisonCurrency = this.props.quoteCurrency;
}
return (
<View>
<StatusBar translucent={false} barStyle="default" />
<FlatList
data={currencies}
renderItem={({ item }) => (
<ListItem
text={item}
selected={item === comparisonCurrency}
onPress={() => this.handlePress(item)}
iconBackground={this.props.primaryColor}
/>
)}
keyExtractor={item => item}
/>
</View>
);
}
}
const mapStateToProps = state => ({
baseCurrency: state.currencies.baseCurrency,
quoteCurrency: state.currencies.quoteCurrency,
primaryColor: state.theme.primaryColor,
});
export default connect(mapStateToProps)(CurrencyList);
Parte 2: app/components/List/ListItem.js : incluir o estado color no texto
import PropTypes from 'prop-types';
import React from 'react';
import { View, Text, TouchableHighlight } from 'react-native';
import styles from './styles';
import Icon from './Icon';
const ListItem = ({
text,
onPress,
checkmark = true,
selected = false,
visible = true,
customIcon = null,
iconBackground,
}) => {
const textStyles = [styles.text];
if (iconBackground) {
textStyles.push({ color: iconBackground });
}
return (
<TouchableHighlight onPress={onPress} underlayColor={styles.$underlayColor}>
<View style={styles.row}>
<Text style={textStyles}>{text}</Text>
{selected ? (
<Icon visible={visible} checkmark={checkmark} iconBackground={iconBackground} />
) : (
<Icon />
)}
{customIcon}
</View>
</TouchableHighlight>
);
};
ListItem.propTypes = {
text: PropTypes.string,
onPress: PropTypes.func,
checkmark: PropTypes.bool,
selected: PropTypes.bool,
visible: PropTypes.bool,
customIcon: PropTypes.element,
iconBackground: PropTypes.string,
};
export default ListItem;
Parte 3: app/screens/Home.js : incluir o estado color na tela
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { KeyboardAvoidingView, StatusBar } from 'react-native';
import { connect } from 'react-redux';
import { Container } from '../components/Container';
import { Logo } from '../components/Logo';
import { InputWithButton } from '../components/TextInput';
import { ClearButton } from '../components/Button';
import { LastConverted } from '../components/Text';
import { Header } from '../components/Header';
import { changeCurrencyAmount, swapCurrency } from '../actions/currencies';
class Home extends Component {
static propTypes = {
navigation: PropTypes.object,
dispatch: PropTypes.func,
baseCurrency: PropTypes.string,
quoteCurrency: PropTypes.string,
amount: PropTypes.number,
conversionRate: PropTypes.number,
lastConvertedDate: PropTypes.object,
primaryColor: PropTypes.string,
};
handleChangeText = (text) => {
this.props.dispatch(changeCurrencyAmount(text));
};
handlePressBaseCurrency = () => {
this.props.navigation.navigate('CurrencyList', { title: 'Base currency', type: 'base' });
};
handlePressQuoteCurrency = () => {
this.props.navigation.navigate('CurrencyList', { title: 'Quote currency', type: 'quote' });
};
handleSwapCurrency = () => {
this.props.dispatch(swapCurrency());
};
handleOptionsPress = () => {
this.props.navigation.navigate('Options');
};
render() {
const quotePrice = (this.props.amount * this.props.conversionRate).toFixed(2);
return (
<Container backgroundColor={this.props.primaryColor}>
<StatusBar backgroundColor="blue" barStyle="light-content" />
<Header onPress={this.handleOptionsPress} />
<KeyboardAvoidingView behavior="padding">
<Logo tintColor={this.props.primaryColor} />
<InputWithButton
buttonText={this.props.baseCurrency}
onPress={this.handlePressBaseCurrency}
defaultValue={this.props.amount.toString()}
keyboardType="numeric"
onChangeText={this.handleChangeText}
textColor={this.props.primaryColor}
/>
<InputWithButton
editable={false}
buttonText={this.props.quoteCurrency}
onPress={this.handlePressQuoteCurrency}
value={quotePrice}
textColor={this.props.primaryColor}
/>
<LastConverted
date={this.props.lastConvertedDate}
base={this.props.baseCurrency}
quote={this.props.quoteCurrency}
conversionRate={this.props.conversionRate}
/>
<ClearButton text="Reverse currencies" onPress={this.handleSwapCurrency} />
</KeyboardAvoidingView>
</Container>
);
}
}
const mapStateToProps = (state) => {
const { baseCurrency, quoteCurrency } = state.currencies;
const conversionSelector = state.currencies.conversions[baseCurrency] || {};
const rates = conversionSelector.rates || {};
return {
baseCurrency,
quoteCurrency,
amount: state.currencies.amount,
conversionRate: rates[quoteCurrency] || 0,
lastConvertedDate: conversionSelector.date ? new Date(conversionSelector.date) : new Date(),
primaryColor: state.theme.primaryColor,
};
};
export default connect(mapStateToProps)(Home);
Parte 4: app/components/Container/Container.js : incluir o estado color no componente
import PropTypes from 'prop-types';
import React from 'react';
import { View, TouchableWithoutFeedback, Keyboard } from 'react-native';
import styles from './styles';
const Container = ({ children, backgroundColor }) => {
const containerStyles = [styles.container];
if (backgroundColor) {
containerStyles.push({ backgroundColor });
}
return (
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
<View style={containerStyles}>{children}</View>
</TouchableWithoutFeedback>
);
};
Container.propTypes = {
children: PropTypes.any,
backgroundColor: PropTypes.string,
};
export default Container;
Parte 5: app/components/TextInput/InputWithButton.js : incluir o estado color no componente
import PropTypes from 'prop-types';
import React from 'react';
import { View, Text, TextInput, TouchableHighlight } from 'react-native';
import color from 'color';
import styles from './styles';
const InputWithButton = (props) => {
const underlayColor = color(styles.$buttonBackgroundColorBase).darken(styles.$buttonBackgroundColorModifier);
const containerStyles = [styles.container];
if (props.editable === false) {
containerStyles.push(styles.containerDiasabled);
}
const buttonTextStyles = [styles.buttonText];
if (props.textColor) {
buttonTextStyles.push({ color: props.textColor });
}
return (
<View style={containerStyles}>
<TouchableHighlight
onPress={props.onPress}
style={styles.buttonContainer}
underlayColor={underlayColor}
>
<Text style={buttonTextStyles}>{props.buttonText}</Text>
</TouchableHighlight>
<View style={styles.separator} />
<TextInput style={styles.input} underlineColorAndroid="transparent" {...props} />
</View>
);
};
InputWithButton.propTypes = {
onPress: PropTypes.func,
buttonText: PropTypes.string,
editable: PropTypes.bool,
textColor: PropTypes.string,
};
export default InputWithButton;
Parte 6: app/screens/Options.js : incluir o estado color na tela
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { ScrollView, StatusBar, Platform, Linking } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { connect } from 'react-redux';
import { ListItem, Separator } from '../components/List';
import { connectAlert } from '../components/Alert';
const ICON_PREFIX = Platform.OS === 'ios' ? 'ios' : 'md';
const ICON_COLOR = '#868686';
const ICON_SIZE = 23;
class Options extends Component {
static propTypes = {
navigation: PropTypes.object,
alertWithType: PropTypes.func,
primaryColor: PropTypes.string,
};
handlePressThemes = () => {
this.props.navigation.navigate('Themes');
};
handlePressSite = () => {
Linking.openURL('telnet://fixer.io/').catch(() =>
this.props.alertWithType('error', 'Sorry!', "Fixer.io can't be opened right now."));
// info, warn, error, success, custom
};
render() {
return (
<ScrollView>
<StatusBar translucent={false} barStyle="default" />
<ListItem
text="Themes"
onPress={this.handlePressThemes}
customIcon={
<Ionicons name={`${ICON_PREFIX}-arrow-forward`} size={ICON_SIZE} color={ICON_COLOR} />
}
iconBackground={this.props.primaryColor}
/>
<Separator />
<ListItem
text="Fixer.io"
onPress={this.handlePressSite}
customIcon={<Ionicons name={`${ICON_PREFIX}-link`} size={ICON_SIZE} color={ICON_COLOR} />}
iconBackground={this.props.primaryColor}
/>
<Separator />
</ScrollView>
);
}
}
const mapStateToProps = state => ({ primaryColor: state.theme.primaryColor });
export default connect(mapStateToProps)(connectAlert(Options));