Compare commits

...

22 commits

Author SHA1 Message Date
keplyx
b625ac7255 Updated translations 2020-03-08 12:17:04 +01:00
keplyx
2f3e171b08 Improved planning display 2020-03-08 12:05:22 +01:00
keplyx
2e579368a8 Changed tab focused icon color 2020-03-08 11:35:11 +01:00
keplyx
0020c5f588 Merge remote-tracking branch 'origin/perf' into perf 2020-03-08 11:27:45 +01:00
keplyx
798617d881 Fixed watchlist fetch + use modal instead of alert 2020-03-08 11:27:05 +01:00
1a15ff4589 Grayed out tab icons when unfocused 2020-03-08 11:17:47 +01:00
keplyx
9e708bcf09 Changed tab icons 2020-03-08 10:37:01 +01:00
keplyx
60a8fedb48 Removed console.log and changed tab colors 2020-03-08 00:33:08 +01:00
keplyx
97a56a5245 Improved RU menu section headers 2020-03-08 00:22:46 +01:00
keplyx
198fca639e Improved roxiwash section headers 2020-03-08 00:20:26 +01:00
keplyx
7f7ae68664 Improved proxiwash screen + show help banner on proxiwash and planex 2020-03-08 00:05:41 +01:00
keplyx
24ad1076a0 Improved drawer item display and fixed modal position 2020-03-07 22:52:55 +01:00
keplyx
922f15f3d2 Set sort menu with modalize 2020-03-07 22:31:08 +01:00
keplyx
8d914c97f5 Removed unused libs and improved style responsiveness 2020-03-07 11:49:32 +01:00
keplyx
38ada0c027 Improved layout 2020-03-07 09:15:25 +01:00
keplyx
1f64c734aa Replaced native base with react native paper 2020-03-06 23:15:01 +01:00
keplyx
79eaefab88 Use React navigation header 2020-03-06 09:12:56 +01:00
keplyx
14960794bc Start using react navigation header 2020-03-05 23:40:50 +01:00
keplyx
cec72be88c Use expo material icons instead of custom class 2020-03-05 21:48:37 +01:00
keplyx
b562357a95 Reworked section list to use react native design 2020-03-05 19:54:56 +01:00
keplyx
f5702297f5 Use expo web browser for drawer links 2020-03-05 10:40:25 +01:00
keplyx
7e48300fa0 Updated react navigation to v5 2020-03-05 10:29:15 +01:00
100 changed files with 2500 additions and 7533 deletions

70
App.js
View file

@ -2,16 +2,16 @@
import * as React from 'react';
import {Platform, StatusBar} from 'react-native';
import {Root, StyleProvider} from 'native-base';
import {createAppContainerWithInitialRoute} from './navigation/AppNavigator';
import LocaleManager from './utils/LocaleManager';
import * as Font from 'expo-font';
import {clearThemeCache} from 'native-base-shoutem-theme';
import AsyncStorageManager from "./utils/AsyncStorageManager";
import CustomIntroSlider from "./components/CustomIntroSlider";
import {AppLoading} from 'expo';
import NotificationsManager from "./utils/NotificationsManager";
import {SplashScreen} from 'expo';
import ThemeManager from './utils/ThemeManager';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import DrawerNavigator from './navigation/DrawerNavigator';
import NotificationsManager from "./utils/NotificationsManager";
import {Provider as PaperProvider} from 'react-native-paper';
type Props = {};
@ -22,6 +22,8 @@ type State = {
currentTheme: ?Object,
};
const Stack = createStackNavigator();
export default class App extends React.Component<Props, State> {
state = {
@ -32,26 +34,21 @@ export default class App extends React.Component<Props, State> {
};
onIntroDone: Function;
loadAssetsAsync: Function;
onLoadFinished: Function;
constructor(props: Object) {
super(props);
constructor() {
super();
LocaleManager.initTranslations();
this.onIntroDone = this.onIntroDone.bind(this);
this.loadAssetsAsync = this.loadAssetsAsync.bind(this);
this.onLoadFinished = this.onLoadFinished.bind(this);
}
/**
* Updates the theme and clears the cache to force reloading the app colors. Need to edit shoutem theme for ti to work
* Updates the theme
*/
updateTheme() {
this.setState({
currentTheme: ThemeManager.getCurrentTheme()
});
this.setupStatusBar();
clearThemeCache();
}
setupStatusBar() {
@ -76,19 +73,24 @@ export default class App extends React.Component<Props, State> {
AsyncStorageManager.getInstance().savePref(AsyncStorageManager.getInstance().preferences.showUpdate5.key, '0');
}
async componentDidMount() {
await this.loadAssetsAsync();
}
async loadAssetsAsync() {
// Wait for custom fonts to be loaded before showing the app
await Font.loadAsync({
'Roboto': require('native-base/Fonts/Roboto.ttf'),
'Roboto_medium': require('native-base/Fonts/Roboto_medium.ttf'),
'material-community': require('native-base/Fonts/MaterialCommunityIcons.ttf'),
});
// console.log("loading Fonts");
SplashScreen.preventAutoHide();
// console.log("loading preferences");
await AsyncStorageManager.getInstance().loadPreferences();
ThemeManager.getInstance().setUpdateThemeCallback(() => this.updateTheme());
// console.log("loading Expo token");
await NotificationsManager.initExpoToken();
this.onLoadFinished();
}
onLoadFinished() {
// console.log("finished");
// Only show intro if this is the first time starting the app
this.setState({
isLoading: false,
@ -97,9 +99,8 @@ export default class App extends React.Component<Props, State> {
showUpdate: AsyncStorageManager.getInstance().preferences.showUpdate5.current === '1'
});
// Status bar goes dark if set too fast
setTimeout(this.setupStatusBar,
1000
)
setTimeout(this.setupStatusBar, 1000);
SplashScreen.hide();
}
/**
@ -107,25 +108,20 @@ export default class App extends React.Component<Props, State> {
*/
render() {
if (this.state.isLoading) {
return (
<AppLoading
startAsync={this.loadAssetsAsync}
onFinish={this.onLoadFinished}
onError={console.warn}
/>
);
}
if (this.state.showIntro || this.state.showUpdate) {
return null;
} else if (this.state.showIntro || this.state.showUpdate) {
return <CustomIntroSlider onDone={this.onIntroDone}
isUpdate={this.state.showUpdate && !this.state.showIntro}/>;
} else {
const AppNavigator = createAppContainerWithInitialRoute(AsyncStorageManager.getInstance().preferences.defaultStartScreen.current);
return (
<Root>
<StyleProvider style={this.state.currentTheme}>
<AppNavigator/>
</StyleProvider>
</Root>
<PaperProvider theme={this.state.currentTheme}>
<NavigationContainer theme={this.state.currentTheme}>
<Stack.Navigator headerMode="none">
<Stack.Screen name="Root" component={DrawerNavigator}/>
</Stack.Navigator>
</NavigationContainer>
</PaperProvider>
);
}
}

View file

@ -1,143 +0,0 @@
// @flow
import * as React from 'react';
import {Container} from "native-base";
import CustomHeader from "./CustomHeader";
import CustomMaterialIcon from "./CustomMaterialIcon";
import {Platform, StatusBar, View} from "react-native";
import ThemeManager from "../utils/ThemeManager";
import Touchable from "react-native-platform-touchable";
import {ScreenOrientation} from "expo";
import {NavigationActions} from "react-navigation";
type Props = {
navigation: Object,
headerTitle: string,
headerSubtitle: string,
headerRightButton: React.Node,
children: React.Node,
hasTabs: boolean,
hasBackButton: boolean,
hasSideMenu: boolean,
enableRotation: boolean,
hideHeaderOnLandscape: boolean,
}
type State = {
isHeaderVisible: boolean
}
export default class BaseContainer extends React.Component<Props, State> {
static defaultProps = {
headerRightButton: <View/>,
hasTabs: false,
hasBackButton: false,
hasSideMenu: true,
enableRotation: false,
hideHeaderOnLandscape: false,
headerSubtitle: '',
};
willBlurSubscription: function;
willFocusSubscription: function;
state = {
isHeaderVisible: true,
};
onDrawerPress: Function;
onWillFocus: Function;
onWillBlur: Function;
onChangeOrientation: Function;
constructor() {
super();
this.onDrawerPress = this.onDrawerPress.bind(this);
this.onWillFocus = this.onWillFocus.bind(this);
this.onWillBlur = this.onWillBlur.bind(this);
this.onChangeOrientation = this.onChangeOrientation.bind(this);
}
onDrawerPress() {
this.props.navigation.toggleDrawer();
}
onWillFocus() {
if (this.props.enableRotation) {
ScreenOrientation.unlockAsync();
ScreenOrientation.addOrientationChangeListener(this.onChangeOrientation);
}
}
onWillBlur() {
if (this.props.enableRotation)
ScreenOrientation.lockAsync(ScreenOrientation.Orientation.PORTRAIT);
}
onChangeOrientation(OrientationChangeEvent) {
if (this.props.hideHeaderOnLandscape) {
let isLandscape = OrientationChangeEvent.orientationInfo.orientation === ScreenOrientation.Orientation.LANDSCAPE ||
OrientationChangeEvent.orientationInfo.orientation === ScreenOrientation.Orientation.LANDSCAPE_LEFT ||
OrientationChangeEvent.orientationInfo.orientation === ScreenOrientation.Orientation.LANDSCAPE_RIGHT;
this.setState({isHeaderVisible: !isLandscape});
const setParamsAction = NavigationActions.setParams({
params: {showTabBar: !isLandscape},
key: this.props.navigation.state.key,
});
this.props.navigation.dispatch(setParamsAction);
StatusBar.setHidden(isLandscape);
}
}
/**
* Register for blur event to close side menu on screen change
*/
componentDidMount() {
this.willFocusSubscription = this.props.navigation.addListener(
'willFocus',
this.onWillFocus
);
this.willBlurSubscription = this.props.navigation.addListener(
'willBlur',
this.onWillBlur
);
}
/**
* Unregister from event when un-mounting components
*/
componentWillUnmount() {
if (this.willBlurSubscription !== undefined)
this.willBlurSubscription.remove();
if (this.willFocusSubscription !== undefined)
this.willFocusSubscription.remove();
}
render() {
// console.log("rendering BaseContainer");
return (
<Container>
{this.state.isHeaderVisible ?
<CustomHeader
navigation={this.props.navigation}
title={this.props.headerTitle}
subtitle={this.props.headerSubtitle}
leftButton={
<Touchable
style={{padding: 6}}
onPress={this.onDrawerPress}>
<CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon="menu"/>
</Touchable>
}
rightButton={this.props.headerRightButton}
hasTabs={this.props.hasTabs}
hasBackButton={this.props.hasBackButton}/>
: <View/>}
{this.props.children}
</Container>
);
}
}

View file

@ -0,0 +1,40 @@
import * as React from 'react';
import {withTheme} from 'react-native-paper';
import {Agenda} from "react-native-calendars";
function CustomAgenda(props) {
const { colors } = props.theme;
return (
<Agenda
{...props}
ref={props.onRef}
theme={{
backgroundColor: colors.agendaBackgroundColor,
calendarBackground: colors.background,
textSectionTitleColor: colors.agendaDayTextColor,
selectedDayBackgroundColor: colors.primary,
selectedDayTextColor: '#ffffff',
todayTextColor: colors.primary,
dayTextColor: colors.text,
textDisabledColor: colors.agendaDayTextColor,
dotColor: colors.primary,
selectedDotColor: '#ffffff',
arrowColor: 'orange',
monthTextColor: colors.primary,
indicatorColor: colors.primary,
textDayFontWeight: '300',
textMonthFontWeight: 'bold',
textDayHeaderFontWeight: '300',
textDayFontSize: 16,
textMonthFontSize: 16,
textDayHeaderFontSize: 16,
agendaDayTextColor: colors.agendaDayTextColor,
agendaDayNumColor: colors.agendaDayTextColor,
agendaTodayColor: colors.primary,
agendaKnobColor: colors.primary,
}}
/>
);
}
export default withTheme(CustomAgenda);

View file

@ -1,150 +0,0 @@
// @flow
import * as React from "react";
import {Body, Header, Input, Item, Left, Right, Subtitle, Title} from "native-base";
import {Platform, StyleSheet, View} from "react-native";
import {getStatusBarHeight} from "react-native-status-bar-height";
import Touchable from 'react-native-platform-touchable';
import ThemeManager from "../utils/ThemeManager";
import CustomMaterialIcon from "./CustomMaterialIcon";
import i18n from "i18n-js";
import {NavigationActions} from 'react-navigation';
type Props = {
hasBackButton: boolean,
hasSearchField: boolean,
searchCallback: Function,
shouldFocusSearchBar: boolean,
leftButton: React.Node,
rightButton: React.Node,
title: string,
subtitle: string,
navigation: Object,
hasTabs: boolean,
};
/**
* Custom component defining a header using native base
*
* @prop hasBackButton {boolean} Whether to show a back button or a burger menu. Use burger if unspecified
* @prop rightMenu {React.Node} Element to place at the right of the header. Use nothing if unspecified
* @prop title {string} This header title
* @prop navigation {Object} The navigation object from react navigation
*/
export default class CustomHeader extends React.Component<Props> {
static defaultProps = {
hasBackButton: false,
hasSearchField: false,
searchCallback: null,
shouldFocusSearchBar: false,
title: '',
subtitle: '',
leftButton: <View/>,
rightButton: <View/>,
hasTabs: false,
};
onPressBack: Function;
constructor() {
super();
this.onPressBack = this.onPressBack.bind(this);
}
shouldComponentUpdate(nextProps: Props): boolean {
return nextProps.title !== this.props.title ||
nextProps.subtitle !== this.props.subtitle ||
nextProps.hasBackButton !== this.props.hasBackButton ||
nextProps.hasSearchField !== this.props.hasSearchField ||
nextProps.shouldFocusSearchBar !== this.props.shouldFocusSearchBar ||
nextProps.hasTabs !== this.props.hasTabs ||
nextProps.rightButton !== this.props.rightButton ||
nextProps.leftButton !== this.props.leftButton;
}
componentDidMount() {
if (this.refs.searchInput !== undefined && this.refs.searchInput._root !== undefined && this.props.shouldFocusSearchBar) {
// does not work if called too early for some reason...
setTimeout(this.refs.searchInput._root.focus, 500);
}
}
getSearchBar() {
return (
<Body>
<Item
style={{
width: '100%',
marginBottom: 7
}}>
<CustomMaterialIcon
icon={'magnify'}
color={ThemeManager.getCurrentThemeVariables().toolbarBtnColor}/>
<Input
ref="searchInput"
placeholder={i18n.t('proximoScreen.search')}
placeholderTextColor={ThemeManager.getCurrentThemeVariables().toolbarPlaceholderColor}
onChangeText={this.props.searchCallback}/>
</Item>
</Body>
);
}
getHeaderTitle() {
return (
<Body>
<Title style={{
color: ThemeManager.getCurrentThemeVariables().toolbarTextColor
}}>
{this.props.title}
</Title>
{this.props.subtitle !== '' ? <Subtitle>{this.props.subtitle}</Subtitle> : null}
</Body>
);
}
onPressBack() {
const backAction = NavigationActions.back();
this.props.navigation.dispatch(backAction);
}
render() {
// console.log("rendering CustomHeader");
let button;
// Does the app have a back button or a burger menu ?
if (this.props.hasBackButton)
button =
<Touchable
style={{padding: 6}}
onPress={this.onPressBack}>
<CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon={Platform.OS === 'ios' ? 'chevron-left' : "arrow-left"}/>
</Touchable>;
else
button = this.props.leftButton;
return (
<Header style={styles.header}
hasTabs={this.props.hasTabs}>
<Left style={{flex: 0}}>
{button}
</Left>
{this.props.hasSearchField ?
this.getSearchBar() :
this.getHeaderTitle()}
<Right style={{flex: this.props.hasSearchField ? 0 : 1}}>
{this.props.rightButton}
</Right>
</Header>);
}
};
// Fix header in status bar on Android
const styles = StyleSheet.create({
header: {
paddingTop: getStatusBarHeight(),
height: 54 + getStatusBarHeight(),
},
});

View file

@ -3,8 +3,8 @@
import * as React from 'react';
import {LinearGradient} from "expo-linear-gradient";
import {Image, StyleSheet, View} from "react-native";
import CustomMaterialIcon from "./CustomMaterialIcon";
import {Text} from "native-base";
import {MaterialCommunityIcons} from "@expo/vector-icons";
import {Text} from "react-native-paper";
import i18n from 'i18n-js';
import AppIntroSlider from "react-native-app-intro-slider";
@ -131,7 +131,10 @@ export default class CustomIntroSlider extends React.Component<Props> {
>
{item.image !== undefined ?
<Image source={item.image} style={styles.image}/>
: <CustomMaterialIcon icon={item.icon} color={'#fff'} fontSize={200} width={200}/>}
: <MaterialCommunityIcons
name={item.icon}
color={'#fff'}
size={200}/>}
<View style={{marginTop: 20}}>
<Text style={styles.title}>{item.title}</Text>
<Text style={styles.text}>{item.text}</Text>

View file

@ -1,61 +0,0 @@
// @flow
import * as React from 'react';
import {Icon} from "native-base";
import ThemeManager from '../utils/ThemeManager';
type Props = {
active: boolean,
icon: string,
color: ?string,
fontSize: number,
width: number | string,
}
/**
* Custom component defining a material icon using native base
*
* @prop active {boolean} Whether to set the icon color to active
* @prop icon {string} The icon string to use from MaterialCommunityIcons
* @prop color {string} The icon color. Use default theme color if unspecified
* @prop fontSize {number} The icon size. Use 26 if unspecified
* @prop width {number} The icon width. Use 30 if unspecified
*/
export default class CustomMaterialIcon extends React.Component<Props> {
static defaultProps = {
active: false,
color: undefined,
fontSize: 26,
width: 30,
};
shouldComponentUpdate(nextProps: Props): boolean {
return nextProps.icon !== this.props.icon ||
nextProps.active !== this.props.active ||
nextProps.width !== this.props.width ||
nextProps.fontSize !== this.props.fontSize ||
nextProps.color !== this.props.color;
}
render() {
// console.log("rendering icon " + this.props.icon);
return (
<Icon
active
name={this.props.icon}
type={'MaterialCommunityIcons'}
style={{
color:
this.props.color !== undefined ?
this.props.color :
this.props.active ?
ThemeManager.getCurrentThemeVariables().brandPrimary :
ThemeManager.getCurrentThemeVariables().customMaterialIconColor,
fontSize: this.props.fontSize,
width: this.props.width
}}
/>
);
}
}

View file

@ -1,16 +1,13 @@
// @flow
import * as React from 'react';
import {Body, Card, CardItem, H3, Left, Text, Thumbnail} from "native-base";
import CustomMaterialIcon from "./CustomMaterialIcon";
import {MaterialCommunityIcons} from "@expo/vector-icons";
import {View} from "react-native";
import ThemeManager from "../utils/ThemeManager";
import HTML from "react-native-render-html";
import {LinearGradient} from "expo-linear-gradient";
import PlatformTouchable from "react-native-platform-touchable";
import i18n from "i18n-js";
const CARD_BORDER_RADIUS = 10;
import {Avatar, Card, Text, Title} from 'react-native-paper';
type Props = {
isAvailable: boolean,
@ -31,12 +28,6 @@ export default class DashboardItem extends React.Component<Props> {
displayEvent: undefined,
};
shouldComponentUpdate(nextProps: Props): boolean {
return nextProps.isAvailable !== this.props.isAvailable ||
nextProps.subtitle !== this.props.subtitle;
}
/**
* Convert the date string given by in the event list json to a date object
* @param dateString
@ -72,72 +63,73 @@ export default class DashboardItem extends React.Component<Props> {
getEventPreviewContainer() {
if (this.props.displayEvent !== undefined && this.props.displayEvent !== null) {
const hasImage = this.props.displayEvent['logo'] !== '' && this.props.displayEvent['logo'] !== null;
return (
<View>
<CardItem style={{
paddingTop: 0,
paddingBottom: 0,
backgroundColor: 'transparent',
}}>
<Left>
{this.props.displayEvent['logo'] !== '' && this.props.displayEvent['logo'] !== null ?
<Thumbnail source={{uri: this.props.displayEvent['logo']}} square/> :
<View/>}
<Body>
<Text>{this.props.displayEvent['title']}</Text>
<Text note>{this.getFormattedEventTime(this.props.displayEvent)}</Text>
</Body>
</Left>
</CardItem>
<CardItem style={{
borderRadius: CARD_BORDER_RADIUS,
backgroundColor: 'transparent',
}}>
<Body style={{
height: this.props.displayEvent['description'].length > 50 ? 70 : 20,
<Card style={{marginBottom: 10}}>
{hasImage ?
<Card.Title
title={this.props.displayEvent['title']}
subtitle={this.getFormattedEventTime(this.props.displayEvent)}
left={() =>
<Avatar.Image
source={{uri: this.props.displayEvent['logo']}}
size={60}
style={{backgroundColor: 'transparent'}}/>
}
/> :
<Card.Title
title={this.props.displayEvent['title']}
subtitle={this.getFormattedEventTime(this.props.displayEvent)}
/>}
<View>
<Card.Content style={{
height: this.props.displayEvent['description'].length > 70 ? 100 : 50,
overflow: 'hidden',
}}>
<HTML html={"<div>" + this.props.displayEvent['description'] + "</div>"}
tagsStyles={{
p: {
color: ThemeManager.getCurrentThemeVariables().textColor,
fontSize: ThemeManager.getCurrentThemeVariables().fontSizeBase,
color: ThemeManager.getCurrentThemeVariables().text,
},
div: {color: ThemeManager.getCurrentThemeVariables().textColor},
div: {color: ThemeManager.getCurrentThemeVariables().text},
}}/>
<LinearGradient
colors={[
// Fix for ios gradient: transparent color must match final color
ThemeManager.getNightMode() ? 'rgba(42,42,42,0)' : 'rgba(255,255,255,0)',
ThemeManager.getCurrentThemeVariables().cardDefaultBg
]}
start={{x: 0, y: 0}}
end={{x: 0, y: 0.6}}
// end={[0, 0.6]}
style={{
position: 'absolute',
width: '100%',
height: 65,
bottom: -5,
}}>
<View style={{
marginLeft: 'auto',
</Card.Content>
<LinearGradient
colors={[
// Fix for ios gradient: transparent color must match final color
ThemeManager.getNightMode() ? 'rgba(42,42,42,0)' : 'rgba(255,255,255,0)',
ThemeManager.getCurrentThemeVariables().card
]}
start={{x: 0, y: 0}}
end={{x: 0, y: 0.6}}
// end={[0, 0.6]}
style={{
position: 'absolute',
width: '100%',
height: 65,
bottom: -5,
}}>
<View style={{
marginLeft: 'auto',
marginTop: 'auto',
flexDirection: 'row'
}}>
<Text style={{
marginTop: 'auto',
flexDirection: 'row'
marginBottom: 'auto',
padding: 0,
}}>
<Text style={{
marginTop: 'auto',
marginBottom: 'auto',
padding: 0,
}}>
{i18n.t("homeScreen.dashboard.seeMore")}
</Text>
<CustomMaterialIcon icon={'chevron-right'}/>
</View>
</LinearGradient>
</Body>
</CardItem>
</View>
{i18n.t("homeScreen.dashboard.seeMore")}
</Text>
<MaterialCommunityIcons
name={'chevron-right'}
size={26}
color={ThemeManager.getCurrentThemeVariables().text}/>
</View>
</LinearGradient>
</View>
</Card>
);
} else
return <View/>
@ -145,15 +137,14 @@ export default class DashboardItem extends React.Component<Props> {
getIcon() {
return (
<CustomMaterialIcon
icon={this.props.icon}
<MaterialCommunityIcons
name={this.props.icon}
color={
this.props.isAvailable ?
this.props.color :
ThemeManager.getCurrentThemeVariables().textDisabledColor
ThemeManager.getCurrentThemeVariables().textDisabled
}
fontSize={this.props.isSquare ? 50 : 40}
width={this.props.isSquare ? 50 : 40}/>
size={this.props.isSquare ? 50 : 40}/>
);
}
@ -162,19 +153,19 @@ export default class DashboardItem extends React.Component<Props> {
<View style={{
width: this.props.isSquare ? '100%' : 'auto',
}}>
<H3 style={{
<Title style={{
color: this.props.isAvailable ?
ThemeManager.getCurrentThemeVariables().textColor :
ThemeManager.getCurrentThemeVariables().listNoteColor,
ThemeManager.getCurrentThemeVariables().text :
ThemeManager.getCurrentThemeVariables().textDisabled,
textAlign: this.props.isSquare ? 'center' : 'left',
width: this.props.isSquare ? '100%' : 'auto',
}}>
{this.props.title}
</H3>
</Title>
<Text style={{
color: this.props.isAvailable ?
ThemeManager.getCurrentThemeVariables().listNoteColor :
ThemeManager.getCurrentThemeVariables().textDisabledColor,
ThemeManager.getCurrentThemeVariables().text :
ThemeManager.getCurrentThemeVariables().textDisabled,
textAlign: this.props.isSquare ? 'center' : 'left',
width: this.props.isSquare ? '100%' : 'auto',
}}>
@ -187,21 +178,12 @@ export default class DashboardItem extends React.Component<Props> {
getContent() {
if (this.props.isSquare) {
return (
<Body>
<View>
<View style={{marginLeft: 'auto', marginRight: 'auto'}}>
{this.getIcon()}
</View>
{this.getText()}
</Body>
);
} else {
return (
<Left>
{this.getIcon()}
<Body>
{this.getText()}
</Body>
</Left>
</View>
);
}
}
@ -216,33 +198,41 @@ export default class DashboardItem extends React.Component<Props> {
else
marginRight = 0
}
const color = this.props.isAvailable ?
ThemeManager.getCurrentThemeVariables().text :
ThemeManager.getCurrentThemeVariables().textDisabled;
return (
<Card style={{
flex: 0,
width: this.props.isSquare ? '48%' : 'auto',
marginLeft: this.props.isSquare ? 0 : 10,
marginRight: marginRight,
marginTop: 10,
borderRadius: CARD_BORDER_RADIUS,
backgroundColor: ThemeManager.getCurrentThemeVariables().cardDefaultBg,
overflow: 'hidden',
}}>
<PlatformTouchable
onPress={this.props.clickAction}
style={{
zIndex: 100,
minHeight: this.props.isSquare ? 150 : 'auto',
}}
>
<Card
style={{
width: this.props.isSquare ? '48%' : 'auto',
marginLeft: this.props.isSquare ? 0 : 10,
marginRight: marginRight,
marginTop: 10,
overflow: 'hidden',
}}
onPress={this.props.clickAction}>
{this.props.isSquare ?
<Card.Content>
{this.getContent()}
</Card.Content>
:
<View>
<CardItem style={{
backgroundColor: 'transparent',
}}>
{this.getContent()}
</CardItem>
{this.getEventPreviewContainer()}
</View>
</PlatformTouchable>
<Card.Title
title={this.props.title}
titleStyle={{color: color}}
subtitle={this.props.subtitle}
subtitleStyle={{color: color}}
left={(props) => <Avatar.Icon
{...props}
icon={this.props.icon}
color={this.props.isAvailable ? this.props.color : ThemeManager.getCurrentThemeVariables().textDisabled}
size={60}
style={{backgroundColor: 'transparent'}}/>}
/>
<Card.Content>
{this.getEventPreviewContainer()}
</Card.Content>
</View>}
</Card>
);
}

View file

@ -0,0 +1,41 @@
import * as React from 'react';
import {ActivityIndicator, Subheading, withTheme} from 'react-native-paper';
import {View} from "react-native";
import {MaterialCommunityIcons} from "@expo/vector-icons";
function EmptyWebSectionListItem(props) {
const { colors } = props.theme;
return (
<View>
<View style={{
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: 100,
marginBottom: 20
}}>
{props.refreshing ?
<ActivityIndicator
animating={true}
size={'large'}
color={colors.primary}/>
:
<MaterialCommunityIcons
name={props.icon}
size={100}
color={colors.textDisabled}/>}
</View>
<Subheading style={{
textAlign: 'center',
marginRight: 20,
marginLeft: 20,
color: colors.textDisabled
}}>
{props.text}
</Subheading>
</View>
);
}
export default withTheme(EmptyWebSectionListItem);

42
components/FeedItem.js Normal file
View file

@ -0,0 +1,42 @@
import * as React from 'react';
import {Avatar, Button, Card, withTheme} from 'react-native-paper';
import {TouchableOpacity, View} from "react-native";
import Autolink from "react-native-autolink";
import i18n from "i18n-js";
const ICON_AMICALE = require('../assets/amicale.png');
function FeedItem(props) {
const {colors} = props.theme;
return (
<Card style={{margin: 10}}>
<Card.Title
title={props.title}
subtitle={props.subtitle}
left={props => <Avatar.Image size={48} source={ICON_AMICALE}
style={{backgroundColor: 'transparent'}}/>}
/>
{props.full_picture !== '' && props.full_picture !== undefined ?
<TouchableOpacity onPress={props.onImagePress}>
<Card.Cover source={{uri: props.full_picture}}/>
</TouchableOpacity> : <View/>}
<Card.Content>
{props.message !== undefined ?
<Autolink
text={props.message}
hashtag="facebook"
style={{color: colors.text}}
/> : <View/>
}
</Card.Content>
<Card.Actions>
<Button
color={'#57aeff'}
onPress={props.onOutLinkPress}
icon={'facebook'}>{i18n.t('homeScreen.dashboard.seeMore')}</Button>
</Card.Actions>
</Card>
);
}
export default withTheme(FeedItem);

View file

@ -1,399 +0,0 @@
// @flow
import * as React from 'react';
import WebDataManager from "../utils/WebDataManager";
import {H3, Spinner, Tab, TabHeading, Tabs, Text} from "native-base";
import {RefreshControl, SectionList, View} from "react-native";
import CustomMaterialIcon from "./CustomMaterialIcon";
import i18n from 'i18n-js';
import ThemeManager from "../utils/ThemeManager";
import BaseContainer from "./BaseContainer";
type Props = {
navigation: Object,
}
type State = {
refreshing: boolean,
firstLoading: boolean,
fetchedData: Object,
machinesWatched: Array<string>,
};
/**
* Class used to create a basic list view using online json data.
* Used by inheriting from it and redefining getters.
*/
export default class FetchedDataSectionList extends React.Component<Props, State> {
webDataManager: WebDataManager;
willFocusSubscription: function;
willBlurSubscription: function;
refreshInterval: IntervalID;
refreshTime: number;
lastRefresh: Date;
minTimeBetweenRefresh = 60;
state = {
refreshing: false,
firstLoading: true,
fetchedData: {},
machinesWatched: [],
};
onRefresh: Function;
onFetchSuccess: Function;
onFetchError: Function;
renderSectionHeaderEmpty: Function;
renderSectionHeaderNotEmpty: Function;
renderItemEmpty: Function;
renderItemNotEmpty: Function;
constructor(fetchUrl: string, refreshTime: number) {
super();
this.webDataManager = new WebDataManager(fetchUrl);
this.refreshTime = refreshTime;
// creating references to functions used in render()
this.onRefresh = this.onRefresh.bind(this);
this.onFetchSuccess = this.onFetchSuccess.bind(this);
this.onFetchError = this.onFetchError.bind(this);
this.renderSectionHeaderEmpty = this.renderSectionHeader.bind(this, true);
this.renderSectionHeaderNotEmpty = this.renderSectionHeader.bind(this, false);
this.renderItemEmpty = this.renderItem.bind(this, true);
this.renderItemNotEmpty = this.renderItem.bind(this, false);
}
/**
* Get the translation for the header in the current language
* @return {string}
*/
getHeaderTranslation(): string {
return "Header";
}
/**
* Get the translation for the toasts in the current language
* @return {string}
*/
getUpdateToastTranslations(): Array<string> {
return ["whoa", "nah"];
}
setMinTimeRefresh(value: number) {
this.minTimeBetweenRefresh = value;
}
/**
* Register react navigation events on first screen load.
* Allows to detect when the screen is focused
*/
componentDidMount() {
this.willFocusSubscription = this.props.navigation.addListener(
'willFocus', this.onScreenFocus.bind(this));
this.willBlurSubscription = this.props.navigation.addListener(
'willBlur', this.onScreenBlur.bind(this));
}
/**
* Refresh data when focusing the screen and setup a refresh interval if asked to
*/
onScreenFocus() {
this.onRefresh();
if (this.refreshTime > 0)
this.refreshInterval = setInterval(this.onRefresh.bind(this), this.refreshTime)
}
/**
* Remove any interval on un-focus
*/
onScreenBlur() {
clearInterval(this.refreshInterval);
}
/**
* Unregister from event when un-mounting components
*/
componentWillUnmount() {
if (this.willBlurSubscription !== undefined)
this.willBlurSubscription.remove();
if (this.willFocusSubscription !== undefined)
this.willFocusSubscription.remove();
}
onFetchSuccess(fetchedData: Object) {
this.setState({
fetchedData: fetchedData,
refreshing: false,
firstLoading: false
});
this.lastRefresh = new Date();
}
onFetchError() {
this.setState({
fetchedData: {},
refreshing: false,
firstLoading: false
});
this.webDataManager.showUpdateToast(this.getUpdateToastTranslations()[0], this.getUpdateToastTranslations()[1]);
}
/**
* Refresh data and show a toast if any error occurred
* @private
*/
onRefresh() {
let canRefresh;
if (this.lastRefresh !== undefined)
canRefresh = (new Date().getTime() - this.lastRefresh.getTime()) / 1000 > this.minTimeBetweenRefresh;
else
canRefresh = true;
if (canRefresh) {
this.setState({refreshing: true});
this.webDataManager.readData()
.then(this.onFetchSuccess)
.catch(this.onFetchError);
}
}
/**
* Get the render item to be used for display in the list.
* Must be overridden by inheriting class.
*
* @param item
* @param section
* @return {*}
*/
getRenderItem(item: Object, section: Object) {
return <View/>;
}
/**
* Get the render item to be used for the section title in the list.
* Must be overridden by inheriting class.
*
* @param title
* @return {*}
*/
getRenderSectionHeader(title: string) {
return <View/>;
}
/**
* Get the render item to be used when the list is empty.
* No need to be overridden, has good defaults.
*
* @param text
* @param isSpinner
* @param icon
* @return {*}
*/
getEmptyRenderItem(text: string, isSpinner: boolean, icon: string) {
return (
<View>
<View style={{
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: 100,
marginBottom: 20
}}>
{isSpinner ?
<Spinner/>
:
<CustomMaterialIcon
icon={icon}
fontSize={100}
width={100}
color={ThemeManager.getCurrentThemeVariables().fetchedDataSectionListErrorText}/>}
</View>
<H3 style={{
textAlign: 'center',
marginRight: 20,
marginLeft: 20,
color: ThemeManager.getCurrentThemeVariables().fetchedDataSectionListErrorText
}}>
{text}
</H3>
</View>);
}
/**
* Create the dataset to be used in the list from the data fetched.
* Must be overridden.
*
* @param fetchedData {Object}
* @return {Array}
*/
createDataset(fetchedData: Object): Array<Object> {
return [];
}
datasetKeyExtractor(item: Object) {
return item.text
}
/**
* Create the dataset when no fetched data is available.
* No need to be overridden, has good defaults.
*
* @return
*/
createEmptyDataset() {
return [
{
title: '',
data: [
{
text: this.state.refreshing ?
i18n.t('general.loading') :
i18n.t('general.networkError'),
isSpinner: this.state.refreshing,
icon: this.state.refreshing ?
'refresh' :
'access-point-network-off'
}
],
keyExtractor: this.datasetKeyExtractor,
}
];
}
/**
* Should the app use a tab layout instead of a section list ?
* If yes, each section will be rendered in a new tab.
* Can be overridden.
*
* @return {boolean}
*/
hasTabs() {
return false;
}
hasBackButton() {
return false;
}
getRightButton() {
return <View/>
}
hasStickyHeader() {
return false;
}
hasSideMenu() {
return true;
}
renderSectionHeader(isEmpty: boolean, {section: {title}} : Object) {
return isEmpty ?
<View/> :
this.getRenderSectionHeader(title)
}
renderItem(isEmpty: boolean, {item, section}: Object) {
return isEmpty ?
this.getEmptyRenderItem(item.text, item.isSpinner, item.icon) :
this.getRenderItem(item, section)
}
/**
* Get the section list render using the generated dataset
*
* @param dataset
* @return
*/
getSectionList(dataset: Array<Object>) {
let isEmpty = dataset[0].data.length === 0;
if (isEmpty)
dataset = this.createEmptyDataset();
return (
<SectionList
sections={dataset}
stickySectionHeadersEnabled={this.hasStickyHeader()}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this.onRefresh}
/>
}
renderSectionHeader={isEmpty ? this.renderSectionHeaderEmpty : this.renderSectionHeaderNotEmpty}
renderItem={isEmpty ? this.renderItemEmpty : this.renderItemNotEmpty}
style={{minHeight: 300, width: '100%'}}
contentContainerStyle={
isEmpty ?
{flexGrow: 1, justifyContent: 'center', alignItems: 'center'} : {}
}
/>
);
}
/**
* Generate the tabs containing the lists
*
* @param dataset
* @return
*/
getTabbedView(dataset: Array<Object>) {
let tabbedView = [];
for (let i = 0; i < dataset.length; i++) {
tabbedView.push(
<Tab heading={
<TabHeading>
<CustomMaterialIcon
icon={dataset[i].icon}
color={ThemeManager.getCurrentThemeVariables().tabIconColor}
fontSize={20}
/>
<Text>{dataset[i].title}</Text>
</TabHeading>}
key={dataset[i].title}
style={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
{this.getSectionList(
[
{
title: dataset[i].title,
data: dataset[i].data,
extraData: dataset[i].extraData,
keyExtractor: dataset[i].keyExtractor
}
]
)}
</Tab>);
}
return tabbedView;
}
render() {
// console.log("rendering FetchedDataSectionList");
const dataset = this.createDataset(this.state.fetchedData);
return (
<BaseContainer
navigation={this.props.navigation}
headerTitle={this.getHeaderTranslation()}
headerRightButton={this.getRightButton()}
hasTabs={this.hasTabs()}
hasBackButton={this.hasBackButton()}
hasSideMenu={this.hasSideMenu()}
>
{this.hasTabs() ?
<Tabs
tabContainerStyle={{
elevation: 0, // Fix for android shadow
}}
>
{this.getTabbedView(dataset)}
</Tabs>
:
this.getSectionList(dataset)
}
</BaseContainer>
);
}
}

View file

@ -0,0 +1,16 @@
import * as React from 'react';
import {IconButton, withTheme} from 'react-native-paper';
function HeaderButton(props) {
const { colors } = props.theme;
return (
<IconButton
icon={props.icon}
size={26}
color={colors.text}
onPress={props.onPress}
/>
);
}
export default withTheme(HeaderButton);

View file

@ -0,0 +1,88 @@
import * as React from 'react';
import {Card, Avatar, List, Text, withTheme} from 'react-native-paper';
import {View} from "react-native";
import ProxiwashConstants from "../constants/ProxiwashConstants";
function ProxiwashListItem(props) {
const {colors} = props.theme;
let stateColors = {};
stateColors[ProxiwashConstants.machineStates.TERMINE] = colors.proxiwashFinishedColor;
stateColors[ProxiwashConstants.machineStates.DISPONIBLE] = colors.proxiwashReadyColor;
stateColors[ProxiwashConstants.machineStates["EN COURS"]] = colors.proxiwashRunningColor;
stateColors[ProxiwashConstants.machineStates.HS] = colors.proxiwashBrokenColor;
stateColors[ProxiwashConstants.machineStates.ERREUR] = colors.proxiwashErrorColor;
const icon = (
props.isWatched ?
<Avatar.Icon
icon={'bell-ring'}
size={45}
color={colors.primary}
style={{backgroundColor: 'transparent'}}
/> :
<Avatar.Icon
icon={props.isDryer ? 'tumble-dryer' : 'washing-machine'}
color={colors.text}
size={40}
style={{backgroundColor: 'transparent'}}
/>
);
return (
<Card
style={{
margin: 5,
}}
onPress={props.onPress}
>
{ProxiwashConstants.machineStates[props.state] === ProxiwashConstants.machineStates["EN COURS"] ?
<Card style={{
height: '100%',
position: 'absolute',
left: 0,
width: '100%',
backgroundColor: colors.proxiwashRunningBgColor,
elevation: 0
}}/> : null
}
<Card style={{
height: '100%',
position: 'absolute',
left: 0,
width: props.progress,
backgroundColor: stateColors[ProxiwashConstants.machineStates[props.state]],
elevation: 0
}}/>
<Card.Title
title={props.title}
subtitle={props.description}
style={{
backgroundColor: 'transparent',
height: 64
}}
left={() => icon}
right={() => (
<View style={{flexDirection: 'row'}}>
<View style={{
justifyContent: 'center',
}}>
<Text style={
ProxiwashConstants.machineStates[props.state] === ProxiwashConstants.machineStates.TERMINE ?
{fontWeight: 'bold',} : {}}
>
{props.statusText}
</Text>
</View>
<Avatar.Icon
icon={props.statusIcon}
color={colors.text}
size={30}
style={{backgroundColor: 'transparent'}}
/>
</View>)}
/>
</Card>
);
}
export default withTheme(ProxiwashListItem);

View file

@ -1,18 +1,17 @@
// @flow
import * as React from 'react';
import {Dimensions, FlatList, Image, Linking, Platform, StyleSheet} from 'react-native';
import {Badge, Container, Left, ListItem, Right, Text} from "native-base";
import {Dimensions, FlatList, Image, Platform, StyleSheet, View} from 'react-native';
import i18n from "i18n-js";
import CustomMaterialIcon from '../components/CustomMaterialIcon';
import ThemeManager from "../utils/ThemeManager";
import * as WebBrowser from 'expo-web-browser';
import SidebarDivider from "./SidebarDivider";
import SidebarItem from "./SidebarItem";
const deviceWidth = Dimensions.get("window").width;
const drawerCover = require("../assets/drawer-cover.png");
type Props = {
navigation: Object,
state: Object,
};
type State = {
@ -42,42 +41,18 @@ export default class SideBar extends React.Component<Props, State> {
// Dataset used to render the drawer
this.dataSet = [
{
name: i18n.t('sidenav.divider1'),
route: "Divider1"
},
{
name: "Amicale",
route: "AmicaleScreen",
icon: "alpha-a-box",
},
{
name: "Élus Étudiants",
route: "ElusEtudScreen",
icon: "alpha-e-box",
},
{
name: "Wiketud",
route: "WiketudScreen",
icon: "wikipedia",
},
{
name: "Tutor'INSA",
route: "TutorInsaScreen",
icon: "school",
name: i18n.t('screens.home'),
route: "Main",
icon: "home",
},
{
name: i18n.t('sidenav.divider2'),
route: "Divider2"
},
{
name: i18n.t('screens.bluemind'),
route: "BlueMindScreen",
icon: "email",
},
{
name: i18n.t('screens.ent'),
route: "EntScreen",
icon: "notebook",
name: i18n.t('screens.menuSelf'),
route: "SelfMenuScreen",
icon: "silverware-fork-knife",
},
{
name: i18n.t('screens.availableRooms'),
@ -85,9 +60,49 @@ export default class SideBar extends React.Component<Props, State> {
icon: "calendar-check",
},
{
name: i18n.t('screens.menuSelf'),
route: "SelfMenuScreen",
icon: "silverware-fork-knife",
name: i18n.t('screens.bib'),
route: "BibScreen",
icon: "book",
},
{
name: i18n.t('screens.bluemind'),
route: "BlueMindScreen",
link: "https://etud-mel.insa-toulouse.fr/webmail/",
icon: "email",
},
{
name: i18n.t('screens.ent'),
route: "EntScreen",
link: "https://ent.insa-toulouse.fr/",
icon: "notebook",
},
{
name: i18n.t('sidenav.divider1'),
route: "Divider1"
},
{
name: "Amicale",
route: "AmicaleScreen",
link: "https://amicale-insat.fr/",
icon: "alpha-a-box",
},
{
name: "Élus Étudiants",
route: "ElusEtudScreen",
link: "https://etud.insa-toulouse.fr/~eeinsat/",
icon: "alpha-e-box",
},
{
name: "Wiketud",
route: "WiketudScreen",
link: "https://wiki.etud.insa-toulouse.fr",
icon: "wikipedia",
},
{
name: "Tutor'INSA",
route: "TutorInsaScreen",
link: "https://www.etud.insa-toulouse.fr/~tutorinsa/",
icon: "school",
},
{
name: i18n.t('sidenav.divider3'),
@ -112,8 +127,11 @@ export default class SideBar extends React.Component<Props, State> {
}
onListItemPress(route: string) {
this.props.navigation.navigate(route);
onListItemPress(item: Object) {
if (item.link === undefined)
this.props.navigation.navigate(item.route);
else
WebBrowser.openBrowserAsync(item.link);
}
@ -123,66 +141,34 @@ export default class SideBar extends React.Component<Props, State> {
getRenderItem({item}: Object) {
const onListItemPress = this.onListItemPress.bind(this, item.route);
const onListItemPress = this.onListItemPress.bind(this, item);
if (item.icon !== undefined) {
return (
<ListItem
button
noBorder
selected={this.state.active === item.route}
<SidebarItem
title={item.name}
icon={item.icon}
onPress={onListItemPress}
>
<Left>
<CustomMaterialIcon
icon={item.icon}
active={this.state.active === item.route}
/>
<Text style={styles.text}>
{item.name}
</Text>
</Left>
{item.types &&
<Right style={{flex: 1}}>
<Badge
style={{
borderRadius: 3,
height: 25,
width: 72,
backgroundColor: item.bg
}}
>
<Text
style={styles.badgeText}
>{`${item.types} Types`}</Text>
</Badge>
</Right>}
</ListItem>
/>
);
} else {
return (
<ListItem itemDivider>
<Text>{item.name}</Text>
</ListItem>
<SidebarDivider title={item.name}/>
);
}
}
render() {
// console.log("rendering SideBar");
return (
<Container style={{
backgroundColor: ThemeManager.getCurrentThemeVariables().sideMenuBgColor,
}}>
<Image source={drawerCover} style={styles.drawerCover}/>
<View style={{height: '100%'}}>
<Image source={require("../assets/drawer-cover.png")} style={styles.drawerCover}/>
<FlatList
data={this.dataSet}
extraData={this.state}
keyExtractor={this.listKeyExtractor}
renderItem={this.getRenderItem}
/>
</Container>
</View>
);
}
}

View file

@ -0,0 +1,23 @@
import * as React from 'react';
import { withTheme } from 'react-native-paper';
import {DrawerItem} from "@react-navigation/drawer";
function SidebarDivider(props) {
const { colors } = props.theme;
return (
<DrawerItem
label={props.title}
focused={false}
onPress={undefined}
style={{
marginLeft: 0,
marginRight: 0,
padding: 0,
borderRadius: 0,
backgroundColor: colors.dividerBackground
}}
/>
);
}
export default withTheme(SidebarDivider);

28
components/SidebarItem.js Normal file
View file

@ -0,0 +1,28 @@
import * as React from 'react';
import {withTheme} from 'react-native-paper';
import {DrawerItem} from "@react-navigation/drawer";
import {MaterialCommunityIcons} from "@expo/vector-icons";
function SidebarItem(props) {
const {colors} = props.theme;
return (
<DrawerItem
label={props.title}
focused={false}
onPress={props.onPress}
icon={({color, size}) =>
<MaterialCommunityIcons color={color} size={size} name={props.icon}/>}
style={{
marginLeft: 0,
marginRight: 0,
padding: 0,
borderRadius: 0,
}}
labelStyle={{
color: colors.text,
}}
/>
);
}
export default withTheme(SidebarItem);

View file

@ -0,0 +1,55 @@
import * as React from 'react';
import {Card, Text, Title, withTheme} from 'react-native-paper';
import {View} from "react-native";
import {MaterialCommunityIcons} from "@expo/vector-icons";
function SquareDashboardItem(props) {
const { colors } = props.theme;
return (
<Card
style={{
width: '48%',
marginTop: 10,
marginRight: props.isLeft ? '4%': 0,
overflow: 'hidden',
}}
onPress={props.clickAction}>
<Card.Content>
<View style={{marginLeft: 'auto', marginRight: 'auto'}}>
<MaterialCommunityIcons
name={props.icon}
color={
props.isAvailable ?
props.color :
colors.textDisabled
}
size={50}/>
</View>
<View style={{
width: '100%',
}}>
<Title style={{
color: props.isAvailable ?
colors.text :
colors.textDisabled,
textAlign: 'center',
width: '100%',
}}>
{props.title}
</Title>
<Text style={{
color: props.isAvailable ?
colors.text :
colors.textDisabled,
textAlign: 'center',
width: '100%',
}}>
{props.subtitle}
</Text>
</View>
</Card.Content>
</Card>
);
}
export default withTheme(SquareDashboardItem);

View file

@ -0,0 +1,226 @@
// @flow
import * as React from 'react';
import WebDataManager from "../utils/WebDataManager";
import i18n from "i18n-js";
import {Snackbar} from 'react-native-paper';
import {RefreshControl, SectionList, View} from "react-native";
import EmptyWebSectionListItem from "./EmptyWebSectionListItem";
type Props = {
navigation: Object,
fetchUrl: string,
refreshTime: number,
renderItem: React.Node,
renderSectionHeader: React.Node,
stickyHeader: boolean,
createDataset: Function,
}
type State = {
refreshing: boolean,
firstLoading: boolean,
fetchedData: Object,
snackbarVisible: boolean
};
/**
* Custom component defining a material icon using native base
*
* @prop active {boolean} Whether to set the icon color to active
* @prop icon {string} The icon string to use from MaterialCommunityIcons
* @prop color {string} The icon color. Use default theme color if unspecified
* @prop fontSize {number} The icon size. Use 26 if unspecified
* @prop width {number} The icon width. Use 30 if unspecified
*/
export default class WebSectionList extends React.Component<Props, State> {
static defaultProps = {
renderSectionHeader: null,
stickyHeader: false,
};
webDataManager: WebDataManager;
refreshInterval: IntervalID;
lastRefresh: Date;
state = {
refreshing: false,
firstLoading: true,
fetchedData: {},
snackbarVisible: false
};
onRefresh: Function;
onFetchSuccess: Function;
onFetchError: Function;
getEmptyRenderItem: Function;
getEmptySectionHeader: Function;
showSnackBar: Function;
hideSnackBar: Function;
constructor() {
super();
// creating references to functions used in render()
this.onRefresh = this.onRefresh.bind(this);
this.onFetchSuccess = this.onFetchSuccess.bind(this);
this.onFetchError = this.onFetchError.bind(this);
this.getEmptyRenderItem = this.getEmptyRenderItem.bind(this);
this.getEmptySectionHeader = this.getEmptySectionHeader.bind(this);
this.showSnackBar = this.showSnackBar.bind(this);
this.hideSnackBar = this.hideSnackBar.bind(this);
}
/**
* Register react navigation events on first screen load.
* Allows to detect when the screen is focused
*/
componentDidMount() {
this.webDataManager = new WebDataManager(this.props.fetchUrl);
const onScreenFocus = this.onScreenFocus.bind(this);
const onScreenBlur = this.onScreenBlur.bind(this);
this.props.navigation.addListener('focus', onScreenFocus);
this.props.navigation.addListener('blur', onScreenBlur);
}
/**
* Refresh data when focusing the screen and setup a refresh interval if asked to
*/
onScreenFocus() {
this.onRefresh();
if (this.props.refreshTime > 0)
this.refreshInterval = setInterval(this.onRefresh, this.props.refreshTime)
}
/**
* Remove any interval on un-focus
*/
onScreenBlur() {
clearInterval(this.refreshInterval);
}
onFetchSuccess(fetchedData: Object) {
this.setState({
fetchedData: fetchedData,
refreshing: false,
firstLoading: false
});
this.lastRefresh = new Date();
}
onFetchError() {
this.setState({
fetchedData: {},
refreshing: false,
firstLoading: false
});
this.showSnackBar();
// this.webDataManager.showUpdateToast(this.props.updateErrorText);
}
/**
* Refresh data and show a toast if any error occurred
* @private
*/
onRefresh() {
let canRefresh;
if (this.lastRefresh !== undefined)
canRefresh = (new Date().getTime() - this.lastRefresh.getTime()) > this.props.refreshTime;
else
canRefresh = true;
if (canRefresh) {
this.setState({refreshing: true});
this.webDataManager.readData()
.then(this.onFetchSuccess)
.catch(this.onFetchError);
}
}
getEmptySectionHeader({section}: Object) {
return <View/>;
}
getEmptyRenderItem({item}: Object) {
return (
<EmptyWebSectionListItem
text={item.text}
icon={item.icon}
refreshing={this.state.refreshing}
/>
);
}
createEmptyDataset() {
return [
{
title: '',
data: [
{
text: this.state.refreshing ?
i18n.t('general.loading') :
i18n.t('general.networkError'),
isSpinner: this.state.refreshing,
icon: this.state.refreshing ?
'refresh' :
'access-point-network-off'
}
],
keyExtractor: this.datasetKeyExtractor,
}
];
}
datasetKeyExtractor(item: Object) {
return item.text
}
showSnackBar() {
this.setState({snackbarVisible: true})
}
hideSnackBar() {
this.setState({snackbarVisible: false})
}
render() {
let dataset = this.props.createDataset(this.state.fetchedData);
const isEmpty = dataset[0].data.length === 0;
const shouldRenderHeader = !isEmpty && (this.props.renderSectionHeader !== null);
if (isEmpty)
dataset = this.createEmptyDataset();
return (
<View>
<Snackbar
visible={this.state.snackbarVisible}
onDismiss={this.hideSnackBar}
action={{
label: 'OK',
onPress: this.hideSnackBar,
}}
duration={4000}
>
{i18n.t("homeScreen.listUpdateFail")}
</Snackbar>
<SectionList
sections={dataset}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this.onRefresh}
/>
}
renderSectionHeader={shouldRenderHeader ? this.props.renderSectionHeader : this.getEmptySectionHeader}
renderItem={isEmpty ? this.getEmptyRenderItem : this.props.renderItem}
style={{minHeight: 300, width: '100%'}}
stickySectionHeadersEnabled={this.props.stickyHeader}
contentContainerStyle={
isEmpty ?
{flexGrow: 1, justifyContent: 'center', alignItems: 'center'} : {}
}
/>
</View>
);
}
}

View file

@ -1,13 +1,11 @@
// @flow
import * as React from 'react';
import {Linking, Platform, View} from 'react-native';
import {Body, Footer, Left, Right, Spinner, Tab, TabHeading, Tabs, Text} from 'native-base';
import {View} from 'react-native';
import WebView from "react-native-webview";
import Touchable from "react-native-platform-touchable";
import CustomMaterialIcon from "../components/CustomMaterialIcon";
import ThemeManager from "../utils/ThemeManager";
import BaseContainer from "../components/BaseContainer";
import {ActivityIndicator} from 'react-native-paper';
import HeaderButton from "./HeaderButton";
type Props = {
navigation: Object,
@ -50,25 +48,25 @@ export default class WebViewScreen extends React.Component<Props> {
this.onOpenWebLink = this.onOpenWebLink.bind(this);
}
openWebLink(url: string) {
Linking.openURL(url).catch((err) => console.error('Error opening link', err));
componentDidMount() {
const rightButton = this.getRefreshButton.bind(this);
this.props.navigation.setOptions({
headerRight: rightButton,
});
}
getHeaderButton(clickAction: Function, icon: string) {
return (
<Touchable
style={{padding: 6}}
onPress={clickAction}>
<CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon={icon}/>
</Touchable>
<HeaderButton icon={icon} onPress={clickAction}/>
);
}
getRefreshButton() {
return (
<View style={{flexDirection: 'row'}}>
<View style={{
flexDirection: 'row',
marginRight: 10
}}>
{this.getHeaderButton(this.onRefreshClicked, 'refresh')}
</View>
);
@ -106,7 +104,7 @@ export default class WebViewScreen extends React.Component<Props> {
getRenderLoading() {
return (
<View style={{
backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor,
backgroundColor: ThemeManager.getCurrentThemeVariables().background,
position: 'absolute',
top: 0,
right: 0,
@ -116,7 +114,10 @@ export default class WebViewScreen extends React.Component<Props> {
alignItems: 'center',
justifyContent: 'center'
}}>
<Spinner/>
<ActivityIndicator
animating={true}
size={'large'}
color={ThemeManager.getCurrentThemeVariables().primary}/>
</View>
);
}
@ -138,81 +139,11 @@ export default class WebViewScreen extends React.Component<Props> {
);
}
getTabbedWebview() {
let tabbedView = [];
for (let i = 0; i < this.props.data.length; i++) {
tabbedView.push(
<Tab heading={
<TabHeading>
<CustomMaterialIcon
icon={this.props.data[i]['icon']}
color={ThemeManager.getCurrentThemeVariables().tabIconColor}
fontSize={20}
/>
<Text>{this.props.data[i]['name']}</Text>
</TabHeading>}
key={this.props.data[i]['url']}
style={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
{this.getWebview(this.props.data[i])}
</Tab>);
}
return tabbedView;
}
render() {
// console.log("rendering WebViewScreen");
const nav = this.props.navigation;
this.webviewArray = [];
return (
<BaseContainer
navigation={nav}
headerTitle={this.props.headerTitle}
headerRightButton={this.getRefreshButton()}
hasBackButton={this.props.hasHeaderBackButton}
hasSideMenu={this.props.hasSideMenu}
enableRotation={true}
hideHeaderOnLandscape={true}
hasTabs={this.props.data.length > 1}>
{this.props.data.length === 1 ?
this.getWebview(this.props.data[0]) :
<Tabs
tabContainerStyle={{
elevation: 0, // Fix for android shadow
}}
locked={true}
style={{
backgroundColor: Platform.OS === 'ios' ?
ThemeManager.getCurrentThemeVariables().tabDefaultBg :
ThemeManager.getCurrentThemeVariables().brandPrimary
}}
>
{this.getTabbedWebview()}
</Tabs>}
{this.props.hasFooter && this.props.data.length === 1 ?
<Footer>
<Left style={{
paddingLeft: 6,
}}>
{this.getHeaderButton(this.onOpenWebLink, 'open-in-new')}
</Left>
<Body/>
<Right style={{
flexDirection: 'row',
alignItems: 'flex-end',
paddingRight: 6
}}>
<View style={{
flexDirection: 'row',
marginRight: 0,
marginLeft: 'auto'
}}>
{this.getHeaderButton(this.onGoBackWebview, 'chevron-left')}
{this.getHeaderButton(this.onGoForwardWebview, 'chevron-right')}
</View>
</Right>
</Footer> : <View/>}
</BaseContainer>
this.getWebview(this.props.data[0])
);
}
}

View file

@ -0,0 +1,10 @@
export default {
machineStates: {
"TERMINE": "0",
"DISPONIBLE": "1",
"EN COURS": "2",
"HS": "3",
"ERREUR": "4"
},
};

View file

@ -1,39 +0,0 @@
// @flow
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
export default (variables /* : * */ = variable) => {
const badgeTheme = {
'.primary': {
backgroundColor: variables.buttonPrimaryBg
},
'.warning': {
backgroundColor: variables.buttonWarningBg
},
'.info': {
backgroundColor: variables.buttonInfoBg
},
'.success': {
backgroundColor: variables.buttonSuccessBg
},
'.danger': {
backgroundColor: variables.buttonDangerBg
},
'NativeBase.Text': {
color: variables.badgeColor,
fontSize: variables.fontSizeBase,
lineHeight: variables.lineHeight - 1,
textAlign: 'center',
paddingHorizontal: 3
},
backgroundColor: variables.badgeBg,
padding: variables.badgePadding,
paddingHorizontal: 6,
alignSelf: 'flex-start',
justifyContent: variables.platform === PLATFORM.IOS ? 'center' : undefined,
borderRadius: 13.5,
height: 27
};
return badgeTheme;
};

View file

@ -1,11 +0,0 @@
// @flow
export default () => {
const bodyTheme = {
flex: 1,
alignItems: 'center',
alignSelf: 'center'
};
return bodyTheme;
};

View file

@ -1,386 +0,0 @@
// @flow
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
export default (variables /* : * */ = variable) => {
const platformStyle = variables.platformStyle;
const platform = variables.platform;
const darkCommon = {
'NativeBase.Text': {
color: variables.brandDark
},
'NativeBase.Icon': {
color: variables.brandDark
},
'NativeBase.IconNB': {
color: variables.brandDark
}
};
const lightCommon = {
'NativeBase.Text': {
color: variables.brandLight
},
'NativeBase.Icon': {
color: variables.brandLight
},
'NativeBase.IconNB': {
color: variables.brandLight
}
};
const primaryCommon = {
'NativeBase.Text': {
color: variables.buttonPrimaryBg
},
'NativeBase.Icon': {
color: variables.buttonPrimaryBg
},
'NativeBase.IconNB': {
color: variables.buttonPrimaryBg
}
};
const successCommon = {
'NativeBase.Text': {
color: variables.buttonSuccessBg
},
'NativeBase.Icon': {
color: variables.buttonSuccessBg
},
'NativeBase.IconNB': {
color: variables.buttonSuccessBg
}
};
const infoCommon = {
'NativeBase.Text': {
color: variables.buttonInfoBg
},
'NativeBase.Icon': {
color: variables.buttonInfoBg
},
'NativeBase.IconNB': {
color: variables.buttonInfoBg
}
};
const warningCommon = {
'NativeBase.Text': {
color: variables.buttonWarningBg
},
'NativeBase.Icon': {
color: variables.buttonWarningBg
},
'NativeBase.IconNB': {
color: variables.buttonWarningBg
}
};
const dangerCommon = {
'NativeBase.Text': {
color: variables.buttonDangerBg
},
'NativeBase.Icon': {
color: variables.buttonDangerBg
},
'NativeBase.IconNB': {
color: variables.buttonDangerBg
}
};
const buttonTheme = {
'.disabled': {
'.transparent': {
backgroundColor: 'transparent',
'NativeBase.Text': {
color: variables.buttonDisabledBg
},
'NativeBase.Icon': {
color: variables.buttonDisabledBg
},
'NativeBase.IconNB': {
color: variables.buttonDisabledBg
}
},
'NativeBase.Icon': {
color: variables.brandLight
},
'NativeBase.IconNB': {
color: variables.brandLight
},
backgroundColor: variables.buttonDisabledBg
},
'.bordered': {
'.dark': {
...darkCommon,
backgroundColor: 'transparent',
borderColor: variables.brandDark,
borderWidth: variables.borderWidth * 2
},
'.light': {
...lightCommon,
backgroundColor: 'transparent',
borderColor: variables.brandLight,
borderWidth: variables.borderWidth * 2
},
'.primary': {
...primaryCommon,
backgroundColor: 'transparent',
borderColor: variables.buttonPrimaryBg,
borderWidth: variables.borderWidth * 2
},
'.success': {
...successCommon,
backgroundColor: 'transparent',
borderColor: variables.buttonSuccessBg,
borderWidth: variables.borderWidth * 2
},
'.info': {
...infoCommon,
backgroundColor: 'transparent',
borderColor: variables.buttonInfoBg,
borderWidth: variables.borderWidth * 2
},
'.warning': {
...warningCommon,
backgroundColor: 'transparent',
borderColor: variables.buttonWarningBg,
borderWidth: variables.borderWidth * 2
},
'.danger': {
...dangerCommon,
backgroundColor: 'transparent',
borderColor: variables.buttonDangerBg,
borderWidth: variables.borderWidth * 2
},
'.disabled': {
backgroundColor: 'transparent',
borderColor: variables.buttonDisabledBg,
borderWidth: variables.borderWidth * 2,
'NativeBase.Text': {
color: variables.buttonDisabledBg
}
},
...primaryCommon,
borderWidth: variables.borderWidth * 2,
elevation: null,
shadowColor: null,
shadowOffset: null,
shadowOpacity: null,
shadowRadius: null,
backgroundColor: 'transparent'
},
'.dark': {
'.bordered': {
...darkCommon
},
backgroundColor: variables.brandDark
},
'.light': {
'.transparent': {
...lightCommon,
backgroundColor: 'transparent'
},
'.bordered': {
...lightCommon
},
...darkCommon,
backgroundColor: variables.brandLight
},
'.primary': {
'.bordered': {
...primaryCommon
},
backgroundColor: variables.buttonPrimaryBg
},
'.success': {
'.bordered': {
...successCommon
},
backgroundColor: variables.buttonSuccessBg
},
'.info': {
'.bordered': {
...infoCommon
},
backgroundColor: variables.buttonInfoBg
},
'.warning': {
'.bordered': {
...warningCommon
},
backgroundColor: variables.buttonWarningBg
},
'.danger': {
'.bordered': {
...dangerCommon
},
backgroundColor: variables.buttonDangerBg
},
'.block': {
justifyContent: 'center',
alignSelf: 'stretch'
},
'.full': {
justifyContent: 'center',
alignSelf: 'stretch',
borderRadius: 0
},
'.rounded': {
borderRadius: variables.borderRadiusLarge
},
'.transparent': {
backgroundColor: 'transparent',
elevation: 0,
shadowColor: null,
shadowOffset: null,
shadowRadius: null,
shadowOpacity: null,
...primaryCommon,
'.dark': {
...darkCommon,
},
'.danger': {
...dangerCommon,
},
'.warning': {
...warningCommon,
},
'.info': {
...infoCommon,
},
'.primary': {
...primaryCommon,
},
'.success': {
...successCommon,
},
'.light': {
...lightCommon,
},
'.disabled': {
backgroundColor: 'transparent',
borderColor: variables.buttonDisabledBg,
borderWidth: variables.borderWidth * 2,
'NativeBase.Text': {
color: variables.buttonDisabledBg
},
'NativeBase.Icon': {
color: variables.buttonDisabledBg
},
'NativeBase.IconNB': {
color: variables.buttonDisabledBg
}
}
},
'.small': {
height: 30,
'NativeBase.Text': {
fontSize: 14
},
'NativeBase.Icon': {
fontSize: 20,
paddingTop: 0
},
'NativeBase.IconNB': {
fontSize: 20,
paddingTop: 0
}
},
'.large': {
height: 60,
'NativeBase.Text': {
fontSize: 22
}
},
'.capitalize': {},
'.vertical': {
flexDirection: 'column',
height: null
},
'NativeBase.Text': {
fontFamily: variables.buttonFontFamily,
marginLeft: 0,
marginRight: 0,
color: variables.buttonTextColor,
fontSize: variables.buttonTextSize,
paddingHorizontal: 16,
backgroundColor: 'transparent'
},
'NativeBase.Icon': {
color: variables.buttonTextColor,
fontSize: 24,
marginHorizontal: 16,
paddingTop: platform === PLATFORM.IOS ? 2 : undefined
},
'NativeBase.IconNB': {
color: variables.buttonTextColor,
fontSize: 24,
marginHorizontal: 16,
paddingTop: platform === PLATFORM.IOS ? 2 : undefined
},
'.iconLeft': {
'NativeBase.Text': {
marginLeft: 0
},
'NativeBase.IconNB': {
marginRight: 0,
marginLeft: 16
},
'NativeBase.Icon': {
marginRight: 0,
marginLeft: 16
}
},
'.iconRight': {
'NativeBase.Text': {
marginRight: 0
},
'NativeBase.IconNB': {
marginLeft: 0,
marginRight: 16
},
'NativeBase.Icon': {
marginLeft: 0,
marginRight: 16
}
},
'.picker': {
'NativeBase.Text': {
'.note': {
fontSize: 16,
lineHeight: null
}
}
},
paddingVertical: variables.buttonPadding,
backgroundColor: variables.buttonPrimaryBg,
borderRadius: variables.borderRadiusBase,
borderColor: variables.buttonPrimaryBg,
borderWidth: null,
height: 45,
flexDirection: 'row',
elevation: 2,
shadowColor:
platformStyle === PLATFORM.MATERIAL ? variables.brandDark : undefined,
shadowOffset:
platformStyle === PLATFORM.MATERIAL ? { width: 0, height: 2 } : undefined,
shadowOpacity: platformStyle === PLATFORM.MATERIAL ? 0.2 : undefined,
shadowRadius: platformStyle === PLATFORM.MATERIAL ? 1.2 : undefined,
alignItems: 'center',
justifyContent: 'space-between'
};
return buttonTheme;
};

View file

@ -1,37 +0,0 @@
// @flow
import variable from './../variables/platform';
export default (variables /* : * */ = variable) => {
const cardTheme = {
'.transparent': {
shadowColor: null,
shadowOffset: null,
shadowOpacity: null,
shadowRadius: null,
elevation: null,
backgroundColor: 'transparent',
borderWidth: 0
},
'.noShadow': {
shadowColor: null,
shadowOffset: null,
shadowOpacity: null,
elevation: null
},
marginVertical: 5,
marginHorizontal: 2,
borderWidth: variables.borderWidth,
borderRadius: variables.cardBorderRadius,
borderColor: variables.cardBorderColor,
flexWrap: 'nowrap',
backgroundColor: variables.cardDefaultBg,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 1.5,
elevation: 3
};
return cardTheme;
};

View file

@ -1,198 +0,0 @@
// @flow
import { StyleSheet } from 'react-native';
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
export default (variables /* : * */ = variable) => {
const platform = variables.platform;
const transparentBtnCommon = {
'NativeBase.Text': {
fontSize: variables.DefaultFontSize - 3,
color: variables.sTabBarActiveTextColor
},
'NativeBase.Icon': {
fontSize: variables.iconFontSize - 10,
color: variables.sTabBarActiveTextColor,
marginHorizontal: null
},
'NativeBase.IconNB': {
fontSize: variables.iconFontSize - 10,
color: variables.sTabBarActiveTextColor
},
paddingVertical: null,
paddingHorizontal: null
};
const cardItemTheme = {
'NativeBase.Left': {
'NativeBase.Body': {
'NativeBase.Text': {
'.note': {
color: variables.listNoteColor,
fontWeight: '400',
marginRight: 20
}
},
flex: 1,
marginLeft: 10,
alignItems: null
},
'NativeBase.Icon': {
fontSize: variables.iconFontSize
},
'NativeBase.IconNB': {
fontSize: variables.iconFontSize
},
'NativeBase.Text': {
marginLeft: 10,
alignSelf: 'center'
},
'NativeBase.Button': {
'.transparent': {
...transparentBtnCommon,
paddingRight: variables.cardItemPadding + 5
}
},
flex: 1,
flexDirection: 'row',
alignItems: 'center'
},
'.content': {
'NativeBase.Text': {
color: platform === PLATFORM.IOS ? '#555' : '#222',
fontSize: variables.DefaultFontSize - 2
}
},
'.cardBody': {
padding: -5,
'NativeBase.Text': {
marginTop: 5
}
},
'NativeBase.Body': {
'NativeBase.Text': {
'.note': {
color: variables.listNoteColor,
fontWeight: '200',
marginRight: 20
}
},
'NativeBase.Button': {
'.transparent': {
...transparentBtnCommon,
paddingRight: variables.cardItemPadding + 5,
alignSelf: 'stretch'
}
},
flex: 1,
alignSelf: 'stretch',
alignItems: 'flex-start'
},
'NativeBase.Right': {
'NativeBase.Badge': {
alignSelf: null
},
'NativeBase.Button': {
'.transparent': {
...transparentBtnCommon
},
alignSelf: null
},
'NativeBase.Icon': {
alignSelf: null,
fontSize: variables.iconFontSize - 8,
color: variables.cardBorderColor
},
'NativeBase.IconNB': {
alignSelf: null,
fontSize: variables.iconFontSize - 8,
color: variables.cardBorderColor
},
'NativeBase.Text': {
fontSize: variables.DefaultFontSize - 1,
alignSelf: null
},
'NativeBase.Thumbnail': {
alignSelf: null
},
'NativeBase.Image': {
alignSelf: null
},
'NativeBase.Radio': {
alignSelf: null
},
'NativeBase.Checkbox': {
alignSelf: null
},
'NativeBase.Switch': {
alignSelf: null
},
flex: 0.8
},
'.header': {
'NativeBase.Text': {
fontSize: 16,
fontWeight: platform === PLATFORM.IOS ? '600' : '500'
},
'.bordered': {
'NativeBase.Text': {
color: variables.brandPrimary,
fontWeight: platform === PLATFORM.IOS ? '600' : '500'
},
borderBottomWidth: variables.borderWidth
},
borderBottomWidth: null,
paddingVertical: variables.cardItemPadding + 5
},
'.footer': {
'NativeBase.Text': {
fontSize: 16,
fontWeight: platform === PLATFORM.IOS ? '600' : '500'
},
'.bordered': {
'NativeBase.Text': {
color: variables.brandPrimary,
fontWeight: platform === PLATFORM.IOS ? '600' : '500'
},
borderTopWidth: variables.borderWidth
},
borderBottomWidth: null
},
'NativeBase.Text': {
'.note': {
color: variables.listNoteColor,
fontWeight: '200'
}
},
'NativeBase.Icon': {
width: variables.iconFontSize + 5,
fontSize: variables.iconFontSize - 2
},
'NativeBase.IconNB': {
width: variables.iconFontSize + 5,
fontSize: variables.iconFontSize - 2
},
'.bordered': {
borderBottomWidth: StyleSheet.hairlineWidth,
borderColor: variables.cardBorderColor
},
'.first': {
borderTopLeftRadius: variables.cardBorderRadius,
borderTopRightRadius: variables.cardBorderRadius
},
'.last': {
borderBottomLeftRadius: variables.cardBorderRadius,
borderBottomRightRadius: variables.cardBorderRadius
},
flexDirection: 'row',
alignItems: 'center',
borderRadius: variables.cardBorderRadius,
padding: variables.cardItemPadding + 5,
paddingVertical: variables.cardItemPadding,
backgroundColor: variables.cardDefaultBg
};
return cardItemTheme;
};

View file

@ -1,38 +0,0 @@
// @flow
import variable from './../variables/platform';
export default (variables /* : * */ = variable) => {
const checkBoxTheme = {
'.checked': {
'NativeBase.Icon': {
color: variables.checkboxTickColor
},
'NativeBase.IconNB': {
color: variables.checkboxTickColor
}
},
'NativeBase.Icon': {
color: 'transparent',
lineHeight: variables.CheckboxIconSize,
marginTop: variables.CheckboxIconMarginTop,
fontSize: variables.CheckboxFontSize
},
'NativeBase.IconNB': {
color: 'transparent',
lineHeight: variables.CheckboxIconSize,
marginTop: variables.CheckboxIconMarginTop,
fontSize: variables.CheckboxFontSize
},
borderRadius: variables.CheckboxRadius,
overflow: 'hidden',
width: variables.checkboxSize,
height: variables.checkboxSize,
borderWidth: variables.CheckboxBorderWidth,
paddingLeft: variables.CheckboxPaddingLeft - 1,
paddingBottom: variables.CheckboxPaddingBottom,
left: 10
};
return checkBoxTheme;
};

View file

@ -1,17 +0,0 @@
// @flow
import { Platform, Dimensions } from 'react-native';
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
const deviceHeight = Dimensions.get('window').height;
export default (variables /* : * */ = variable) => {
const theme = {
flex: 1,
height: Platform.OS === PLATFORM.IOS ? deviceHeight : deviceHeight - 20,
backgroundColor: variables.containerBgColor
};
return theme;
};

View file

@ -1,14 +0,0 @@
// @flow
export default () => {
const contentTheme = {
flex: 1,
backgroundColor: 'transparent',
'NativeBase.Segment': {
borderWidth: 0,
backgroundColor: 'transparent'
}
};
return contentTheme;
};

View file

@ -1,25 +0,0 @@
// @flow
export default () => {
const fabTheme = {
'NativeBase.Button': {
alignItems: 'center',
padding: null,
justifyContent: 'center',
'NativeBase.Icon': {
alignSelf: 'center',
fontSize: 20,
marginLeft: 0,
marginRight: 0
},
'NativeBase.IconNB': {
alignSelf: 'center',
fontSize: 20,
marginLeft: 0,
marginRight: 0
}
}
};
return fabTheme;
};

View file

@ -1,119 +0,0 @@
// @flow
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
export default (variables /* : * */ = variable) => {
const platformStyle = variables.platformStyle;
const platform = variables.platform;
const iconCommon = {
'NativeBase.Icon': {
color: variables.tabBarActiveTextColor
}
};
const iconNBCommon = {
'NativeBase.IconNB': {
color: variables.tabBarActiveTextColor
}
};
const textCommon = {
'NativeBase.Text': {
color: variables.tabBarActiveTextColor
}
};
const footerTheme = {
'NativeBase.Left': {
'NativeBase.Button': {
'.transparent': {
backgroundColor: 'transparent',
borderColor: null,
elevation: 0,
shadowColor: null,
shadowOffset: null,
shadowRadius: null,
shadowOpacity: null,
...iconCommon,
...iconNBCommon,
...textCommon
},
alignSelf: null,
...iconCommon,
...iconNBCommon
// ...textCommon
},
flex: 1,
alignSelf: 'center',
alignItems: 'flex-start'
},
'NativeBase.Body': {
flex: 1,
alignItems: 'center',
alignSelf: 'center',
flexDirection: 'row',
'NativeBase.Button': {
alignSelf: 'center',
'.transparent': {
backgroundColor: 'transparent',
borderColor: null,
elevation: 0,
shadowColor: null,
shadowOffset: null,
shadowRadius: null,
shadowOpacity: null,
...iconCommon,
...iconNBCommon,
...textCommon
},
'.full': {
height: variables.footerHeight,
paddingBottom: variables.footerPaddingBottom,
flex: 1
},
...iconCommon,
...iconNBCommon
// ...textCommon
}
},
'NativeBase.Right': {
'NativeBase.Button': {
'.transparent': {
backgroundColor: 'transparent',
borderColor: null,
elevation: 0,
shadowColor: null,
shadowOffset: null,
shadowRadius: null,
shadowOpacity: null,
...iconCommon,
...iconNBCommon,
...textCommon
},
alignSelf: null,
...iconCommon,
...iconNBCommon
// ...textCommon
},
flex: 1,
alignSelf: 'center',
alignItems: 'flex-end'
},
backgroundColor: variables.footerDefaultBg,
flexDirection: 'row',
justifyContent: 'center',
borderTopWidth:
platform === PLATFORM.IOS && platformStyle !== PLATFORM.MATERIAL
? variables.borderWidth
: undefined,
borderColor:
platform === PLATFORM.IOS && platformStyle !== PLATFORM.MATERIAL
? '#cbcbcb'
: undefined,
height: variables.footerHeight,
paddingBottom: variables.footerPaddingBottom,
elevation: 3,
left: 0,
right: 0
};
return footerTheme;
};

View file

@ -1,79 +0,0 @@
// @flow
import { Platform } from 'react-native';
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
export default (variables /* : * */ = variable) => {
const platform = variables.platform;
const footerTabTheme = {
'NativeBase.Button': {
'.active': {
'NativeBase.Text': {
color: variables.tabBarActiveTextColor,
fontSize: variables.tabBarTextSize,
lineHeight: 16
},
'NativeBase.Icon': {
color: variables.tabBarActiveTextColor
},
'NativeBase.IconNB': {
color: variables.tabBarActiveTextColor
},
backgroundColor: variables.tabActiveBgColor
},
flexDirection: null,
backgroundColor: 'transparent',
borderColor: null,
elevation: 0,
shadowColor: null,
shadowOffset: null,
shadowRadius: null,
shadowOpacity: null,
alignSelf: 'center',
flex: 1,
height: variables.footerHeight,
justifyContent: 'center',
'.badge': {
'NativeBase.Badge': {
'NativeBase.Text': {
fontSize: 11,
fontWeight: platform === PLATFORM.IOS ? '600' : undefined,
lineHeight: 14
},
top: -3,
alignSelf: 'center',
left: 10,
zIndex: 99,
height: 18,
padding: 1.7,
paddingHorizontal: 3
},
'NativeBase.Icon': {
marginTop: -18
}
},
'NativeBase.Icon': {
color: variables.tabBarTextColor
},
'NativeBase.IconNB': {
color: variables.tabBarTextColor
},
'NativeBase.Text': {
color: variables.tabBarTextColor,
fontSize: variables.tabBarTextSize,
lineHeight: 16
}
},
backgroundColor:
Platform.OS === PLATFORM.ANDROID ? variables.footerDefaultBg : undefined,
flexDirection: 'row',
justifyContent: 'space-between',
flex: 1,
alignSelf: 'stretch'
};
return footerTabTheme;
};

View file

@ -1,86 +0,0 @@
// @flow
export default () => {
const theme = {
'NativeBase.Item': {
'.fixedLabel': {
'NativeBase.Label': {
paddingLeft: null
},
marginLeft: 15
},
'.inlineLabel': {
'NativeBase.Label': {
paddingLeft: null
},
marginLeft: 15
},
'.placeholderLabel': {
'NativeBase.Input': {}
},
'.stackedLabel': {
'NativeBase.Label': {
top: 5,
paddingLeft: null
},
'NativeBase.Input': {
paddingLeft: null,
marginLeft: null
},
'NativeBase.Icon': {
marginTop: 36
},
marginLeft: 15
},
'.floatingLabel': {
'NativeBase.Input': {
paddingLeft: null,
top: 10,
marginLeft: null
},
'NativeBase.Label': {
left: 0,
top: 6
},
'NativeBase.Icon': {
top: 6
},
marginTop: 15,
marginLeft: 15
},
'.regular': {
'NativeBase.Label': {
left: 0
},
marginLeft: 0
},
'.rounded': {
'NativeBase.Label': {
left: 0
},
marginLeft: 0
},
'.underline': {
'NativeBase.Label': {
left: 0,
top: 0,
position: 'relative'
},
'NativeBase.Input': {
left: -15
},
marginLeft: 15
},
'.last': {
marginLeft: 0,
paddingLeft: 15
},
'NativeBase.Label': {
paddingRight: 5
},
marginLeft: 15
}
};
return theme;
};

View file

@ -1,13 +0,0 @@
// @flow
import variable from './../variables/platform';
export default (variables /* : * */ = variable) => {
const h1Theme = {
color: variables.textColor,
fontSize: variables.fontSizeH1,
lineHeight: variables.lineHeightH1
};
return h1Theme;
};

View file

@ -1,13 +0,0 @@
// @flow
import variable from './../variables/platform';
export default (variables /* : * */ = variable) => {
const h2Theme = {
color: variables.textColor,
fontSize: variables.fontSizeH2,
lineHeight: variables.lineHeightH2
};
return h2Theme;
};

View file

@ -1,13 +0,0 @@
// @flow
import variable from './../variables/platform';
export default (variables /* : * */ = variable) => {
const h3Theme = {
color: variables.textColor,
fontSize: variables.fontSizeH3,
lineHeight: variables.lineHeightH3
};
return h3Theme;
};

View file

@ -1,419 +0,0 @@
// @flow
import { PixelRatio, StatusBar } from 'react-native';
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
export default (variables /* : * */ = variable) => {
const platformStyle = variables.platformStyle;
const platform = variables.platform;
const headerTheme = {
'.span': {
height: 128,
'NativeBase.Left': {
alignSelf: 'flex-start'
},
'NativeBase.Body': {
alignSelf: 'flex-end',
alignItems: 'flex-start',
justifyContent: 'center',
paddingBottom: 26
},
'NativeBase.Right': {
alignSelf: 'flex-start'
}
},
'.hasSubtitle': {
'NativeBase.Body': {
'NativeBase.Title': {
fontSize: variables.titleFontSize - 2,
fontFamily: variables.titleFontfamily,
textAlign: 'center',
fontWeight: '500',
paddingBottom: 3
},
'NativeBase.Subtitle': {
fontSize: variables.subTitleFontSize,
fontFamily: variables.titleFontfamily,
color: variables.subtitleColor,
textAlign: 'center'
}
}
},
'.transparent': {
backgroundColor: 'transparent',
borderBottomColor: 'transparent',
elevation: 0,
shadowColor: null,
shadowOffset: null,
shadowRadius: null,
shadowOpacity: null,
paddingTop:
platform === PLATFORM.ANDROID ? StatusBar.currentHeight : undefined,
height:
platform === PLATFORM.ANDROID
? variables.toolbarHeight + StatusBar.currentHeight
: variables.toolbarHeight
},
'.noShadow': {
elevation: 0,
shadowColor: null,
shadowOffset: null,
shadowRadius: null,
shadowOpacity: null
},
'.hasTabs': {
elevation: 0,
shadowColor: null,
shadowOffset: null,
shadowRadius: null,
shadowOpacity: null,
borderBottomWidth: null
},
'.hasSegment': {
elevation: 0,
shadowColor: null,
shadowOffset: null,
shadowRadius: null,
shadowOpacity: null,
borderBottomWidth: null,
'NativeBase.Left': {
flex: 0.3
},
'NativeBase.Right': {
flex: 0.3
},
'NativeBase.Body': {
flex: 1,
'NativeBase.Segment': {
marginRight: 0,
alignSelf: 'center',
'NativeBase.Button': {
paddingLeft: 0,
paddingRight: 0
}
}
}
},
'.noLeft': {
'NativeBase.Left': {
width: platform === PLATFORM.IOS ? undefined : 0,
flex: platform === PLATFORM.IOS ? 1 : 0
},
'NativeBase.Body': {
'NativeBase.Title': {
paddingLeft: platform === PLATFORM.IOS ? undefined : 10
},
'NativeBase.Subtitle': {
paddingLeft: platform === PLATFORM.IOS ? undefined : 10
}
}
},
'NativeBase.Button': {
justifyContent: 'center',
alignSelf: 'center',
alignItems: 'center',
'.transparent': {
'NativeBase.Text': {
color: variables.toolbarBtnTextColor,
fontWeight: '600'
},
'NativeBase.Icon': {
color: variables.toolbarBtnColor
},
'NativeBase.IconNB': {
color: variables.toolbarBtnColor
},
paddingHorizontal: variables.buttonPadding
},
paddingHorizontal: 15
},
'.searchBar': {
'NativeBase.Item': {
'NativeBase.Icon': {
backgroundColor: 'transparent',
color: variables.dropdownLinkColor,
fontSize: variables.toolbarSearchIconSize,
alignItems: 'center',
marginTop: 2,
paddingRight: 10,
paddingLeft: 10
},
'NativeBase.IconNB': {
backgroundColor: 'transparent',
color: null,
alignSelf: 'center'
},
'NativeBase.Input': {
alignSelf: 'center',
lineHeight: null,
height: variables.searchBarInputHeight
},
alignSelf: 'center',
alignItems: 'center',
justifyContent: 'flex-start',
flex: 1,
height: variables.searchBarHeight,
borderColor: 'transparent',
backgroundColor: variables.toolbarInputColor
},
'NativeBase.Button': {
'.transparent': {
'NativeBase.Text': {
fontWeight: '500'
},
paddingHorizontal: null,
paddingLeft: platform === PLATFORM.IOS ? 10 : null
},
paddingHorizontal: platform === PLATFORM.IOS ? undefined : null,
width: platform === PLATFORM.IOS ? undefined : 0,
height: platform === PLATFORM.IOS ? undefined : 0
}
},
'.rounded': {
'NativeBase.Item': {
borderRadius:
platform === PLATFORM.IOS && platformStyle !== PLATFORM.MATERIAL
? 25
: 3
}
},
'NativeBase.Left': {
'NativeBase.Button': {
'.hasText': {
marginLeft: -10,
height: 30,
'NativeBase.Icon': {
color: variables.toolbarBtnColor,
fontSize: variables.iconHeaderSize,
marginTop: 2,
marginRight: 5,
marginLeft: 2
},
'NativeBase.Text': {
color: variables.toolbarBtnTextColor,
fontSize: platform === PLATFORM.IOS ? 17 : 0,
marginLeft: 7,
lineHeight: 19.5
},
'NativeBase.IconNB': {
color: variables.toolbarBtnColor,
fontSize: variables.iconHeaderSize,
marginTop: 2,
marginRight: 5,
marginLeft: 2
}
},
'.transparent': {
marginLeft:
platform === PLATFORM.IOS && platformStyle !== PLATFORM.MATERIAL
? -3
: 0,
'NativeBase.Icon': {
color: variables.toolbarBtnColor,
fontSize:
platform === PLATFORM.IOS &&
variables.platformStyle !== PLATFORM.MATERIAL
? variables.iconHeaderSize + 1
: variables.iconHeaderSize,
marginTop: 0,
marginRight: 2,
marginLeft: 1,
paddingTop: 1
},
'NativeBase.IconNB': {
color: variables.toolbarBtnColor,
fontSize:
platform === PLATFORM.IOS &&
variables.platformStyle !== PLATFORM.MATERIAL
? variables.iconHeaderSize + 1
: variables.iconHeaderSize - 2,
marginTop: 0,
marginRight: 2,
marginLeft: 1,
paddingTop: 1
},
'NativeBase.Text': {
color: variables.toolbarBtnTextColor,
fontSize: platform === PLATFORM.IOS ? 17 : 0,
top: platform === PLATFORM.IOS ? 1 : -1.5,
paddingLeft:
platform === PLATFORM.IOS && platformStyle !== PLATFORM.MATERIAL
? 2
: 5,
paddingRight:
platform === PLATFORM.IOS && platformStyle !== PLATFORM.MATERIAL
? undefined
: 10
},
backgroundColor: 'transparent',
borderColor: null,
elevation: 0,
shadowColor: null,
shadowOffset: null,
shadowRadius: null,
shadowOpacity: null
},
'NativeBase.Icon': {
color: variables.toolbarBtnColor
},
'NativeBase.IconNB': {
color: variables.toolbarBtnColor
},
alignSelf: null,
paddingRight: variables.buttonPadding,
paddingLeft:
platform === PLATFORM.IOS && platformStyle !== PLATFORM.MATERIAL
? 4
: 8
},
flex:
platform === PLATFORM.IOS && platformStyle !== PLATFORM.MATERIAL
? 1
: 0.4,
alignSelf: 'center',
alignItems: 'flex-start'
},
'NativeBase.Body': {
flex: 1,
alignItems:
platform === PLATFORM.IOS && platformStyle !== PLATFORM.MATERIAL
? 'center'
: 'flex-start',
alignSelf: 'center',
'NativeBase.Segment': {
borderWidth: 0,
alignSelf: 'flex-end',
marginRight: platform === PLATFORM.IOS ? -40 : -55
},
'NativeBase.Button': {
alignSelf: 'center',
'.transparent': {
backgroundColor: 'transparent'
},
'NativeBase.Icon': {
color: variables.toolbarBtnColor
},
'NativeBase.IconNB': {
color: variables.toolbarBtnColor
},
'NativeBase.Text': {
color: variables.inverseTextColor,
backgroundColor: 'transparent'
}
}
},
'NativeBase.Right': {
'NativeBase.Button': {
'.hasText': {
height: 30,
'NativeBase.Icon': {
color: variables.toolbarBtnColor,
fontSize: variables.iconHeaderSize - 2,
marginTop: 2,
marginRight: 2,
marginLeft: 5
},
'NativeBase.Text': {
color: variables.toolbarBtnTextColor,
fontSize: platform === PLATFORM.IOS ? 17 : 14,
lineHeight: 19.5
},
'NativeBase.IconNB': {
color: variables.toolbarBtnColor,
fontSize: variables.iconHeaderSize - 2,
marginTop: 2,
marginRight: 2,
marginLeft: 5
}
},
'.transparent': {
marginRight: platform === PLATFORM.IOS ? -9 : -5,
paddingLeft: 15,
paddingRight: 12,
paddingHorizontal: 15,
borderRadius: 50,
'NativeBase.Icon': {
color: variables.toolbarBtnColor,
fontSize: variables.iconHeaderSize - 2,
marginTop: 0,
marginLeft: 2,
marginRight: 0
// paddingTop: 0
},
'NativeBase.IconNB': {
color: variables.toolbarBtnColor,
fontSize: variables.iconHeaderSize - 2,
marginTop: 0,
marginLeft: 2,
marginRight: 0
// paddingTop: 0
},
'NativeBase.Text': {
color: variables.toolbarBtnTextColor,
fontSize: platform === PLATFORM.IOS ? 17 : 14,
top: platform === PLATFORM.IOS ? 1 : -1.5,
paddingRight:
platform === PLATFORM.IOS &&
variables.platformStyle !== PLATFORM.MATERIAL
? 0
: undefined
},
backgroundColor: 'transparent',
borderColor: null,
elevation: 0,
shadowColor: null,
shadowOffset: null,
shadowRadius: null,
shadowOpacity: null
},
'NativeBase.Icon': {
color: variables.toolbarBtnColor
},
'NativeBase.IconNB': {
color: variables.toolbarBtnColor
},
alignSelf: null,
paddingHorizontal: variables.buttonPadding
},
flex: 1,
alignSelf: 'center',
alignItems: 'flex-end',
flexDirection: 'row',
justifyContent: 'flex-end'
},
backgroundColor: variables.toolbarDefaultBg,
flexDirection: 'row',
// paddingHorizontal: 10,
paddingLeft:
platform === PLATFORM.IOS && variables.platformStyle !== PLATFORM.MATERIAL
? 6
: 10,
paddingRight: 10,
justifyContent: 'center',
paddingTop: platform === PLATFORM.IOS ? 18 : 0,
borderBottomWidth:
platform === PLATFORM.IOS
? 1 / PixelRatio.getPixelSizeForLayoutSize(1)
: 0,
borderBottomColor: variables.toolbarDefaultBorder,
height:
variables.platform === PLATFORM.IOS &&
variables.platformStyle === PLATFORM.MATERIAL
? variables.toolbarHeight + 10
: variables.toolbarHeight,
elevation: 3,
shadowColor: platformStyle === PLATFORM.MATERIAL ? '#000' : undefined,
shadowOffset:
platformStyle === PLATFORM.MATERIAL ? { width: 0, height: 2 } : undefined,
shadowOpacity: platformStyle === PLATFORM.MATERIAL ? 0.2 : undefined,
shadowRadius: platformStyle === PLATFORM.MATERIAL ? 1.2 : undefined,
top: 0,
left: 0,
right: 0
};
return headerTheme;
};

View file

@ -1,12 +0,0 @@
// @flow
import variable from './../variables/platform';
export default (variables /* : * */ = variable) => {
const iconTheme = {
fontSize: variables.iconFontSize,
color: variable.textColor
};
return iconTheme;
};

View file

@ -1,19 +0,0 @@
// @flow
import variable from './../variables/platform';
export default (variables /* : * */ = variable) => {
const inputTheme = {
'.multiline': {
height: null
},
height: variables.inputHeightBase,
color: variables.inputColor,
paddingLeft: 5,
paddingRight: 5,
flex: 1,
fontSize: variables.inputFontSize
};
return inputTheme;
};

View file

@ -1,132 +0,0 @@
// @flow
import variable from './../variables/platform';
export default (variables /* : * */ = variable) => {
const inputGroupTheme = {
'NativeBase.Icon': {
fontSize: 24,
color: variables.sTabBarActiveTextColor,
paddingHorizontal: 5
},
'NativeBase.IconNB': {
fontSize: 24,
color: variables.sTabBarActiveTextColor,
paddingHorizontal: 5
},
'NativeBase.Input': {
height: variables.inputHeightBase,
color: variables.inputColor,
paddingLeft: 5,
paddingRight: 5,
flex: 1,
fontSize: variables.inputFontSize,
lineHeight: variables.inputLineHeight
},
'.underline': {
'.success': {
borderColor: variables.inputSuccessBorderColor
},
'.error': {
borderColor: variables.inputErrorBorderColor
},
paddingLeft: 5,
borderWidth: variables.borderWidth,
borderTopWidth: 0,
borderRightWidth: 0,
borderLeftWidth: 0,
borderColor: variables.inputBorderColor
},
'.regular': {
'.success': {
borderColor: variables.inputSuccessBorderColor
},
'.error': {
borderColor: variables.inputErrorBorderColor
},
paddingLeft: 5,
borderWidth: variables.borderWidth,
borderColor: variables.inputBorderColor
},
'.rounded': {
'.success': {
borderColor: variables.inputSuccessBorderColor
},
'.error': {
borderColor: variables.inputErrorBorderColor
},
paddingLeft: 5,
borderWidth: variables.borderWidth,
borderRadius: variables.inputGroupRoundedBorderRadius,
borderColor: variables.inputBorderColor
},
'.success': {
'NativeBase.Icon': {
color: variables.inputSuccessBorderColor
},
'NativeBase.IconNB': {
color: variables.inputSuccessBorderColor
},
'.rounded': {
borderRadius: 30,
borderColor: variables.inputSuccessBorderColor
},
'.regular': {
borderColor: variables.inputSuccessBorderColor
},
'.underline': {
borderWidth: variables.borderWidth,
borderTopWidth: 0,
borderRightWidth: 0,
borderLeftWidth: 0,
borderColor: variables.inputSuccessBorderColor
},
borderColor: variables.inputSuccessBorderColor
},
'.error': {
'NativeBase.Icon': {
color: variables.inputErrorBorderColor
},
'NativeBase.IconNB': {
color: variables.inputErrorBorderColor
},
'.rounded': {
borderRadius: 30,
borderColor: variables.inputErrorBorderColor
},
'.regular': {
borderColor: variables.inputErrorBorderColor
},
'.underline': {
borderWidth: variables.borderWidth,
borderTopWidth: 0,
borderRightWidth: 0,
borderLeftWidth: 0,
borderColor: variables.inputErrorBorderColor
},
borderColor: variables.inputErrorBorderColor
},
'.disabled': {
'NativeBase.Icon': {
color: '#384850'
},
'NativeBase.IconNB': {
color: '#384850'
}
},
paddingLeft: 5,
borderWidth: variables.borderWidth,
borderTopWidth: 0,
borderRightWidth: 0,
borderLeftWidth: 0,
borderColor: variables.inputBorderColor,
backgroundColor: 'transparent',
flexDirection: 'row',
alignItems: 'center'
};
return inputGroupTheme;
};

View file

@ -1,241 +0,0 @@
// @flow
import { Platform } from 'react-native';
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
export default (variables /* : * */ = variable) => {
const itemTheme = {
'.floatingLabel': {
'NativeBase.Input': {
height: 50,
top: 8,
paddingTop: 3,
paddingBottom: 7,
'.multiline': {
minHeight: variables.inputHeightBase,
paddingTop: Platform.OS === PLATFORM.IOS ? 10 : 3,
paddingBottom: Platform.OS === PLATFORM.IOS ? 14 : 10
}
},
'NativeBase.Label': {
paddingTop: 5
},
'NativeBase.Icon': {
top: 6,
paddingTop: 8
},
'NativeBase.IconNB': {
top: 6,
paddingTop: 8
}
},
'.fixedLabel': {
'NativeBase.Label': {
position: null,
top: null,
left: null,
right: null,
flex: 1,
height: null,
width: null,
fontSize: variables.inputFontSize
},
'NativeBase.Input': {
flex: 2,
fontSize: variables.inputFontSize
}
},
'.stackedLabel': {
'NativeBase.Label': {
position: null,
top: null,
left: null,
right: null,
paddingTop: 5,
alignSelf: 'flex-start',
fontSize: variables.inputFontSize - 2
},
'NativeBase.Icon': {
marginTop: 36
},
'NativeBase.Input': {
alignSelf: Platform.OS === PLATFORM.IOS ? 'stretch' : 'flex-start',
flex: 1,
width: Platform.OS === PLATFORM.IOS ? null : variables.deviceWidth - 25,
fontSize: variables.inputFontSize,
lineHeight: variables.inputLineHeight - 6,
'.secureTextEntry': {
fontSize: variables.inputFontSize
},
'.multiline': {
paddingTop: Platform.OS === PLATFORM.IOS ? 9 : undefined,
paddingBottom: Platform.OS === PLATFORM.IOS ? 9 : undefined
}
},
flexDirection: null,
minHeight: variables.inputHeightBase + 15
},
'.inlineLabel': {
'NativeBase.Label': {
position: null,
top: null,
left: null,
right: null,
paddingRight: 20,
height: null,
width: null,
fontSize: variables.inputFontSize
},
'NativeBase.Input': {
paddingLeft: 5,
fontSize: variables.inputFontSize
},
flexDirection: 'row'
},
'NativeBase.Label': {
fontSize: variables.inputFontSize,
color: variables.inputColorPlaceholder,
paddingRight: 5
},
'NativeBase.Icon': {
fontSize: 24,
paddingRight: 8
},
'NativeBase.IconNB': {
fontSize: 24,
paddingRight: 8
},
'NativeBase.Input': {
'.multiline': {
height: null
},
height: variables.inputHeightBase,
color: variables.inputColor,
flex: 1,
top: Platform.OS === PLATFORM.IOS ? 1.5 : undefined,
fontSize: variables.inputFontSize
},
'.underline': {
'NativeBase.Input': {
paddingLeft: 15
},
'.success': {
borderColor: variables.inputSuccessBorderColor
},
'.error': {
borderColor: variables.inputErrorBorderColor
},
borderWidth: variables.borderWidth * 2,
borderTopWidth: 0,
borderRightWidth: 0,
borderLeftWidth: 0,
borderColor: variables.inputBorderColor
},
'.regular': {
'NativeBase.Input': {
paddingLeft: 8
},
'NativeBase.Icon': {
paddingLeft: 10
},
'.success': {
borderColor: variables.inputSuccessBorderColor
},
'.error': {
borderColor: variables.inputErrorBorderColor
},
borderWidth: variables.borderWidth * 2,
borderColor: variables.inputBorderColor
},
'.rounded': {
'NativeBase.Input': {
paddingLeft: 8
},
'NativeBase.Icon': {
paddingLeft: 10
},
'.success': {
borderColor: variables.inputSuccessBorderColor
},
'.error': {
borderColor: variables.inputErrorBorderColor
},
borderWidth: variables.borderWidth * 2,
borderRadius: 30,
borderColor: variables.inputBorderColor
},
'.success': {
'NativeBase.Icon': {
color: variables.inputSuccessBorderColor
},
'NativeBase.IconNB': {
color: variables.inputSuccessBorderColor
},
'.rounded': {
borderRadius: 30,
borderColor: variables.inputSuccessBorderColor
},
'.regular': {
borderColor: variables.inputSuccessBorderColor
},
'.underline': {
borderWidth: variables.borderWidth * 2,
borderTopWidth: 0,
borderRightWidth: 0,
borderLeftWidth: 0,
borderColor: variables.inputSuccessBorderColor
},
borderColor: variables.inputSuccessBorderColor
},
'.error': {
'NativeBase.Icon': {
color: variables.inputErrorBorderColor
},
'NativeBase.IconNB': {
color: variables.inputErrorBorderColor
},
'.rounded': {
borderRadius: 30,
borderColor: variables.inputErrorBorderColor
},
'.regular': {
borderColor: variables.inputErrorBorderColor
},
'.underline': {
borderWidth: variables.borderWidth * 2,
borderTopWidth: 0,
borderRightWidth: 0,
borderLeftWidth: 0,
borderColor: variables.inputErrorBorderColor
},
borderColor: variables.inputErrorBorderColor
},
'.disabled': {
'NativeBase.Icon': {
color: '#384850'
},
'NativeBase.IconNB': {
color: '#384850'
}
},
'.picker': {
marginLeft: 0
},
borderWidth: variables.borderWidth * 2,
borderTopWidth: 0,
borderRightWidth: 0,
borderLeftWidth: 0,
borderColor: variables.inputBorderColor,
backgroundColor: 'transparent',
flexDirection: 'row',
alignItems: 'center',
marginLeft: 2
};
return itemTheme;
};

View file

@ -1,12 +0,0 @@
// @flow
export default () => {
const labelTheme = {
'.focused': {
width: 0
},
fontSize: 17
};
return labelTheme;
};

View file

@ -1,11 +0,0 @@
// @flow
export default () => {
const leftTheme = {
flex: 1,
alignSelf: 'center',
alignItems: 'flex-start'
};
return leftTheme;
};

View file

@ -1,446 +0,0 @@
// @flow
import { Platform, PixelRatio } from 'react-native';
import pickerTheme from './Picker';
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
export default (variables /* : * */ = variable) => {
const platform = variables.platform;
const selectedStyle = {
'NativeBase.Text': {
color: variables.listItemSelected
},
'NativeBase.Icon': {
color: variables.listItemSelected
}
};
const listItemTheme = {
'NativeBase.InputGroup': {
'NativeBase.Icon': {
paddingRight: 5
},
'NativeBase.IconNB': {
paddingRight: 5
},
'NativeBase.Input': {
paddingHorizontal: 5
},
flex: 1,
borderWidth: null,
margin: -10,
borderBottomColor: 'transparent'
},
'.searchBar': {
'NativeBase.Item': {
'NativeBase.Icon': {
backgroundColor: 'transparent',
color: variables.dropdownLinkColor,
fontSize:
platform === PLATFORM.IOS
? variables.iconFontSize - 10
: variables.iconFontSize - 5,
alignItems: 'center',
marginTop: 2,
paddingRight: 8
},
'NativeBase.IconNB': {
backgroundColor: 'transparent',
color: null,
alignSelf: 'center'
},
'NativeBase.Input': {
alignSelf: 'center'
},
alignSelf: 'center',
alignItems: 'center',
justifyContent: 'flex-start',
flex: 1,
height: platform === PLATFORM.IOS ? 30 : 40,
borderColor: 'transparent',
backgroundColor: '#fff',
borderRadius: 5
},
'NativeBase.Button': {
'.transparent': {
'NativeBase.Text': {
fontWeight: '500'
},
paddingHorizontal: null,
paddingLeft: platform === PLATFORM.IOS ? 10 : null
},
paddingHorizontal: platform === PLATFORM.IOS ? undefined : null,
width: platform === PLATFORM.IOS ? undefined : 0,
height: platform === PLATFORM.IOS ? undefined : 0
},
backgroundColor: variables.toolbarInputColor,
padding: 10,
marginLeft: null
},
'NativeBase.CheckBox': {
marginLeft: -10,
marginRight: 10
},
'.first': {
'.itemHeader': {
paddingTop: variables.listItemPadding + 3
}
},
'.itemHeader': {
'.first': {
paddingTop: variables.listItemPadding + 3
},
borderBottomWidth:
platform === PLATFORM.IOS ? variables.borderWidth : null,
marginLeft: null,
padding: variables.listItemPadding,
paddingLeft: variables.listItemPadding + 5,
paddingTop:
platform === PLATFORM.IOS ? variables.listItemPadding + 25 : undefined,
paddingBottom:
platform === PLATFORM.ANDROID ? variables.listItemPadding + 20 : undefined,
flexDirection: 'row',
borderColor: variables.listBorderColor,
'NativeBase.Text': {
fontSize: 14,
color: platform === PLATFORM.IOS ? undefined : variables.listNoteColor
}
},
'.itemDivider': {
borderBottomWidth: null,
marginLeft: null,
padding: variables.listItemPadding,
paddingLeft: variables.listItemPadding + 5,
backgroundColor: variables.listDividerBg,
flexDirection: 'row',
borderColor: variables.listBorderColor
},
'.selected': {
'NativeBase.Left': {
...selectedStyle
},
'NativeBase.Body': {
...selectedStyle
},
'NativeBase.Right': {
...selectedStyle
},
...selectedStyle
},
'NativeBase.Left': {
'NativeBase.Body': {
'NativeBase.Text': {
'.note': {
color: variables.listNoteColor,
fontWeight: '200'
},
fontWeight: '600'
},
marginLeft: 10,
alignItems: null,
alignSelf: null
},
'NativeBase.Icon': {
width: variables.iconFontSize - 10,
fontSize: variables.iconFontSize - 10
},
'NativeBase.IconNB': {
width: variables.iconFontSize - 10,
fontSize: variables.iconFontSize - 10
},
'NativeBase.Text': {
alignSelf: 'center'
},
flexDirection: 'row'
},
'NativeBase.Body': {
'NativeBase.Text': {
marginHorizontal: variables.listItemPadding,
'.note': {
color: variables.listNoteColor,
fontWeight: '200'
}
},
alignSelf: null,
alignItems: null
},
'NativeBase.Right': {
'NativeBase.Badge': {
alignSelf: null
},
'NativeBase.PickerNB': {
'NativeBase.Button': {
marginRight: -15,
'NativeBase.Text': {
color: variables.topTabBarActiveTextColor
}
}
},
'NativeBase.Button': {
alignSelf: null,
'.transparent': {
'NativeBase.Text': {
color: variables.topTabBarActiveTextColor
}
}
},
'NativeBase.Icon': {
alignSelf: null,
fontSize: variables.iconFontSize - 8,
color: '#c9c8cd'
},
'NativeBase.IconNB': {
alignSelf: null,
fontSize: variables.iconFontSize - 8,
color: '#c9c8cd'
},
'NativeBase.Text': {
'.note': {
color: variables.listNoteColor,
fontWeight: '200'
},
alignSelf: null
},
'NativeBase.Thumbnail': {
alignSelf: null
},
'NativeBase.Image': {
alignSelf: null
},
'NativeBase.Radio': {
alignSelf: null
},
'NativeBase.Checkbox': {
alignSelf: null
},
'NativeBase.Switch': {
alignSelf: null
},
padding: null,
flex: 0.28
},
'NativeBase.Text': {
'.note': {
color: variables.listNoteColor,
fontWeight: '200'
},
alignSelf: 'center'
},
'.last': {
marginLeft: -(variables.listItemPadding + 5),
paddingLeft: (variables.listItemPadding + 5) * 2,
top: 1
},
'.avatar': {
'NativeBase.Left': {
flex: 0,
alignSelf: 'flex-start',
paddingTop: 14
},
'NativeBase.Body': {
'NativeBase.Text': {
marginLeft: null
},
flex: 1,
paddingVertical: variables.listItemPadding,
borderBottomWidth: variables.borderWidth,
borderColor: variables.listBorderColor,
marginLeft: variables.listItemPadding + 5
},
'NativeBase.Right': {
'NativeBase.Text': {
'.note': {
fontSize: variables.noteFontSize - 2
}
},
flex: 0,
paddingRight: variables.listItemPadding + 5,
alignSelf: 'stretch',
paddingVertical: variables.listItemPadding,
borderBottomWidth: variables.borderWidth,
borderColor: variables.listBorderColor
},
'.noBorder': {
'NativeBase.Body': {
borderBottomWidth: null
},
'NativeBase.Right': {
borderBottomWidth: null
}
},
borderBottomWidth: null,
paddingVertical: null,
paddingRight: null
},
'.thumbnail': {
'NativeBase.Left': {
flex: 0
},
'NativeBase.Body': {
'NativeBase.Text': {
marginLeft: null
},
flex: 1,
paddingVertical: variables.listItemPadding + 8,
borderBottomWidth: variables.borderWidth,
borderColor: variables.listBorderColor,
marginLeft: variables.listItemPadding + 5
},
'NativeBase.Right': {
'NativeBase.Button': {
'.transparent': {
'NativeBase.Text': {
fontSize: variables.listNoteSize,
color: variables.sTabBarActiveTextColor
}
},
height: null
},
flex: 0,
justifyContent: 'center',
alignSelf: 'stretch',
paddingRight: variables.listItemPadding + 5,
paddingVertical: variables.listItemPadding + 5,
borderBottomWidth: variables.borderWidth,
borderColor: variables.listBorderColor
},
'.noBorder': {
'NativeBase.Body': {
borderBottomWidth: null
},
'NativeBase.Right': {
borderBottomWidth: null
}
},
borderBottomWidth: null,
paddingVertical: null,
paddingRight: null
},
'.icon': {
'.last': {
'NativeBase.Body': {
borderBottomWidth: null
},
'NativeBase.Right': {
borderBottomWidth: null
},
borderBottomWidth: variables.borderWidth,
borderColor: variables.listBorderColor
},
'NativeBase.Left': {
'NativeBase.Button': {
'NativeBase.IconNB': {
marginHorizontal: null,
fontSize: variables.iconFontSize - 5
},
'NativeBase.Icon': {
marginHorizontal: null,
fontSize: variables.iconFontSize - 8
},
alignSelf: 'center',
height: 29,
width: 29,
borderRadius: 6,
paddingVertical: null,
paddingHorizontal: null,
alignItems: 'center',
justifyContent: 'center'
},
'NativeBase.Icon': {
width: variables.iconFontSize - 5,
fontSize: variables.iconFontSize - 2
},
'NativeBase.IconNB': {
width: variables.iconFontSize - 5,
fontSize: variables.iconFontSize - 2
},
paddingRight: variables.listItemPadding + 5,
flex: 0,
height: 44,
justifyContent: 'center',
alignItems: 'center'
},
'NativeBase.Body': {
'NativeBase.Text': {
marginLeft: null,
fontSize: 17
},
flex: 1,
height: 44,
justifyContent: 'center',
borderBottomWidth: 1 / PixelRatio.getPixelSizeForLayoutSize(1),
borderColor: variables.listBorderColor
},
'NativeBase.Right': {
'NativeBase.Text': {
textAlign: 'center',
color: '#8F8E95',
fontSize: 17
},
'NativeBase.IconNB': {
color: '#C8C7CC',
fontSize: variables.iconFontSize - 10,
alignSelf: 'center',
paddingLeft: 10,
paddingTop: 3
},
'NativeBase.Icon': {
color: '#C8C7CC',
fontSize: variables.iconFontSize - 10,
alignSelf: 'center',
paddingLeft: 10,
paddingTop: 3
},
'NativeBase.Switch': {
marginRight: Platform.OS === PLATFORM.IOS ? undefined : -5,
alignSelf: null
},
'NativeBase.PickerNB': {
...pickerTheme()
},
flexDirection: 'row',
alignItems: 'center',
flex: 0,
alignSelf: 'stretch',
height: 44,
justifyContent: 'flex-end',
borderBottomWidth: 1 / PixelRatio.getPixelSizeForLayoutSize(1),
borderColor: variables.listBorderColor,
paddingRight: variables.listItemPadding + 5
},
'.noBorder': {
'NativeBase.Body': {
borderBottomWidth: null
},
'NativeBase.Right': {
borderBottomWidth: null
}
},
borderBottomWidth: null,
paddingVertical: null,
paddingRight: null,
height: 44,
justifyContent: 'center'
},
'.noBorder': {
borderBottomWidth: null
},
'.noIndent': {
marginLeft: null,
padding: variables.listItemPadding,
paddingLeft: variables.listItemPadding + 6
},
alignItems: 'center',
flexDirection: 'row',
paddingRight: variables.listItemPadding + 6,
paddingVertical: variables.listItemPadding + 3,
marginLeft: variables.listItemPadding + 6,
borderBottomWidth: 1 / PixelRatio.getPixelSizeForLayoutSize(1),
backgroundColor: variables.listBg,
borderColor: variables.listBorderColor
};
return listItemTheme;
};

View file

@ -1,14 +0,0 @@
// @flow
export default () => {
const pickerTheme = {
'.note': {
color: '#8F8E95'
},
// width: 90,
marginRight: -4,
flexGrow: 1
};
return pickerTheme;
};

View file

@ -1,7 +0,0 @@
// @flow
export default () => {
const pickerTheme = {};
return pickerTheme;
};

View file

@ -1,14 +0,0 @@
// @flow
export default () => {
const pickerTheme = {
'.note': {
color: '#8F8E95'
},
// width: 90,
marginRight: -4,
flexGrow: 1
};
return pickerTheme;
};

View file

@ -1,31 +0,0 @@
// @flow
import { Platform } from 'react-native';
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
export default (variables /* : * */ = variable) => {
const radioTheme = {
'.selected': {
'NativeBase.IconNB': {
color:
Platform.OS === PLATFORM.IOS
? variables.radioColor
: variables.radioSelectedColorAndroid,
lineHeight:
Platform.OS === PLATFORM.IOS ? 25 : variables.radioBtnLineHeight,
height: Platform.OS === PLATFORM.IOS ? 20 : undefined
}
},
'NativeBase.IconNB': {
color: Platform.OS === PLATFORM.IOS ? 'transparent' : undefined,
lineHeight:
Platform.OS === PLATFORM.IOS ? undefined : variables.radioBtnLineHeight,
fontSize:
Platform.OS === PLATFORM.IOS ? undefined : variables.radioBtnSize
}
};
return radioTheme;
};

View file

@ -1,14 +0,0 @@
// @flow
export default () => {
const rightTheme = {
'NativeBase.Button': {
alignSelf: null
},
flex: 1,
alignSelf: 'center',
alignItems: 'flex-end'
};
return rightTheme;
};

View file

@ -1,57 +0,0 @@
// @flow
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
export default (variables /* : * */ = variable) => {
const platform = variables.platform;
const segmentTheme = {
height: 45,
borderColor: variables.segmentBorderColorMain,
flexDirection: 'row',
justifyContent: 'center',
backgroundColor: variables.segmentBackgroundColor,
'NativeBase.Button': {
alignSelf: 'center',
borderRadius: 0,
paddingTop: 3,
paddingBottom: 3,
height: 30,
backgroundColor: 'transparent',
borderWidth: 1,
borderLeftWidth: 0,
borderColor: variables.segmentBorderColor,
elevation: 0,
'.active': {
backgroundColor: variables.segmentActiveBackgroundColor,
'NativeBase.Text': {
color: variables.segmentActiveTextColor
},
'NativeBase.Icon': {
color: variables.segmentActiveTextColor
}
},
'.first': {
borderTopLeftRadius: platform === PLATFORM.IOS ? 5 : undefined,
borderBottomLeftRadius: platform === PLATFORM.IOS ? 5 : undefined,
borderLeftWidth: 1
},
'.last': {
borderTopRightRadius: platform === PLATFORM.IOS ? 5 : undefined,
borderBottomRightRadius: platform === PLATFORM.IOS ? 5 : undefined
},
'NativeBase.Text': {
color: variables.segmentTextColor,
fontSize: 14
},
'NativeBase.Icon': {
fontSize: 22,
paddingTop: 0,
color: variables.segmentTextColor
}
}
};
return segmentTheme;
};

View file

@ -1,49 +0,0 @@
// @flow
import variable from './../variables/platform';
export default (variables /* : * */ = variable) => {
const theme = {
'.group': {
height: 50,
paddingVertical: variables.listItemPadding - 8,
paddingTop: variables.listItemPadding + 12,
'.bordered': {
height: 50,
paddingVertical: variables.listItemPadding - 8,
paddingTop: variables.listItemPadding + 12
}
},
'.bordered': {
'.noTopBorder': {
borderTopWidth: 0
},
'.noBottomBorder': {
borderBottomWidth: 0
},
height: 35,
paddingTop: variables.listItemPadding + 2,
paddingBottom: variables.listItemPadding,
borderBottomWidth: variables.borderWidth,
borderTopWidth: variables.borderWidth,
borderColor: variables.listBorderColor
},
'NativeBase.Text': {
fontSize: variables.tabBarTextSize - 2,
color: '#777'
},
'.noTopBorder': {
borderTopWidth: 0
},
'.noBottomBorder': {
borderBottomWidth: 0
},
height: 38,
backgroundColor: '#F0EFF5',
flex: 1,
justifyContent: 'center',
paddingLeft: variables.listItemPadding + 5
};
return theme;
};

View file

@ -1,9 +0,0 @@
// @flow
export default () => {
const spinnerTheme = {
height: 80
};
return spinnerTheme;
};

View file

@ -1,19 +0,0 @@
// @flow
import { Platform } from 'react-native';
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
export default (variables /* : * */ = variable) => {
const subtitleTheme = {
fontSize: variables.subTitleFontSize,
fontFamily: variables.titleFontfamily,
color: variables.subtitleColor,
textAlign: 'center',
paddingLeft: Platform.OS === PLATFORM.IOS ? 4 : 0,
marginLeft: Platform.OS === PLATFORM.IOS ? undefined : -3
};
return subtitleTheme;
};

View file

@ -1,46 +0,0 @@
// @flow
export default () => {
const swipeRowTheme = {
'NativeBase.ListItem': {
'.list': {
backgroundColor: '#FFF'
},
marginLeft: 0
},
'NativeBase.Left': {
flex: 0,
alignSelf: null,
alignItems: null,
'NativeBase.Button': {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
alignSelf: 'stretch',
borderRadius: 0
}
},
'NativeBase.Right': {
flex: 0,
alignSelf: null,
alignItems: null,
'NativeBase.Button': {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
alignSelf: 'stretch',
borderRadius: 0
}
},
'NativeBase.Button': {
flex: 1,
height: null,
alignItems: 'center',
justifyContent: 'center',
alignSelf: 'stretch',
borderRadius: 0
}
};
return swipeRowTheme;
};

View file

@ -1,9 +0,0 @@
// @flow
export default () => {
const switchTheme = {
marginVertical: -5
};
return switchTheme;
};

View file

@ -1,10 +0,0 @@
// @flow
export default () => {
const tabTheme = {
flex: 1,
backgroundColor: '#FFF'
};
return tabTheme;
};

View file

@ -1,57 +0,0 @@
// @flow
import variable from './../variables/platform';
export default (variables /* : * */ = variable) => {
const tabBarTheme = {
'.tabIcon': {
height: undefined
},
'.vertical': {
height: 60
},
'NativeBase.Button': {
'.transparent': {
'NativeBase.Text': {
fontSize: variables.tabFontSize,
color: variables.sTabBarActiveTextColor,
fontWeight: '400'
},
'NativeBase.IconNB': {
color: variables.sTabBarActiveTextColor
}
},
'NativeBase.IconNB': {
color: variables.sTabBarActiveTextColor
},
'NativeBase.Text': {
fontSize: variables.tabFontSize,
color: variables.sTabBarActiveTextColor,
fontWeight: '400'
},
'.isTabActive': {
'NativeBase.Text': {
fontWeight: '900'
}
},
flex: 1,
alignSelf: 'stretch',
alignItems: 'center',
justifyContent: 'center',
borderRadius: null,
borderBottomColor: 'transparent',
backgroundColor: variables.tabBgColor
},
height: 45,
flexDirection: 'row',
justifyContent: 'space-around',
borderWidth: 1,
borderTopWidth: 0,
borderLeftWidth: 0,
borderRightWidth: 0,
borderBottomColor: '#ccc',
backgroundColor: variables.tabBgColor
};
return tabBarTheme;
};

View file

@ -1,26 +0,0 @@
// @flow
import { Platform } from 'react-native';
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
export default (variables /* : * */ = variable) => {
const platformStyle = variables.platformStyle;
const tabContainerTheme = {
elevation: 3,
height: 50,
flexDirection: 'row',
shadowColor: platformStyle === PLATFORM.MATERIAL ? '#000' : undefined,
shadowOffset:
platformStyle === PLATFORM.MATERIAL ? { width: 0, height: 2 } : undefined,
shadowOpacity: platformStyle === PLATFORM.MATERIAL ? 0.2 : undefined,
shadowRadius: platformStyle === PLATFORM.MATERIAL ? 1.2 : undefined,
justifyContent: 'space-around',
borderBottomWidth: Platform.OS === PLATFORM.IOS ? variables.borderWidth : 0,
borderColor: variables.topTabBarBorderColor
};
return tabContainerTheme;
};

View file

@ -1,40 +0,0 @@
// @flow
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
export default (variables /* : * */ = variable) => {
const platform = variables.platform;
const tabHeadingTheme = {
flexDirection: 'row',
backgroundColor: variables.tabDefaultBg,
flex: 1,
alignItems: 'center',
justifyContent: 'center',
'.scrollable': {
paddingHorizontal: 20,
flex: platform === PLATFORM.ANDROID ? 0 : 1,
minWidth: platform === PLATFORM.ANDROID ? undefined : 60
},
'NativeBase.Text': {
color: variables.topTabBarTextColor,
marginHorizontal: 7
},
'NativeBase.Icon': {
color: variables.topTabBarTextColor,
fontSize: platform === PLATFORM.IOS ? 26 : undefined
},
'.active': {
'NativeBase.Text': {
color: variables.topTabBarActiveTextColor,
fontWeight: '600'
},
'NativeBase.Icon': {
color: variables.topTabBarActiveTextColor
}
}
};
return tabHeadingTheme;
};

View file

@ -1,17 +0,0 @@
// @flow
import variable from './../variables/platform';
export default (variables /* : * */ = variable) => {
const textTheme = {
fontSize: variables.DefaultFontSize,
fontFamily: variables.fontFamily,
color: variables.textColor,
'.note': {
color: '#a7a7a7',
fontSize: variables.noteFontSize
}
};
return textTheme;
};

View file

@ -1,25 +0,0 @@
// @flow
import variable from './../variables/platform';
export default (variables /* : * */ = variable) => {
const textAreaTheme = {
'.underline': {
borderBottomWidth: variables.borderWidth,
marginTop: 5,
borderColor: variables.inputBorderColor
},
'.bordered': {
borderWidth: 1,
marginTop: 5,
borderColor: variables.inputBorderColor
},
color: variables.textColor,
paddingLeft: 10,
paddingRight: 5,
fontSize: 15,
textAlignVertical: 'top'
};
return textAreaTheme;
};

View file

@ -1,40 +0,0 @@
// @flow
export default () => {
const thumbnailTheme = {
'.square': {
borderRadius: 0,
'.small': {
width: 36,
height: 36,
borderRadius: 0
},
'.large': {
width: 80,
height: 80,
borderRadius: 0
}
},
'.small': {
width: 36,
height: 36,
borderRadius: 18,
'.square': {
borderRadius: 0
}
},
'.large': {
width: 80,
height: 80,
borderRadius: 40,
'.square': {
borderRadius: 0
}
},
width: 56,
height: 56,
borderRadius: 28
};
return thumbnailTheme;
};

View file

@ -1,21 +0,0 @@
// @flow
import { Platform } from 'react-native';
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
export default (variables /* : * */ = variable) => {
const titleTheme = {
fontSize: variables.titleFontSize,
fontFamily: variables.titleFontfamily,
color: variables.titleFontColor,
fontWeight: Platform.OS === PLATFORM.IOS ? '700' : undefined,
textAlign: 'center',
paddingLeft: Platform.OS === PLATFORM.IOS ? 4 : 0,
marginLeft: Platform.OS === PLATFORM.IOS ? undefined : -3,
paddingTop: 1
};
return titleTheme;
};

View file

@ -1,41 +0,0 @@
// @flow
import variable from './../variables/platform';
import { PLATFORM } from './../variables/commonColor';
export default (variables /* : * */ = variable) => {
const platform = variables.platform;
const toastTheme = {
'.danger': {
backgroundColor: variables.brandDanger
},
'.warning': {
backgroundColor: variables.brandWarning
},
'.success': {
backgroundColor: variables.brandSuccess
},
backgroundColor: 'rgba(0,0,0,0.8)',
borderRadius: platform === PLATFORM.IOS ? 5 : 0,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
padding: 10,
minHeight: 50,
'NativeBase.Text': {
color: '#fff',
flex: 1
},
'NativeBase.Button': {
backgroundColor: 'transparent',
height: 30,
elevation: 0,
'NativeBase.Text': {
fontSize: 14
}
}
};
return toastTheme;
};

View file

@ -1,13 +0,0 @@
// @flow
import variable from './../variables/platform';
export default (variables /* : * */ = variable) => {
const viewTheme = {
'.padder': {
padding: variables.contentPadding
}
};
return viewTheme;
};

View file

@ -1,249 +0,0 @@
/* eslint-disable no-param-reassign */
// @flow
import _ from 'lodash';
import bodyTheme from './Body';
import leftTheme from './Left';
import rightTheme from './Right';
import headerTheme from './Header';
import switchTheme from './Switch';
import thumbnailTheme from './Thumbnail';
import containerTheme from './Container';
import contentTheme from './Content';
import buttonTheme from './Button';
import titleTheme from './Title';
import subtitleTheme from './Subtitle';
import inputGroupTheme from './InputGroup';
import badgeTheme from './Badge';
import checkBoxTheme from './CheckBox';
import cardTheme from './Card';
import radioTheme from './Radio';
import h3Theme from './H3';
import h2Theme from './H2';
import h1Theme from './H1';
import footerTheme from './Footer';
import footerTabTheme from './FooterTab';
import fabTheme from './Fab';
import itemTheme from './Item';
import labelTheme from './Label';
import textAreaTheme from './Textarea';
import textTheme from './Text';
import toastTheme from './Toast';
import tabTheme from './Tab';
import tabBarTheme from './TabBar';
import tabContainerTheme from './TabContainer';
import viewTheme from './View';
import tabHeadingTheme from './TabHeading';
import iconTheme from './Icon';
import inputTheme from './Input';
import swipeRowTheme from './SwipeRow';
import segmentTheme from './Segment';
import spinnerTheme from './Spinner';
import cardItemTheme from './CardItem';
import listItemTheme from './ListItem';
import formTheme from './Form';
import separatorTheme from './Separator';
import pickerTheme from './Picker';
import variable from './../variables/platform';
export default (variables /* : * */ = variable) => {
const theme = {
variables,
'NativeBase.Left': {
...leftTheme(variables)
},
'NativeBase.Right': {
...rightTheme(variables)
},
'NativeBase.Body': {
...bodyTheme(variables)
},
'NativeBase.Header': {
...headerTheme(variables)
},
'NativeBase.Button': {
...buttonTheme(variables)
},
'NativeBase.Title': {
...titleTheme(variables)
},
'NativeBase.Subtitle': {
...subtitleTheme(variables)
},
'NativeBase.InputGroup': {
...inputGroupTheme(variables)
},
'NativeBase.Input': {
...inputTheme(variables)
},
'NativeBase.Badge': {
...badgeTheme(variables)
},
'NativeBase.CheckBox': {
...checkBoxTheme(variables)
},
'NativeBase.Radio': {
...radioTheme(variables)
},
'NativeBase.Card': {
...cardTheme(variables)
},
'NativeBase.CardItem': {
...cardItemTheme(variables)
},
'NativeBase.Toast': {
...toastTheme(variables)
},
'NativeBase.H1': {
...h1Theme(variables)
},
'NativeBase.H2': {
...h2Theme(variables)
},
'NativeBase.H3': {
...h3Theme(variables)
},
'NativeBase.Form': {
...formTheme(variables)
},
'NativeBase.Container': {
...containerTheme(variables)
},
'NativeBase.Content': {
...contentTheme(variables)
},
'NativeBase.Footer': {
...footerTheme(variables)
},
'NativeBase.Tabs': {
flex: 1
},
'NativeBase.FooterTab': {
...footerTabTheme(variables)
},
'NativeBase.ListItem': {
...listItemTheme(variables)
},
'NativeBase.ListItem1': {
...listItemTheme(variables)
},
'NativeBase.Icon': {
...iconTheme(variables)
},
'NativeBase.IconNB': {
...iconTheme(variables)
},
'NativeBase.Text': {
...textTheme(variables)
},
'NativeBase.Spinner': {
...spinnerTheme(variables)
},
'NativeBase.Fab': {
...fabTheme(variables)
},
'NativeBase.Item': {
...itemTheme(variables)
},
'NativeBase.Label': {
...labelTheme(variables)
},
'NativeBase.Textarea': {
...textAreaTheme(variables)
},
'NativeBase.PickerNB': {
...pickerTheme(variables),
'NativeBase.Button': {
'NativeBase.Text': {}
}
},
'NativeBase.Tab': {
...tabTheme(variables)
},
'NativeBase.Segment': {
...segmentTheme(variables)
},
'NativeBase.TabBar': {
...tabBarTheme(variables)
},
'NativeBase.ViewNB': {
...viewTheme(variables)
},
'NativeBase.TabHeading': {
...tabHeadingTheme(variables)
},
'NativeBase.TabContainer': {
...tabContainerTheme(variables)
},
'NativeBase.Switch': {
...switchTheme(variables)
},
'NativeBase.Separator': {
...separatorTheme(variables)
},
'NativeBase.SwipeRow': {
...swipeRowTheme(variables)
},
'NativeBase.Thumbnail': {
...thumbnailTheme(variables)
}
};
const cssifyTheme = (grandparent, parent, parentKey) => {
_.forEach(parent, (style, styleName) => {
if (
styleName.indexOf('.') === 0 &&
parentKey &&
parentKey.indexOf('.') === 0
) {
if (grandparent) {
if (!grandparent[styleName]) {
grandparent[styleName] = {};
} else {
grandparent[styleName][parentKey] = style;
}
}
}
if (
style &&
typeof style === 'object' &&
styleName !== 'fontVariant' &&
styleName !== 'transform'
) {
cssifyTheme(parent, style, styleName);
}
});
};
cssifyTheme(null, theme, null);
return theme;
};

View file

@ -1,311 +0,0 @@
// @flow
import color from 'color';
import { Platform, Dimensions, PixelRatio } from 'react-native';
export const PLATFORM = {
ANDROID: 'android',
IOS: 'ios',
MATERIAL: 'material',
WEB: 'web'
};
const deviceHeight = Dimensions.get('window').height;
const deviceWidth = Dimensions.get('window').width;
const platform = Platform.OS;
const platformStyle = undefined;
const isIphoneX =
platform === PLATFORM.IOS &&
(deviceHeight === 812 ||
deviceWidth === 812 ||
deviceHeight === 896 ||
deviceWidth === 896);
export default {
platformStyle,
platform,
// Accordion
headerStyle: '#edebed',
iconStyle: '#000',
contentStyle: '#f5f4f5',
expandedIconStyle: '#000',
accordionBorderColor: '#d3d3d3',
// ActionSheet
elevation: 4,
containerTouchableBackgroundColor: 'rgba(0,0,0,0.4)',
innerTouchableBackgroundColor: '#fff',
listItemHeight: 50,
listItemBorderColor: 'transparent',
marginHorizontal: -15,
marginLeft: 14,
marginTop: 15,
minHeight: 56,
padding: 15,
touchableTextColor: '#757575',
// Android
androidRipple: true,
androidRippleColor: 'rgba(256, 256, 256, 0.3)',
androidRippleColorDark: 'rgba(0, 0, 0, 0.15)',
buttonUppercaseAndroidText: true,
// Badge
badgeBg: '#ED1727',
badgeColor: '#fff',
badgePadding: platform === PLATFORM.IOS ? 3 : 0,
// Button
buttonFontFamily: platform === PLATFORM.IOS ? 'System' : 'Roboto_medium',
buttonDisabledBg: '#b5b5b5',
buttonPadding: 6,
get buttonPrimaryBg() {
return this.brandPrimary;
},
get buttonPrimaryColor() {
return this.inverseTextColor;
},
get buttonInfoBg() {
return this.brandInfo;
},
get buttonInfoColor() {
return this.inverseTextColor;
},
get buttonSuccessBg() {
return this.brandSuccess;
},
get buttonSuccessColor() {
return this.inverseTextColor;
},
get buttonDangerBg() {
return this.brandDanger;
},
get buttonDangerColor() {
return this.inverseTextColor;
},
get buttonWarningBg() {
return this.brandWarning;
},
get buttonWarningColor() {
return this.inverseTextColor;
},
get buttonTextSize() {
return platform === PLATFORM.IOS
? this.fontSizeBase * 1.1
: this.fontSizeBase - 1;
},
get buttonTextSizeLarge() {
return this.fontSizeBase * 1.5;
},
get buttonTextSizeSmall() {
return this.fontSizeBase * 0.8;
},
get borderRadiusLarge() {
return this.fontSizeBase * 3.8;
},
get iconSizeLarge() {
return this.iconFontSize * 1.5;
},
get iconSizeSmall() {
return this.iconFontSize * 0.6;
},
// Card
cardDefaultBg: '#fff',
cardBorderColor: '#ccc',
cardBorderRadius: 2,
cardItemPadding: platform === PLATFORM.IOS ? 10 : 12,
// CheckBox
CheckboxRadius: platform === PLATFORM.IOS ? 13 : 0,
CheckboxBorderWidth: platform === PLATFORM.IOS ? 1 : 2,
CheckboxPaddingLeft: platform === PLATFORM.IOS ? 4 : 2,
CheckboxPaddingBottom: platform === PLATFORM.IOS ? 0 : 5,
CheckboxIconSize: platform === PLATFORM.IOS ? 21 : 16,
CheckboxIconMarginTop: platform === PLATFORM.IOS ? undefined : 1,
CheckboxFontSize: platform === PLATFORM.IOS ? 23 / 0.9 : 17,
checkboxBgColor: '#039BE5',
checkboxSize: 20,
checkboxTickColor: '#fff',
// Color
brandPrimary: platform === PLATFORM.IOS ? '#007aff' : '#3F51B5',
brandInfo: '#62B1F6',
brandSuccess: '#5cb85c',
brandDanger: '#d9534f',
brandWarning: '#f0ad4e',
brandDark: '#000',
brandLight: '#f4f4f4',
// Container
containerBgColor: '#fff',
// Date Picker
datePickerTextColor: '#000',
datePickerBg: 'transparent',
// FAB
fabWidth: 56,
// Font
DefaultFontSize: 16,
fontFamily: platform === PLATFORM.IOS ? 'System' : 'Roboto',
fontSizeBase: 15,
get fontSizeH1() {
return this.fontSizeBase * 1.8;
},
get fontSizeH2() {
return this.fontSizeBase * 1.6;
},
get fontSizeH3() {
return this.fontSizeBase * 1.4;
},
// Footer
footerHeight: 55,
footerDefaultBg: platform === PLATFORM.IOS ? '#F8F8F8' : '#3F51B5',
footerPaddingBottom: 0,
// FooterTab
tabBarTextColor: platform === PLATFORM.IOS ? '#737373' : '#bfc6ea',
tabBarTextSize: platform === PLATFORM.IOS ? 14 : 11,
activeTab: platform === PLATFORM.IOS ? '#007aff' : '#fff',
sTabBarActiveTextColor: '#007aff',
tabBarActiveTextColor: platform === PLATFORM.IOS ? '#2874F0' : '#fff',
tabActiveBgColor: platform === PLATFORM.IOS ? '#cde1f9' : '#3F51B5',
// Header
toolbarBtnColor: platform === PLATFORM.IOS ? '#007aff' : '#fff',
toolbarDefaultBg: platform === PLATFORM.IOS ? '#F8F8F8' : '#3F51B5',
toolbarHeight: platform === PLATFORM.IOS ? 64 : 56,
toolbarSearchIconSize: platform === PLATFORM.IOS ? 20 : 23,
toolbarInputColor: platform === PLATFORM.IOS ? '#CECDD2' : '#fff',
searchBarHeight: platform === PLATFORM.IOS ? 30 : 40,
searchBarInputHeight: platform === PLATFORM.IOS ? 30 : 50,
toolbarBtnTextColor: platform === PLATFORM.IOS ? '#007aff' : '#fff',
iosStatusbar: 'dark-content',
toolbarDefaultBorder: platform === PLATFORM.IOS ? '#a7a6ab' : '#3F51B5',
get statusBarColor() {
return color(this.toolbarDefaultBg)
.darken(0.2)
.hex();
},
get darkenHeader() {
return color(this.tabBgColor)
.darken(0.03)
.hex();
},
// Icon
iconFamily: 'Ionicons',
iconFontSize: platform === PLATFORM.IOS ? 30 : 28,
iconHeaderSize: platform === PLATFORM.IOS ? 33 : 24,
// InputGroup
inputFontSize: 17,
inputBorderColor: '#D9D5DC',
inputSuccessBorderColor: '#2b8339',
inputErrorBorderColor: '#ed2f2f',
inputHeightBase: 50,
get inputColor() {
return this.textColor;
},
get inputColorPlaceholder() {
return '#575757';
},
// Line Height
buttonLineHeight: 19,
lineHeightH1: 32,
lineHeightH2: 27,
lineHeightH3: 22,
lineHeight: platform === PLATFORM.IOS ? 20 : 24,
// List
listBg: 'transparent',
listBorderColor: '#c9c9c9',
listDividerBg: '#f4f4f4',
listBtnUnderlayColor: '#DDD',
listItemPadding: platform === PLATFORM.IOS ? 10 : 12,
listNoteColor: '#808080',
listNoteSize: 13,
listItemSelected: platform === PLATFORM.IOS ? '#007aff' : '#3F51B5',
// Progress Bar
defaultProgressColor: '#E4202D',
inverseProgressColor: '#1A191B',
// Radio Button
radioBtnSize: platform === PLATFORM.IOS ? 25 : 23,
radioSelectedColorAndroid: '#3F51B5',
radioBtnLineHeight: platform === PLATFORM.IOS ? 29 : 24,
get radioColor() {
return this.brandPrimary;
},
// Segment
segmentBackgroundColor: platform === PLATFORM.IOS ? '#F8F8F8' : '#3F51B5',
segmentActiveBackgroundColor: platform === PLATFORM.IOS ? '#007aff' : '#fff',
segmentTextColor: platform === PLATFORM.IOS ? '#007aff' : '#fff',
segmentActiveTextColor: platform === PLATFORM.IOS ? '#fff' : '#3F51B5',
segmentBorderColor: platform === PLATFORM.IOS ? '#007aff' : '#fff',
segmentBorderColorMain: platform === PLATFORM.IOS ? '#a7a6ab' : '#3F51B5',
// Spinner
defaultSpinnerColor: '#45D56E',
inverseSpinnerColor: '#1A191B',
// Tab
tabDefaultBg: platform === PLATFORM.IOS ? '#F8F8F8' : '#3F51B5',
topTabBarTextColor: platform === PLATFORM.IOS ? '#6b6b6b' : '#b3c7f9',
topTabBarActiveTextColor: platform === PLATFORM.IOS ? '#007aff' : '#fff',
topTabBarBorderColor: platform === PLATFORM.IOS ? '#a7a6ab' : '#fff',
topTabBarActiveBorderColor: platform === PLATFORM.IOS ? '#007aff' : '#fff',
// Tabs
tabBgColor: '#F8F8F8',
tabFontSize: 15,
// Text
textColor: '#000',
inverseTextColor: '#fff',
noteFontSize: 14,
get defaultTextColor() {
return this.textColor;
},
// Title
titleFontfamily: platform === PLATFORM.IOS ? 'System' : 'Roboto_medium',
titleFontSize: platform === PLATFORM.IOS ? 17 : 19,
subTitleFontSize: platform === PLATFORM.IOS ? 11 : 14,
subtitleColor: platform === PLATFORM.IOS ? '#000' : '#fff',
titleFontColor: platform === PLATFORM.IOS ? '#000' : '#fff',
// Other
borderRadiusBase: platform === PLATFORM.IOS ? 5 : 2,
borderWidth: 1 / PixelRatio.getPixelSizeForLayoutSize(1),
contentPadding: 10,
dropdownLinkColor: '#414142',
inputLineHeight: 24,
deviceWidth,
deviceHeight,
isIphoneX,
inputGroupRoundedBorderRadius: 30,
// iPhoneX SafeArea
Inset: {
portrait: {
topInset: 24,
leftInset: 0,
rightInset: 0,
bottomInset: 34
},
landscape: {
topInset: 0,
leftInset: 44,
rightInset: 44,
bottomInset: 21
}
}
};

View file

@ -1,304 +0,0 @@
// @flow
import color from 'color';
import { Platform, Dimensions, PixelRatio } from 'react-native';
import { PLATFORM } from './commonColor';
const deviceHeight = Dimensions.get('window').height;
const deviceWidth = Dimensions.get('window').width;
const platform = Platform.OS;
const platformStyle = PLATFORM.MATERIAL;
const isIphoneX =
platform === PLATFORM.IOS &&
(deviceHeight === 812 ||
deviceWidth === 812 ||
deviceHeight === 896 ||
deviceWidth === 896);
export default {
platformStyle,
platform,
// Accordion
headerStyle: '#edebed',
iconStyle: '#000',
contentStyle: '#f5f4f5',
expandedIconStyle: '#000',
accordionBorderColor: '#d3d3d3',
// ActionSheet
elevation: 4,
containerTouchableBackgroundColor: 'rgba(0,0,0,0.4)',
innerTouchableBackgroundColor: '#fff',
listItemHeight: 50,
listItemBorderColor: 'transparent',
marginHorizontal: -15,
marginLeft: 14,
marginTop: 15,
minHeight: 56,
padding: 15,
touchableTextColor: '#757575',
// Android
androidRipple: true,
androidRippleColor: 'rgba(256, 256, 256, 0.3)',
androidRippleColorDark: 'rgba(0, 0, 0, 0.15)',
buttonUppercaseAndroidText: true,
// Badge
badgeBg: '#ED1727',
badgeColor: '#fff',
badgePadding: 0,
// Button
buttonFontFamily: 'Roboto',
buttonDisabledBg: '#b5b5b5',
buttonPadding: 6,
get buttonPrimaryBg() {
return this.brandPrimary;
},
get buttonPrimaryColor() {
return this.inverseTextColor;
},
get buttonInfoBg() {
return this.brandInfo;
},
get buttonInfoColor() {
return this.inverseTextColor;
},
get buttonSuccessBg() {
return this.brandSuccess;
},
get buttonSuccessColor() {
return this.inverseTextColor;
},
get buttonDangerBg() {
return this.brandDanger;
},
get buttonDangerColor() {
return this.inverseTextColor;
},
get buttonWarningBg() {
return this.brandWarning;
},
get buttonWarningColor() {
return this.inverseTextColor;
},
get buttonTextSize() {
return this.fontSizeBase - 1;
},
get buttonTextSizeLarge() {
return this.fontSizeBase * 1.5;
},
get buttonTextSizeSmall() {
return this.fontSizeBase * 0.8;
},
get borderRadiusLarge() {
return this.fontSizeBase * 3.8;
},
get iconSizeLarge() {
return this.iconFontSize * 1.5;
},
get iconSizeSmall() {
return this.iconFontSize * 0.6;
},
// Card
cardDefaultBg: '#fff',
cardBorderColor: '#ccc',
cardBorderRadius: 2,
cardItemPadding: platform === PLATFORM.IOS ? 10 : 12,
// CheckBox
CheckboxRadius: 0,
CheckboxBorderWidth: 2,
CheckboxPaddingLeft: 2,
CheckboxPaddingBottom: 5,
CheckboxIconSize: 16,
CheckboxIconMarginTop: 1,
CheckboxFontSize: 17,
checkboxBgColor: '#039BE5',
checkboxSize: 20,
checkboxTickColor: '#fff',
// Color
brandPrimary: '#3F51B5',
brandInfo: '#62B1F6',
brandSuccess: '#5cb85c',
brandDanger: '#d9534f',
brandWarning: '#f0ad4e',
brandDark: '#000',
brandLight: '#f4f4f4',
// Container
containerBgColor: '#fff',
// Date Picker
datePickerTextColor: '#000',
datePickerBg: 'transparent',
// FAB
fabWidth: 56,
// Font
DefaultFontSize: 16,
fontFamily: 'Roboto',
fontSizeBase: 15,
get fontSizeH1() {
return this.fontSizeBase * 1.8;
},
get fontSizeH2() {
return this.fontSizeBase * 1.6;
},
get fontSizeH3() {
return this.fontSizeBase * 1.4;
},
// Footer
footerHeight: 55,
footerDefaultBg: '#3F51B5',
footerPaddingBottom: 0,
// FooterTab
tabBarTextColor: '#bfc6ea',
tabBarTextSize: 11,
activeTab: '#fff',
sTabBarActiveTextColor: '#007aff',
tabBarActiveTextColor: '#fff',
tabActiveBgColor: '#3F51B5',
// Header
toolbarBtnColor: '#fff',
toolbarDefaultBg: '#3F51B5',
toolbarHeight: 56,
toolbarSearchIconSize: 23,
toolbarInputColor: '#fff',
searchBarHeight: platform === PLATFORM.IOS ? 30 : 40,
searchBarInputHeight: platform === PLATFORM.IOS ? 40 : 50,
toolbarBtnTextColor: '#fff',
toolbarDefaultBorder: '#3F51B5',
iosStatusbar: 'light-content',
get statusBarColor() {
return color(this.toolbarDefaultBg)
.darken(0.2)
.hex();
},
get darkenHeader() {
return color(this.tabBgColor)
.darken(0.03)
.hex();
},
// Icon
iconFamily: 'Ionicons',
iconFontSize: 28,
iconHeaderSize: 24,
// InputGroup
inputFontSize: 17,
inputBorderColor: '#D9D5DC',
inputSuccessBorderColor: '#2b8339',
inputErrorBorderColor: '#ed2f2f',
inputHeightBase: 50,
get inputColor() {
return this.textColor;
},
get inputColorPlaceholder() {
return '#575757';
},
// Line Height
buttonLineHeight: 19,
lineHeightH1: 32,
lineHeightH2: 27,
lineHeightH3: 22,
lineHeight: 24,
// List
listBg: 'transparent',
listBorderColor: '#c9c9c9',
listDividerBg: '#f4f4f4',
listBtnUnderlayColor: '#DDD',
listItemPadding: 12,
listNoteColor: '#808080',
listNoteSize: 13,
listItemSelected: '#3F51B5',
// Progress Bar
defaultProgressColor: '#E4202D',
inverseProgressColor: '#1A191B',
// Radio Button
radioBtnSize: 23,
radioSelectedColorAndroid: '#3F51B5',
radioBtnLineHeight: 24,
get radioColor() {
return this.brandPrimary;
},
// Segment
segmentBackgroundColor: '#3F51B5',
segmentActiveBackgroundColor: '#fff',
segmentTextColor: '#fff',
segmentActiveTextColor: '#3F51B5',
segmentBorderColor: '#fff',
segmentBorderColorMain: '#3F51B5',
// Spinner
defaultSpinnerColor: '#45D56E',
inverseSpinnerColor: '#1A191B',
// Tab
tabDefaultBg: '#3F51B5',
topTabBarTextColor: '#b3c7f9',
topTabBarActiveTextColor: '#fff',
topTabBarBorderColor: '#fff',
topTabBarActiveBorderColor: '#fff',
// Tabs
tabBgColor: '#F8F8F8',
tabFontSize: 15,
// Text
textColor: '#000',
inverseTextColor: '#fff',
noteFontSize: 14,
get defaultTextColor() {
return this.textColor;
},
// Title
titleFontfamily: 'Roboto',
titleFontSize: 19,
subTitleFontSize: 14,
subtitleColor: '#FFF',
titleFontColor: '#FFF',
// Other
borderRadiusBase: 2,
borderWidth: 1 / PixelRatio.getPixelSizeForLayoutSize(1),
contentPadding: 10,
dropdownLinkColor: '#414142',
inputLineHeight: 24,
deviceWidth,
deviceHeight,
isIphoneX,
inputGroupRoundedBorderRadius: 30,
// iPhoneX SafeArea
Inset: {
portrait: {
topInset: 24,
leftInset: 0,
rightInset: 0,
bottomInset: 34
},
landscape: {
topInset: 0,
leftInset: 44,
rightInset: 44,
bottomInset: 21
}
}
};

View file

@ -1,362 +0,0 @@
// @flow
import color from 'color';
import { Platform, Dimensions, PixelRatio } from 'react-native';
import { PLATFORM } from './commonColor';
const deviceHeight = Dimensions.get('window').height;
const deviceWidth = Dimensions.get('window').width;
const platform = Platform.OS;
const platformStyle = undefined;
const isIphoneX =
platform === PLATFORM.IOS &&
(deviceHeight === 812 ||
deviceWidth === 812 ||
deviceHeight === 896 ||
deviceWidth === 896);
export default {
platformStyle,
platform,
// Accordion
accordionBorderColor: '#d3d3d3',
accordionContentPadding: 10,
accordionIconFontSize: 18,
contentStyle: '#f5f4f5',
expandedIconStyle: '#000',
headerStyle: '#edebed',
iconStyle: '#000',
// ActionSheet
elevation: 4,
containerTouchableBackgroundColor: 'rgba(0,0,0,0.4)',
innerTouchableBackgroundColor: '#fff',
listItemHeight: 50,
listItemBorderColor: 'transparent',
marginHorizontal: -15,
marginLeft: 14,
marginTop: 15,
minHeight: 56,
padding: 15,
touchableTextColor: '#757575',
// Android
androidRipple: true,
androidRippleColor: 'rgba(256, 256, 256, 0.3)',
androidRippleColorDark: 'rgba(0, 0, 0, 0.15)',
buttonUppercaseAndroidText: true,
// Badge
badgeBg: '#ED1727',
badgeColor: '#fff',
badgePadding: platform === PLATFORM.IOS ? 3 : 0,
// Button
buttonFontFamily: platform === PLATFORM.IOS ? 'System' : 'Roboto_medium',
buttonTextColor: '#fff',
buttonDisabledBg: '#b5b5b5',
buttonPadding: 6,
buttonDefaultActiveOpacity: 0.5,
buttonDefaultFlex: 1,
buttonDefaultBorderRadius: 2,
buttonDefaultBorderWidth: 1,
get buttonPrimaryBg() {
return this.brandPrimary;
},
get buttonPrimaryColor() {
return this.inverseTextColor;
},
get buttonInfoBg() {
return this.brandInfo;
},
get buttonInfoColor() {
return this.inverseTextColor;
},
get buttonSuccessBg() {
return this.brandSuccess;
},
get buttonSuccessColor() {
return this.inverseTextColor;
},
get buttonDangerBg() {
return this.brandDanger;
},
get buttonDangerColor() {
return this.inverseTextColor;
},
get buttonWarningBg() {
return this.brandWarning;
},
get buttonWarningColor() {
return this.inverseTextColor;
},
get buttonTextSize() {
return platform === PLATFORM.IOS
? this.fontSizeBase * 1.1
: this.fontSizeBase - 1;
},
get buttonTextSizeLarge() {
return this.fontSizeBase * 1.5;
},
get buttonTextSizeSmall() {
return this.fontSizeBase * 0.8;
},
get borderRadiusLarge() {
return this.fontSizeBase * 3.8;
},
get iconSizeLarge() {
return this.iconFontSize * 1.5;
},
get iconSizeSmall() {
return this.iconFontSize * 0.6;
},
// Card
cardDefaultBg: '#fff',
cardBorderColor: '#ccc',
cardBorderRadius: 2,
cardItemPadding: platform === PLATFORM.IOS ? 10 : 12,
// CheckBox
CheckboxRadius: platform === PLATFORM.IOS ? 13 : 0,
CheckboxBorderWidth: platform === PLATFORM.IOS ? 1 : 2,
CheckboxPaddingLeft: platform === PLATFORM.IOS ? 4 : 2,
CheckboxPaddingBottom: platform === PLATFORM.IOS ? 0 : 5,
CheckboxIconSize: platform === PLATFORM.IOS ? 21 : 16,
CheckboxIconMarginTop: platform === PLATFORM.IOS ? undefined : 1,
CheckboxFontSize: platform === PLATFORM.IOS ? 23 / 0.9 : 17,
checkboxBgColor: '#be1522',
checkboxSize: 20,
checkboxTickColor: '#fff',
checkboxDefaultColor: 'transparent',
checkboxTextShadowRadius: 0,
// Color
brandPrimary: '#be1522',
brandInfo: '#62B1F6',
brandSuccess: '#5cb85c',
brandDanger: '#d9534f',
brandWarning: '#f0ad4e',
brandDark: '#000',
brandLight: '#f4f4f4',
// Container
containerBgColor: '#fff',
sideMenuBgColor: "#f2f2f2",
// Date Picker
datePickerFlex: 1,
datePickerPadding: 10,
datePickerTextColor: '#000',
datePickerBg: 'transparent',
// FAB
fabBackgroundColor: 'blue',
fabBorderRadius: 28,
fabBottom: 0,
fabButtonBorderRadius: 20,
fabButtonHeight: 40,
fabButtonLeft: 7,
fabButtonMarginBottom: 10,
fabContainerBottom: 20,
fabDefaultPosition: 20,
fabElevation: 4,
fabIconColor: '#fff',
fabIconSize: 24,
fabShadowColor: '#000',
fabShadowOffsetHeight: 2,
fabShadowOffsetWidth: 0,
fabShadowOpacity: 0.4,
fabShadowRadius: 2,
fabWidth: 56,
// Font
DefaultFontSize: 16,
fontFamily: platform === PLATFORM.IOS ? 'System' : 'Roboto',
fontSizeBase: 15,
get fontSizeH1() {
return this.fontSizeBase * 1.8;
},
get fontSizeH2() {
return this.fontSizeBase * 1.6;
},
get fontSizeH3() {
return this.fontSizeBase * 1.4;
},
// Footer
footerHeight: 55,
footerDefaultBg: platform === PLATFORM.IOS ? '#F8F8F8' : '#be1522',
footerPaddingBottom: 0,
// FooterTab
tabBarTextColor: platform === PLATFORM.IOS ? '#6b6b6b' : '#b3c7f9',
tabBarTextSize: platform === PLATFORM.IOS ? 14 : 11,
activeTab: platform === PLATFORM.IOS ? '#007aff' : '#fff',
sTabBarActiveTextColor: '#007aff',
tabBarActiveTextColor: platform === PLATFORM.IOS ? '#007aff' : '#fff',
tabActiveBgColor: platform === PLATFORM.IOS ? '#cde1f9' : '#3F51B5',
// Header
toolbarBtnColor: platform === PLATFORM.IOS ? '#be1522' : '#fff',
toolbarDefaultBg: platform === PLATFORM.IOS ? '#F8F8F8' : '#be1522',
toolbarHeight: platform === PLATFORM.IOS ? 64 : 56,
toolbarSearchIconSize: platform === PLATFORM.IOS ? 20 : 23,
toolbarInputColor: platform === PLATFORM.IOS ? '#CECDD2' : '#fff',
searchBarHeight: platform === PLATFORM.IOS ? 30 : 40,
searchBarInputHeight: platform === PLATFORM.IOS ? 30 : 50,
toolbarBtnTextColor: platform === PLATFORM.IOS ? '#be1522' : '#fff',
toolbarDefaultBorder: platform === PLATFORM.IOS ? '#a7a6ab' : '#be1522',
iosStatusbar: platform === PLATFORM.IOS ? 'dark-content' : 'light-content',
toolbarTextColor: platform === PLATFORM.IOS ? '#000000' : '#ffffff',
get statusBarColor() {
return color(this.toolbarDefaultBg)
.darken(0.2)
.hex();
},
get darkenHeader() {
return color(this.tabBgColor)
.darken(0.03)
.hex();
},
// Icon
iconFamily: 'Ionicons',
iconFontSize: platform === PLATFORM.IOS ? 30 : 28,
iconHeaderSize: platform === PLATFORM.IOS ? 33 : 24,
// InputGroup
inputFontSize: 17,
inputBorderColor: '#D9D5DC',
inputSuccessBorderColor: '#2b8339',
inputErrorBorderColor: '#ed2f2f',
inputHeightBase: 50,
get inputColor() {
return this.textColor;
},
get inputColorPlaceholder() {
return '#575757';
},
// Line Height
buttonLineHeight: 19,
lineHeightH1: 32,
lineHeightH2: 27,
lineHeightH3: 22,
lineHeight: platform === PLATFORM.IOS ? 20 : 24,
listItemSelected: '#be1522',
// List
listBg: 'transparent',
listBorderColor: '#c9c9c9',
listDividerBg: '#e2e2e2',
listBtnUnderlayColor: '#DDD',
listItemPadding: platform === PLATFORM.IOS ? 10 : 12,
listNoteColor: '#808080',
listNoteSize: 13,
// Progress Bar
defaultProgressColor: '#E4202D',
inverseProgressColor: '#1A191B',
// Radio Button
radioBtnSize: platform === PLATFORM.IOS ? 25 : 23,
radioSelectedColorAndroid: '#be1522',
radioBtnLineHeight: platform === PLATFORM.IOS ? 29 : 24,
get radioColor() {
return this.brandPrimary;
},
// Segment
segmentBackgroundColor: platform === PLATFORM.IOS ? '#F8F8F8' : '#3F51B5',
segmentActiveBackgroundColor: platform === PLATFORM.IOS ? '#007aff' : '#fff',
segmentTextColor: platform === PLATFORM.IOS ? '#007aff' : '#fff',
segmentActiveTextColor: platform === PLATFORM.IOS ? '#fff' : '#3F51B5',
segmentBorderColor: platform === PLATFORM.IOS ? '#007aff' : '#fff',
segmentBorderColorMain: platform === PLATFORM.IOS ? '#a7a6ab' : '#3F51B5',
// Spinner
defaultSpinnerColor: '#be1522',
inverseSpinnerColor: '#1A191B',
// Tab
tabBarDisabledTextColor: '#BDBDBD',
tabDefaultBg: platform === PLATFORM.IOS ? '#F8F8F8' : '#be1522',
topTabBarTextColor: platform === PLATFORM.IOS ? '#6b6b6b' : '#b3c7f9',
topTabBarActiveTextColor: platform === PLATFORM.IOS ? '#be1522' : '#fff',
topTabBarBorderColor: platform === PLATFORM.IOS ? '#a7a6ab' : '#fff',
topTabBarActiveBorderColor: platform === PLATFORM.IOS ? '#be1522' : '#fff',
// Tabs
tabBgColor: '#F8F8F8',
tabIconColor: platform === "ios" ? "#5d5d5d" : "#fff",
tabFontSize: 15,
// Text
textColor: '#000',
textDisabledColor: "#c1c1c1",
inverseTextColor: '#fff',
noteFontSize: 14,
get defaultTextColor() {
return this.textColor;
},
// Title
titleFontfamily: platform === PLATFORM.IOS ? 'System' : 'Roboto_medium',
titleFontSize: platform === PLATFORM.IOS ? 17 : 19,
subTitleFontSize: platform === PLATFORM.IOS ? 11 : 14,
subtitleColor: platform === PLATFORM.IOS ? '#8e8e93' : '#FFF',
titleFontColor: platform === PLATFORM.IOS ? '#000' : '#FFF',
// CUSTOM
customMaterialIconColor: "#5d5d5d",
fetchedDataSectionListErrorText: "#898989",
// Calendar/Agenda
agendaBackgroundColor: '#f3f3f4',
agendaEmptyLine: '#dbdbdc',
// PROXIWASH
proxiwashFinishedColor: "rgba(54,165,22,0.31)",
proxiwashReadyColor: "transparent",
proxiwashRunningColor: "rgba(94,104,241,0.3)",
proxiwashBrokenColor: "rgba(162,162,162,0.31)",
proxiwashErrorColor: "rgba(204,7,0,0.31)",
// Screens
planningColor: '#d9b10a',
proximoColor: '#ec5904',
proxiwashColor: '#1fa5ee',
menuColor: '#e91314',
tutorinsaColor: '#f93943',
// Other
borderRadiusBase: platform === PLATFORM.IOS ? 5 : 2,
borderWidth: 1 / PixelRatio.getPixelSizeForLayoutSize(1),
contentPadding: 10,
dropdownLinkColor: '#414142',
inputLineHeight: 24,
deviceWidth,
deviceHeight,
isIphoneX,
inputGroupRoundedBorderRadius: 30,
// iPhoneX SafeArea
Inset: {
portrait: {
topInset: 24,
leftInset: 0,
rightInset: 0,
bottomInset: 34
},
landscape: {
topInset: 0,
leftInset: 44,
rightInset: 44,
bottomInset: 21
}
}
};

View file

@ -1,362 +0,0 @@
// @flow
import color from 'color';
import { Platform, Dimensions, PixelRatio } from 'react-native';
import { PLATFORM } from './commonColor';
const deviceHeight = Dimensions.get('window').height;
const deviceWidth = Dimensions.get('window').width;
const platform = Platform.OS;
const platformStyle = undefined;
const isIphoneX =
platform === PLATFORM.IOS &&
(deviceHeight === 812 ||
deviceWidth === 812 ||
deviceHeight === 896 ||
deviceWidth === 896);
export default {
platformStyle,
platform,
// Accordion
accordionBorderColor: '#d3d3d3',
accordionContentPadding: 10,
accordionIconFontSize: 18,
contentStyle: '#f5f4f5',
expandedIconStyle: '#000',
headerStyle: '#edebed',
iconStyle: '#000',
// ActionSheet
elevation: 4,
containerTouchableBackgroundColor: 'rgba(0,0,0,0.4)',
innerTouchableBackgroundColor: '#fff',
listItemHeight: 50,
listItemBorderColor: 'transparent',
marginHorizontal: -15,
marginLeft: 14,
marginTop: 15,
minHeight: 56,
padding: 15,
touchableTextColor: '#757575',
// Android
androidRipple: true,
androidRippleColor: 'rgba(256, 256, 256, 0.3)',
androidRippleColorDark: 'rgba(0, 0, 0, 0.15)',
buttonUppercaseAndroidText: true,
// Badge
badgeBg: '#ED1727',
badgeColor: '#fff',
badgePadding: platform === PLATFORM.IOS ? 3 : 0,
// Button
buttonFontFamily: platform === PLATFORM.IOS ? 'System' : 'Roboto_medium',
buttonTextColor: '#fff',
buttonDisabledBg: '#b5b5b5',
buttonPadding: 6,
buttonDefaultActiveOpacity: 0.5,
buttonDefaultFlex: 1,
buttonDefaultBorderRadius: 2,
buttonDefaultBorderWidth: 1,
get buttonPrimaryBg() {
return this.brandPrimary;
},
get buttonPrimaryColor() {
return this.textColor;
},
get buttonInfoBg() {
return this.brandInfo;
},
get buttonInfoColor() {
return this.textColor;
},
get buttonSuccessBg() {
return this.brandSuccess;
},
get buttonSuccessColor() {
return this.textColor;
},
get buttonDangerBg() {
return this.brandDanger;
},
get buttonDangerColor() {
return this.textColor;
},
get buttonWarningBg() {
return this.brandWarning;
},
get buttonWarningColor() {
return this.textColor;
},
get buttonTextSize() {
return platform === PLATFORM.IOS
? this.fontSizeBase * 1.1
: this.fontSizeBase - 1;
},
get buttonTextSizeLarge() {
return this.fontSizeBase * 1.5;
},
get buttonTextSizeSmall() {
return this.fontSizeBase * 0.8;
},
get borderRadiusLarge() {
return this.fontSizeBase * 3.8;
},
get iconSizeLarge() {
return this.iconFontSize * 1.5;
},
get iconSizeSmall() {
return this.iconFontSize * 0.6;
},
// Card
cardDefaultBg: '#2A2A2A',
cardBorderColor: '#1a1a1a',
cardBorderRadius: 2,
cardItemPadding: platform === PLATFORM.IOS ? 10 : 12,
// CheckBox
CheckboxRadius: platform === PLATFORM.IOS ? 13 : 0,
CheckboxBorderWidth: platform === PLATFORM.IOS ? 1 : 2,
CheckboxPaddingLeft: platform === PLATFORM.IOS ? 4 : 2,
CheckboxPaddingBottom: platform === PLATFORM.IOS ? 0 : 5,
CheckboxIconSize: platform === PLATFORM.IOS ? 21 : 16,
CheckboxIconMarginTop: platform === PLATFORM.IOS ? undefined : 1,
CheckboxFontSize: platform === PLATFORM.IOS ? 23 / 0.9 : 17,
checkboxBgColor: '#be1522',
checkboxSize: 20,
checkboxTickColor: '#fff',
checkboxDefaultColor: 'transparent',
checkboxTextShadowRadius: 0,
// Color
brandPrimary: '#be1522',
brandInfo: '#62B1F6',
brandSuccess: '#5cb85c',
brandDanger: '#d9534f',
brandWarning: '#f0ad4e',
brandDark: '#000',
brandLight: '#f4f4f4',
// Container
containerBgColor: '#222222',
sideMenuBgColor: "#1c1c1c",
// Date Picker
datePickerFlex: 1,
datePickerPadding: 10,
datePickerTextColor: '#fff',
datePickerBg: 'transparent',
// FAB
fabBackgroundColor: 'blue',
fabBorderRadius: 28,
fabBottom: 0,
fabButtonBorderRadius: 20,
fabButtonHeight: 40,
fabButtonLeft: 7,
fabButtonMarginBottom: 10,
fabContainerBottom: 20,
fabDefaultPosition: 20,
fabElevation: 4,
fabIconColor: '#fff',
fabIconSize: 24,
fabShadowColor: '#000',
fabShadowOffsetHeight: 2,
fabShadowOffsetWidth: 0,
fabShadowOpacity: 0.4,
fabShadowRadius: 2,
fabWidth: 56,
// Font
DefaultFontSize: 16,
fontFamily: platform === PLATFORM.IOS ? 'System' : 'Roboto',
fontSizeBase: 15,
get fontSizeH1() {
return this.fontSizeBase * 1.8;
},
get fontSizeH2() {
return this.fontSizeBase * 1.6;
},
get fontSizeH3() {
return this.fontSizeBase * 1.4;
},
// Footer
footerHeight: 55,
footerDefaultBg: platform === PLATFORM.IOS ? '#333333' : '#be1522',
footerPaddingBottom: 0,
// FooterTab
tabBarTextColor: platform === PLATFORM.IOS ? '#6b6b6b' : '#b3c7f9',
tabBarTextSize: platform === PLATFORM.IOS ? 14 : 11,
activeTab: platform === PLATFORM.IOS ? '#007aff' : '#fff',
sTabBarActiveTextColor: '#007aff',
tabBarActiveTextColor: platform === PLATFORM.IOS ? '#007aff' : '#fff',
tabActiveBgColor: platform === PLATFORM.IOS ? '#cde1f9' : '#3F51B5',
// Header
toolbarBtnColor: platform === PLATFORM.IOS ? '#be1522' : '#fff',
toolbarDefaultBg: platform === PLATFORM.IOS ? '#333333' : '#be1522',
toolbarHeight: platform === PLATFORM.IOS ? 64 : 56,
toolbarSearchIconSize: platform === PLATFORM.IOS ? 20 : 23,
toolbarInputColor: platform === PLATFORM.IOS ? '#CECDD2' : '#fff',
searchBarHeight: platform === PLATFORM.IOS ? 30 : 40,
searchBarInputHeight: platform === PLATFORM.IOS ? 30 : 50,
toolbarBtnTextColor: platform === PLATFORM.IOS ? '#be1522' : '#fff',
toolbarDefaultBorder: platform === PLATFORM.IOS ? '#3f3f3f' : '#be1522',
iosStatusbar: platform === PLATFORM.IOS ? 'dark-content' : 'light-content',
toolbarTextColor: '#ffffff',
get statusBarColor() {
return color(this.toolbarDefaultBg)
.darken(0.2)
.hex();
},
get darkenHeader() {
return color(this.tabBgColor)
.darken(0.03)
.hex();
},
// Icon
iconFamily: 'Ionicons',
iconFontSize: platform === PLATFORM.IOS ? 30 : 28,
iconHeaderSize: platform === PLATFORM.IOS ? 33 : 24,
// InputGroup
inputFontSize: 17,
inputBorderColor: '#D9D5DC',
inputSuccessBorderColor: '#2b8339',
inputErrorBorderColor: '#ed2f2f',
inputHeightBase: 50,
get inputColor() {
return this.textColor;
},
get inputColorPlaceholder() {
return '#575757';
},
// Line Height
buttonLineHeight: 19,
lineHeightH1: 32,
lineHeightH2: 27,
lineHeightH3: 22,
lineHeight: platform === PLATFORM.IOS ? 20 : 24,
listItemSelected: '#be1522',
// List
listBg: 'transparent',
listBorderColor: '#3e3e3e',
listDividerBg: '#222222',
listBtnUnderlayColor: '#3a3a3a',
listItemPadding: platform === PLATFORM.IOS ? 10 : 12,
listNoteColor: '#acacac',
listNoteSize: 13,
// Progress Bar
defaultProgressColor: '#E4202D',
inverseProgressColor: '#1A191B',
// Radio Button
radioBtnSize: platform === PLATFORM.IOS ? 25 : 23,
radioSelectedColorAndroid: '#be1522',
radioBtnLineHeight: platform === PLATFORM.IOS ? 29 : 24,
get radioColor() {
return this.brandPrimary;
},
// Segment
segmentBackgroundColor: platform === PLATFORM.IOS ? '#F8F8F8' : '#3F51B5',
segmentActiveBackgroundColor: platform === PLATFORM.IOS ? '#007aff' : '#fff',
segmentTextColor: platform === PLATFORM.IOS ? '#007aff' : '#fff',
segmentActiveTextColor: platform === PLATFORM.IOS ? '#fff' : '#3F51B5',
segmentBorderColor: platform === PLATFORM.IOS ? '#007aff' : '#fff',
segmentBorderColorMain: platform === PLATFORM.IOS ? '#a7a6ab' : '#3F51B5',
// Spinner
defaultSpinnerColor: '#be1522',
inverseSpinnerColor: '#1A191B',
// Tab
tabBarDisabledTextColor: '#BDBDBD',
tabDefaultBg: platform === PLATFORM.IOS ? '#333333' : '#be1522',
topTabBarTextColor: platform === PLATFORM.IOS ? '#6b6b6b' : '#b3c7f9',
topTabBarActiveTextColor: platform === PLATFORM.IOS ? '#be1522' : '#fff',
topTabBarBorderColor: platform === PLATFORM.IOS ? '#3f3f3f' : '#fff',
topTabBarActiveBorderColor: platform === PLATFORM.IOS ? '#be1522' : '#fff',
// Tabs
tabBgColor: '#2b2b2b',
tabIconColor: "#fff",
tabFontSize: 15,
// Text
textColor: '#ebebeb',
textDisabledColor: "#5b5b5b",
inverseTextColor: '#000',
noteFontSize: 14,
get defaultTextColor() {
return this.textColor;
},
// Title
titleFontfamily: platform === PLATFORM.IOS ? 'System' : 'Roboto_medium',
titleFontSize: platform === PLATFORM.IOS ? 17 : 19,
subTitleFontSize: platform === PLATFORM.IOS ? 11 : 14,
subtitleColor: platform === PLATFORM.IOS ? '#8e8e93' : '#FFF',
titleFontColor: platform === PLATFORM.IOS ? '#000' : '#FFF',
// CUSTOM
customMaterialIconColor: "#b3b3b3",
fetchedDataSectionListErrorText: "#acacac",
// Calendar/Agenda
agendaBackgroundColor: '#373737',
agendaEmptyLine: '#464646',
// PROXIWASH
proxiwashFinishedColor: "rgba(17,149,32,0.53)",
proxiwashReadyColor: "transparent",
proxiwashRunningColor: "rgba(29,59,175,0.65)",
proxiwashBrokenColor: "#000000",
proxiwashErrorColor: "rgba(213,8,0,0.57)",
// Screens
planningColor: '#d99e09',
proximoColor: '#ec5904',
proxiwashColor: '#1fa5ee',
menuColor: '#b81213',
tutorinsaColor: '#f93943',
// Other
borderRadiusBase: platform === PLATFORM.IOS ? 5 : 2,
borderWidth: 1 / PixelRatio.getPixelSizeForLayoutSize(1),
contentPadding: 10,
dropdownLinkColor: '#414142',
inputLineHeight: 24,
deviceWidth,
deviceHeight,
isIphoneX,
inputGroupRoundedBorderRadius: 30,
// iPhoneX SafeArea
Inset: {
portrait: {
topInset: 24,
leftInset: 0,
rightInset: 0,
bottomInset: 34
},
landscape: {
topInset: 0,
leftInset: 44,
rightInset: 44,
bottomInset: 21
}
}
};

View file

@ -1,14 +0,0 @@
// @flow
import {createAppContainer} from 'react-navigation';
import {createDrawerNavigatorWithInitialRoute} from './DrawerNavigator';
/**
* Create a stack navigator using the drawer to handle navigation between screens
*/
function createAppContainerWithInitialRoute(initialRoute: string) {
return createAppContainer(createDrawerNavigatorWithInitialRoute(initialRoute));
}
export {createAppContainerWithInitialRoute};

View file

@ -1,79 +1,207 @@
// @flow
import { createDrawerNavigator } from 'react-navigation-drawer';
import {createMaterialBottomTabNavigatorWithInitialRoute} from './MainTabNavigator';
import * as React from 'react';
import {createDrawerNavigator} from '@react-navigation/drawer';
import TabNavigator from './MainTabNavigator';
import SettingsScreen from '../screens/SettingsScreen';
import AboutScreen from '../screens/About/AboutScreen';
import AboutDependenciesScreen from '../screens/About/AboutDependenciesScreen';
import SelfMenuScreen from '../screens/SelfMenuScreen';
import TutorInsaScreen from "../screens/Websites/TutorInsaScreen";
import AmicaleScreen from "../screens/Websites/AmicaleScreen";
import WiketudScreen from "../screens/Websites/WiketudScreen";
import ElusEtudScreen from "../screens/Websites/ElusEtudScreen";
import BlueMindScreen from "../screens/Websites/BlueMindScreen";
import EntScreen from "../screens/Websites/EntScreen";
import AvailableRoomScreen from "../screens/Websites/AvailableRoomScreen";
import BibScreen from "../screens/Websites/BibScreen";
import DebugScreen from '../screens/DebugScreen';
import Sidebar from "../components/Sidebar";
import {createStackNavigator, TransitionPresets} from "react-navigation-stack";
import {createStackNavigator, TransitionPresets} from "@react-navigation/stack";
import HeaderButton from "../components/HeaderButton";
import i18n from "i18n-js";
const AboutStack = createStackNavigator({
AboutScreen: {screen: AboutScreen},
AboutDependenciesScreen: {screen: AboutDependenciesScreen},
DebugScreen: {screen: DebugScreen},
},
{
initialRouteName: "AboutScreen",
mode: 'card',
headerMode: "none",
defaultNavigationOptions: {
gestureEnabled: true,
cardOverlayEnabled: true,
...TransitionPresets.SlideFromRightIOS,
},
});
const defaultScreenOptions = {
gestureEnabled: true,
cardOverlayEnabled: true,
...TransitionPresets.SlideFromRightIOS,
};
// Create a stack to use animations
function createDrawerStackWithInitialRoute(initialRoute: string) {
return createStackNavigator({
Main: createMaterialBottomTabNavigatorWithInitialRoute(initialRoute),
SettingsScreen: {screen: SettingsScreen},
AboutScreen: AboutStack,
SelfMenuScreen: {screen: SelfMenuScreen},
TutorInsaScreen: {screen: TutorInsaScreen},
AmicaleScreen: {screen: AmicaleScreen},
WiketudScreen: {screen: WiketudScreen},
ElusEtudScreen: {screen: ElusEtudScreen},
BlueMindScreen: {screen: BlueMindScreen},
EntScreen: {screen: EntScreen},
AvailableRoomScreen: {screen: AvailableRoomScreen},
},
{
initialRouteName: "Main",
mode: 'card',
headerMode: "none",
defaultNavigationOptions: {
gestureEnabled: true,
cardOverlayEnabled: true,
...TransitionPresets.SlideFromRightIOS,
},
});
function getDrawerButton(navigation: Object) {
return (
<HeaderButton icon={'menu'} onPress={navigation.openDrawer}/>
);
}
/**
* Creates the drawer navigation stack
*/
function createDrawerNavigatorWithInitialRoute(initialRoute: string) {
return createDrawerNavigator({
Main: createDrawerStackWithInitialRoute(initialRoute),
}, {
contentComponent: Sidebar,
initialRouteName: 'Main',
backBehavior: 'initialRoute',
drawerType: 'front',
useNativeAnimations: true,
});
const AboutStack = createStackNavigator();
function AboutStackComponent() {
return (
<AboutStack.Navigator
initialRouteName="AboutScreen"
headerMode="float"
screenOptions={defaultScreenOptions}
>
<AboutStack.Screen
name="AboutScreen"
component={AboutScreen}
options={({navigation}) => {
const openDrawer = getDrawerButton.bind(this, navigation);
return {
title: i18n.t('screens.about'),
headerLeft: openDrawer
};
}}
/>
<AboutStack.Screen
name="AboutDependenciesScreen"
component={AboutDependenciesScreen}
options={{
title: i18n.t('aboutScreen.libs')
}}
/>
<AboutStack.Screen
name="DebugScreen"
component={DebugScreen}
options={{
title: i18n.t('aboutScreen.debug')
}}
/>
</AboutStack.Navigator>
);
}
export {createDrawerNavigatorWithInitialRoute};
const SettingsStack = createStackNavigator();
function SettingsStackComponent() {
return (
<SettingsStack.Navigator
initialRouteName="SettingsScreen"
headerMode="float"
screenOptions={defaultScreenOptions}
>
<SettingsStack.Screen
name="SettingsScreen"
component={SettingsScreen}
options={({navigation}) => {
const openDrawer = getDrawerButton.bind(this, navigation);
return {
title: i18n.t('screens.settings'),
headerLeft: openDrawer
};
}}
/>
</SettingsStack.Navigator>
);
}
const SelfMenuStack = createStackNavigator();
function SelfMenuStackComponent() {
return (
<SelfMenuStack.Navigator
initialRouteName="SelfMenuScreen"
headerMode="float"
screenOptions={defaultScreenOptions}
>
<SelfMenuStack.Screen
name="SelfMenuScreen"
component={SelfMenuScreen}
options={({navigation}) => {
const openDrawer = getDrawerButton.bind(this, navigation);
return {
title: i18n.t('screens.menuSelf'),
headerLeft: openDrawer
};
}}
/>
</SelfMenuStack.Navigator>
);
}
const AvailableRoomStack = createStackNavigator();
function AvailableRoomStackComponent() {
return (
<AvailableRoomStack.Navigator
initialRouteName="AvailableRoomScreen"
headerMode="float"
screenOptions={defaultScreenOptions}
>
<AvailableRoomStack.Screen
name="AvailableRoomScreen"
component={AvailableRoomScreen}
options={({navigation}) => {
const openDrawer = getDrawerButton.bind(this, navigation);
return {
title: i18n.t('screens.availableRooms'),
headerLeft: openDrawer
};
}}
/>
</AvailableRoomStack.Navigator>
);
}
const BibStack = createStackNavigator();
function BibStackComponent() {
return (
<BibStack.Navigator
initialRouteName="BibScreen"
headerMode="float"
screenOptions={defaultScreenOptions}
>
<BibStack.Screen
name="BibScreen"
component={BibScreen}
options={({navigation}) => {
const openDrawer = getDrawerButton.bind(this, navigation);
return {
title: i18n.t('screens.bib'),
headerLeft: openDrawer
};
}}
/>
</BibStack.Navigator>
);
}
const Drawer = createDrawerNavigator();
function getDrawerContent(props) {
return <Sidebar {...props}/>
}
export default function DrawerNavigator() {
return (
<Drawer.Navigator
initialRouteName={'Main'}
headerMode={'float'}
backBehavior={'initialRoute'}
drawerType={'front'}
drawerContent={(props) => getDrawerContent(props)}
screenOptions={defaultScreenOptions}
>
<Drawer.Screen
name="Main"
component={TabNavigator}
>
</Drawer.Screen>
<Drawer.Screen
name="SettingsScreen"
component={SettingsStackComponent}
/>
<Drawer.Screen
name="AboutScreen"
component={AboutStackComponent}
/>
<Drawer.Screen
name="SelfMenuScreen"
component={SelfMenuStackComponent}
/>
<Drawer.Screen
name="AvailableRoomScreen"
component={AvailableRoomStackComponent}
/>
<Drawer.Screen
name="BibScreen"
component={BibStackComponent}
/>
</Drawer.Navigator>
);
}

View file

@ -1,6 +1,6 @@
import * as React from 'react';
import {createStackNavigator, TransitionPresets} from 'react-navigation-stack';
import {createMaterialBottomTabNavigator} from "react-navigation-material-bottom-tabs";
import {createStackNavigator, TransitionPresets} from '@react-navigation/stack';
import {createMaterialBottomTabNavigator} from "@react-navigation/material-bottom-tabs";
import HomeScreen from '../screens/HomeScreen';
import PlanningScreen from '../screens/PlanningScreen';
@ -11,117 +11,231 @@ import ProximoMainScreen from '../screens/Proximo/ProximoMainScreen';
import ProximoListScreen from "../screens/Proximo/ProximoListScreen";
import ProximoAboutScreen from "../screens/Proximo/ProximoAboutScreen";
import PlanexScreen from '../screens/Websites/PlanexScreen';
import CustomMaterialIcon from "../components/CustomMaterialIcon";
import ThemeManager from "../utils/ThemeManager";
import {MaterialCommunityIcons} from "@expo/vector-icons";
import AsyncStorageManager from "../utils/AsyncStorageManager";
import HeaderButton from "../components/HeaderButton";
import {withTheme} from 'react-native-paper';
const TAB_ICONS = {
Home: 'triangle',
Planning: 'calendar-range',
Proxiwash: 'washing-machine',
Proximo: 'shopping',
Planex: 'timetable',
Proxiwash: 'tshirt-crew',
Proximo: 'cart',
Planex: 'clock',
};
const ProximoStack = createStackNavigator({
ProximoMainScreen: {screen: ProximoMainScreen},
ProximoListScreen: {screen: ProximoListScreen},
ProximoAboutScreen: {
screen: ProximoAboutScreen,
navigationOptions: () => ({
...TransitionPresets.ModalSlideFromBottomIOS,
}),
},
},
{
initialRouteName: "ProximoMainScreen",
mode: 'card',
headerMode: "none",
defaultNavigationOptions: {
gestureEnabled: true,
cardOverlayEnabled: true,
...TransitionPresets.SlideFromRightIOS,
},
});
const defaultScreenOptions = {
gestureEnabled: true,
cardOverlayEnabled: true,
...TransitionPresets.SlideFromRightIOS,
};
const ProxiwashStack = createStackNavigator({
ProxiwashScreen: {screen: ProxiwashScreen},
ProxiwashAboutScreen: {screen: ProxiwashAboutScreen},
},
{
initialRouteName: "ProxiwashScreen",
mode: 'card',
headerMode: "none",
defaultNavigationOptions: {
gestureEnabled: true,
cardOverlayEnabled: true,
...TransitionPresets.ModalSlideFromBottomIOS,
},
});
const PlanningStack = createStackNavigator({
PlanningScreen: {screen: PlanningScreen},
PlanningDisplayScreen: {screen: PlanningDisplayScreen},
},
{
initialRouteName: "PlanningScreen",
mode: 'card',
headerMode: "none",
defaultNavigationOptions: {
gestureEnabled: true,
cardOverlayEnabled: true,
...TransitionPresets.ModalSlideFromBottomIOS,
},
});
const HomeStack = createStackNavigator({
HomeScreen: {screen: HomeScreen},
PlanningDisplayScreen: {screen: PlanningDisplayScreen},
},
{
initialRouteName: "HomeScreen",
mode: 'card',
headerMode: "none",
defaultNavigationOptions: {
gestureEnabled: true,
cardOverlayEnabled: true,
...TransitionPresets.ModalSlideFromBottomIOS,
},
});
function createMaterialBottomTabNavigatorWithInitialRoute(initialRoute: string) {
return createMaterialBottomTabNavigator({
Home: HomeStack,
Planning: PlanningStack,
Proxiwash: ProxiwashStack,
Proximo: ProximoStack,
Planex: {
screen: PlanexScreen,
navigationOptions: ({navigation}) => {
const showTabBar = navigation.state && navigation.state.params ? navigation.state.params.showTabBar : true;
return {
tabBarVisible: showTabBar,
};
},
},
}, {
defaultNavigationOptions: ({navigation}) => ({
tabBarIcon: ({focused, tintColor}) => {
let icon = TAB_ICONS[navigation.state.routeName];
// tintColor is ignoring activeColor et inactiveColor for some reason
let color = focused ? "#f0edf6" : "#4e1108";
return <CustomMaterialIcon icon={icon} color={color}/>;
},
tabBarVisible: true,
}),
order: ['Proximo', 'Planning', 'Home', 'Proxiwash', 'Planex'],
initialRouteName: initialRoute,
activeColor: '#f0edf6',
inactiveColor: '#4e1108',
backBehavior: 'initialRoute',
barStyle: {backgroundColor: ThemeManager.getCurrentThemeVariables().brandPrimary},
});
function getDrawerButton(navigation: Object) {
return (
<HeaderButton icon={'menu'} onPress={navigation.openDrawer}/>
);
}
const ProximoStack = createStackNavigator();
export {createMaterialBottomTabNavigatorWithInitialRoute};
function ProximoStackComponent() {
return (
<ProximoStack.Navigator
initialRouteName="ProximoMainScreen"
headerMode="float"
screenOptions={defaultScreenOptions}
>
<ProximoStack.Screen
name="ProximoMainScreen"
options={({navigation}) => {
const openDrawer = getDrawerButton.bind(this, navigation);
return {
title: 'Proximo',
headerLeft: openDrawer
};
}}
component={ProximoMainScreen}
/>
<ProximoStack.Screen
name="ProximoListScreen"
options={{
title: 'Articles'
}}
component={ProximoListScreen}
/>
<ProximoStack.Screen
name="ProximoAboutScreen"
component={ProximoAboutScreen}
options={{
title: 'Proximo',
...TransitionPresets.ModalSlideFromBottomIOS,
}}
/>
</ProximoStack.Navigator>
);
}
const ProxiwashStack = createStackNavigator();
function ProxiwashStackComponent() {
return (
<ProxiwashStack.Navigator
initialRouteName="ProxiwashScreen"
headerMode='float'
screenOptions={defaultScreenOptions}
>
<ProxiwashStack.Screen
name="ProxiwashScreen"
component={ProxiwashScreen}
options={({navigation}) => {
const openDrawer = getDrawerButton.bind(this, navigation);
return {
title: 'Proxiwash',
headerLeft: openDrawer
};
}}
/>
<ProxiwashStack.Screen
name="ProxiwashAboutScreen"
component={ProxiwashAboutScreen}
options={{
title: 'Proxiwash',
...TransitionPresets.ModalSlideFromBottomIOS,
}}
/>
</ProxiwashStack.Navigator>
);
}
const PlanningStack = createStackNavigator();
function PlanningStackComponent() {
return (
<PlanningStack.Navigator
initialRouteName="PlanningScreen"
headerMode='float'
screenOptions={defaultScreenOptions}
>
<PlanningStack.Screen
name="PlanningScreen"
component={PlanningScreen}
options={({navigation}) => {
const openDrawer = getDrawerButton.bind(this, navigation);
return {
title: 'Planning',
headerLeft: openDrawer
};
}}
/>
<PlanningStack.Screen
name="PlanningDisplayScreen"
component={PlanningDisplayScreen}
options={{
title: 'Details',
...TransitionPresets.ModalSlideFromBottomIOS,
}}
/>
</PlanningStack.Navigator>
);
}
const HomeStack = createStackNavigator();
function HomeStackComponent() {
return (
<HomeStack.Navigator
initialRouteName="HomeScreen"
headerMode="float"
screenOptions={defaultScreenOptions}
>
<HomeStack.Screen
name="HomeScreen"
component={HomeScreen}
options={({navigation}) => {
const openDrawer = getDrawerButton.bind(this, navigation);
return {
title: 'Home',
headerLeft: openDrawer
};
}}
/>
<HomeStack.Screen
name="PlanningDisplayScreen"
component={PlanningDisplayScreen}
options={{
title: 'Details',
...TransitionPresets.ModalSlideFromBottomIOS,
}}
/>
</HomeStack.Navigator>
);
}
const PlanexStack = createStackNavigator();
function PlanexStackComponent() {
return (
<PlanexStack.Navigator
initialRouteName="HomeScreen"
headerMode="float"
screenOptions={defaultScreenOptions}
>
<PlanexStack.Screen
name="PlanexScreen"
component={PlanexScreen}
options={({navigation}) => {
const openDrawer = getDrawerButton.bind(this, navigation);
return {
title: 'Planex',
headerLeft: openDrawer
};
}}
/>
</PlanexStack.Navigator>
);
}
const Tab = createMaterialBottomTabNavigator();
function TabNavigator(props) {
const {colors} = props.theme;
return (
<Tab.Navigator
initialRouteName={AsyncStorageManager.getInstance().preferences.defaultStartScreen.current}
barStyle={{backgroundColor: colors.surface}}
screenOptions={({route}) => ({
tabBarIcon: ({focused, color, size}) => {
let icon = TAB_ICONS[route.name];
// tintColor is ignoring activeColor and inactiveColor for some reason
icon = focused ? icon : icon + ('-outline');
return <MaterialCommunityIcons name={icon} color={color} size={26}/>;
},
})}
activeColor={colors.primary}
inactiveColor={colors.tabIcon}
>
<Tab.Screen
name="Proximo"
component={ProximoStackComponent}
/>
<Tab.Screen
name="Planning"
component={PlanningStackComponent}
/>
<Tab.Screen
name="Home"
component={HomeStackComponent}
/>
<Tab.Screen
name="Proxiwash"
component={ProxiwashStackComponent}
/>
<Tab.Screen
name="Planex"
component={PlanexStackComponent}
/>
</Tab.Navigator>
);
}
export default withTheme(TabNavigator);

View file

@ -8,15 +8,19 @@
"eject": "expo eject"
},
"dependencies": {
"@expo/vector-icons": "~10.0.0",
"@react-native-community/masked-view": "0.1.5",
"@react-navigation/bottom-tabs": "^5.1.1",
"@react-navigation/drawer": "^5.1.1",
"@react-navigation/material-bottom-tabs": "^5.1.1",
"@react-navigation/native": "^5.0.9",
"@react-navigation/stack": "^5.1.1",
"expo": "^36.0.0",
"expo-font": "~8.0.0",
"expo-linear-gradient": "~8.0.0",
"expo-localization": "~8.0.0",
"expo-permissions": "~8.0.0",
"expo-web-browser": "~8.0.0",
"i18n-js": "^3.3.0",
"native-base": "^2.12.1",
"native-base-shoutem-theme": "^0.3.1",
"react": "16.9.0",
"react-dom": "16.9.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-36.0.1.tar.gz",
@ -24,21 +28,13 @@
"react-native-autolink": "^1.8.1",
"react-native-calendars": "^1.260.0",
"react-native-gesture-handler": "~1.5.0",
"react-native-material-menu": "^1.0.0",
"react-native-modalize": "^1.3.6",
"react-native-paper": "^3.5.1",
"react-native-platform-touchable": "^1.1.1",
"react-native-paper": "^3.6.0",
"react-native-reanimated": "~1.4.0",
"react-native-render-html": "^4.1.2",
"react-native-safe-area-context": "0.6.0",
"react-native-screens": "2.0.0-alpha.12",
"react-native-status-bar-height": "^2.3.1",
"react-native-webview": "7.4.3",
"react-navigation": "^4.1.0",
"react-navigation-drawer": "^2.3.3",
"react-navigation-material-bottom-tabs": "^2.1.5",
"react-navigation-stack": "^2.1.0",
"react-navigation-transitions": "^1.0.12"
"react-native-webview": "7.4.3"
},
"devDependencies": {
"babel-preset-expo": "^8.0.0"

View file

@ -1,10 +1,9 @@
// @flow
import * as React from 'react';
import {Body, Container, ListItem, Text} from 'native-base';
import CustomHeader from "../../components/CustomHeader";
import {FlatList} from "react-native";
import i18n from "i18n-js";
import packageJson from '../../package';
import {List} from 'react-native-paper';
function generateListFromObject(object) {
let list = [];
@ -17,7 +16,8 @@ function generateListFromObject(object) {
}
type Props = {
navigation: Object
navigation: Object,
route: Object
}
/**
@ -26,28 +26,18 @@ type Props = {
export default class AboutDependenciesScreen extends React.Component<Props> {
render() {
const nav = this.props.navigation;
const data = generateListFromObject(nav.getParam('data', {}));
const data = generateListFromObject(packageJson.dependencies);
return (
<Container>
<CustomHeader hasBackButton={true} navigation={nav} title={i18n.t('aboutScreen.libs')}/>
<FlatList
data={data}
keyExtractor={(item) => item.name}
style={{minHeight: 300, width: '100%'}}
renderItem={({item}) =>
<ListItem>
<Body>
<Text>
{item.name}
</Text>
<Text note>
{item.version.replace('^', '')}
</Text>
</Body>
</ListItem>}
/>
</Container>
<FlatList
data={data}
keyExtractor={(item) => item.name}
style={{minHeight: 300, width: '100%'}}
renderItem={({item}) =>
<List.Item
title={item.name}
description={item.version.replace('^', '').replace('~', '')}
/>}
/>
);
}
}

View file

@ -2,15 +2,12 @@
import * as React from 'react';
import {FlatList, Linking, Platform, View} from 'react-native';
import {Body, Button, Card, CardItem, Container, H1, Left, Right, Text, Thumbnail} from 'native-base';
import CustomHeader from "../../components/CustomHeader";
import i18n from "i18n-js";
import appJson from '../../app';
import packageJson from '../../package';
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
import AsyncStorageManager from "../../utils/AsyncStorageManager";
import {Modalize} from "react-native-modalize";
import ThemeManager from "../../utils/ThemeManager";
import {Avatar, Button, Card, List, Text, Title} from 'react-native-paper';
const links = {
appstore: 'https://apps.apple.com/us/app/campus-amicale-insat/id1477722148',
@ -169,7 +166,7 @@ export default class AboutScreen extends React.Component<Props, State> {
showChevron: true
},
{
onPressCallback: () => this.props.navigation.navigate('AboutDependenciesScreen', {data: packageJson.dependencies}),
onPressCallback: () => this.props.navigation.navigate('AboutDependenciesScreen'),
icon: 'developer-board',
text: i18n.t('aboutScreen.libs'),
showChevron: true
@ -199,81 +196,65 @@ export default class AboutScreen extends React.Component<Props, State> {
getAppCard() {
return (
<Card>
<CardItem>
<Left>
<Thumbnail square source={require('../../assets/android.icon.png')}/>
<Body>
<H1>{appJson.expo.name}</H1>
<Text note>
v.{appJson.expo.version}
</Text>
</Body>
</Left>
</CardItem>
<FlatList
data={this.appData}
extraData={this.state}
keyExtractor={(item) => item.icon}
listKey={"app"}
renderItem={this.getCardItem}
/>
<Card style={{marginBottom: 10}}>
<Card.Title
title={appJson.expo.name}
subtitle={appJson.expo.version}
left={(props) => <Avatar.Image {...props} source={require('../../assets/android.icon.png')}/>}/>
<Card.Content>
<FlatList
data={this.appData}
extraData={this.state}
keyExtractor={(item) => item.icon}
listKey={"app"}
renderItem={this.getCardItem}
/>
</Card.Content>
</Card>
);
}
getTeamCard() {
return (
<Card>
<CardItem>
<Left>
<CustomMaterialIcon
icon={'account-multiple'}
fontSize={40}
width={40}
color={ThemeManager.getCurrentThemeVariables().brandPrimary}/>
<Body>
<H1>{i18n.t('aboutScreen.team')}</H1>
</Body>
</Left>
</CardItem>
<CardItem header>
<Text>{i18n.t('aboutScreen.author')}</Text>
</CardItem>
<FlatList
data={this.authorData}
extraData={this.state}
keyExtractor={(item) => item.icon}
listKey={"team1"}
renderItem={this.getCardItem}
/>
<CardItem header>
<Text>{i18n.t('aboutScreen.additionalDev')}</Text>
</CardItem>
<FlatList
data={this.additionalDevData}
extraData={this.state}
keyExtractor={(item) => item.icon}
listKey={"team2"}
renderItem={this.getCardItem}
/>
<Card style={{marginBottom: 10}}>
<Card.Title
title={i18n.t('aboutScreen.team')}
left={(props) => <Avatar.Icon {...props} icon={'account-multiple'}/>}/>
<Card.Content>
<Title>{i18n.t('aboutScreen.author')}</Title>
<FlatList
data={this.authorData}
extraData={this.state}
keyExtractor={(item) => item.icon}
listKey={"team1"}
renderItem={this.getCardItem}
/>
<Title>{i18n.t('aboutScreen.additionalDev')}</Title>
<FlatList
data={this.additionalDevData}
extraData={this.state}
keyExtractor={(item) => item.icon}
listKey={"team2"}
renderItem={this.getCardItem}
/>
</Card.Content>
</Card>
);
}
getTechnoCard() {
return (
<Card>
<CardItem header>
<Text>{i18n.t('aboutScreen.technologies')}</Text>
</CardItem>
<FlatList
data={this.technoData}
extraData={this.state}
keyExtractor={(item) => item.icon}
listKey={"techno"}
renderItem={this.getCardItem}
/>
<Card style={{marginBottom: 10}}>
<Card.Content>
<Title>{i18n.t('aboutScreen.technologies')}</Title>
<FlatList
data={this.technoData}
extraData={this.state}
keyExtractor={(item) => item.icon}
listKey={"techno"}
renderItem={this.getCardItem}
/>
</Card.Content>
</Card>
);
}
@ -286,25 +267,27 @@ export default class AboutScreen extends React.Component<Props, State> {
getCardItem({item}: Object) {
let shouldShow = !item.showOnlyInDebug || (item.showOnlyInDebug && this.state.isDebugUnlocked);
if (shouldShow) {
return (
<CardItem button
onPress={item.onPressCallback}>
<Left>
<CustomMaterialIcon icon={item.icon}/>
<Text>{item.text}</Text>
</Left>
{item.showChevron ?
<Right>
<CustomMaterialIcon icon="chevron-right"
fontSize={20}/>
</Right>
:
<Right/>
}
</CardItem>)
;
if (item.showChevron) {
return (
<List.Item
title={item.text}
left={props => <List.Icon {...props} icon={item.icon}/>}
right={props => <List.Icon {...props} icon={'chevron-right'}/>}
onPress={item.onPressCallback}
/>
);
} else {
return (
<List.Item
title={item.text}
left={props => <List.Icon {...props} icon={item.icon}/>}
onPress={item.onPressCallback}
/>
);
}
} else {
return <View/>
return null;
}
}
@ -328,37 +311,42 @@ export default class AboutScreen extends React.Component<Props, State> {
return (
<Modalize ref={this.modalRef}
adjustToContentHeight
modalStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
handlePosition={'inside'}
modalStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().surface}}
handleStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().text}}
>
<View style={{
flex: 1,
padding: 20
}}>
<H1>{i18n.t('aboutScreen.bugs')}</H1>
<Title>{i18n.t('aboutScreen.bugs')}</Title>
<Text>
{i18n.t('aboutScreen.bugsDescription')}
</Text>
<Button
icon="email"
mode="contained"
dark={true}
color={ThemeManager.getCurrentThemeVariables().primary}
style={{
marginTop: 20,
marginLeft: 'auto',
marginRight: 'auto',
}}
onPress={onPressMail}>
<CustomMaterialIcon
icon={'email'}
color={'#fff'}/>
<Text>{i18n.t('aboutScreen.bugsMail')}</Text>
</Button>
<Button
icon="git"
mode="contained"
dark={true}
color={ThemeManager.getCurrentThemeVariables().primary}
style={{
marginTop: 20,
marginLeft: 'auto',
marginRight: 'auto',
}}
onPress={onPressGit}>
<CustomMaterialIcon
icon={'git'}
color={'#fff'}/>
<Text>{i18n.t('aboutScreen.bugsGit')}</Text>
</Button>
</View>
@ -385,11 +373,9 @@ export default class AboutScreen extends React.Component<Props, State> {
}
render() {
const nav = this.props.navigation;
return (
<Container>
<View style={{padding: 5}}>
{this.getBugReportModal()}
<CustomHeader navigation={nav} title={i18n.t('screens.about')} hasBackButton={true}/>
<FlatList
style={{padding: 5}}
data={this.dataOrder}
@ -397,7 +383,7 @@ export default class AboutScreen extends React.Component<Props, State> {
keyExtractor={(item) => item.id}
renderItem={this.getMainCard}
/>
</Container>
</View>
);
}
}

View file

@ -1,33 +1,12 @@
// @flow
import * as React from 'react';
import {
Body,
Button,
Card,
CardItem,
Container,
Content,
Form,
H1,
H3,
Input,
Item,
Label,
Left,
List,
ListItem,
Right,
Text
} from "native-base";
import CustomHeader from "../components/CustomHeader";
import ThemeManager from '../utils/ThemeManager';
import i18n from "i18n-js";
import CustomMaterialIcon from "../components/CustomMaterialIcon";
import {Alert, Clipboard, View} from "react-native";
import {Alert, Clipboard, ScrollView, View} from "react-native";
import AsyncStorageManager from "../utils/AsyncStorageManager";
import NotificationsManager from "../utils/NotificationsManager";
import {Modalize} from "react-native-modalize";
import {Button, Card, List, Subheading, TextInput, Title} from 'react-native-paper';
type Props = {
navigation: Object,
@ -56,29 +35,24 @@ export default class DebugScreen extends React.Component<Props, State> {
}
static getGeneralItem(onPressCallback: Function, icon: ?string, title: string, subtitle: string) {
return (
<ListItem
button
thumbnail
onPress={onPressCallback}
>
{icon !== undefined ?
<Left>
<CustomMaterialIcon icon={icon}/>
</Left>
: <View/>
}
<Body>
<Text>
{title}
</Text>
<Text note>
{subtitle}
</Text>
</Body>
<Right/>
</ListItem>
);
if (icon !== undefined) {
return (
<List.Item
title={title}
description={subtitle}
left={() => <List.Icon icon={icon}/>}
onPress={onPressCallback}
/>
);
} else {
return (
<List.Item
title={title}
description={subtitle}
onPress={onPressCallback}
/>
);
}
}
alertCurrentExpoToken() {
@ -113,26 +87,30 @@ export default class DebugScreen extends React.Component<Props, State> {
flex: 1,
padding: 20
}}>
<H1>{this.state.modalCurrentDisplayItem.key}</H1>
<H3>Default: {this.state.modalCurrentDisplayItem.default}</H3>
<H3>Current: {this.state.modalCurrentDisplayItem.current}</H3>
<Form>
<Item floatingLabel>
<Label>New Value</Label>
<Input onChangeText={(text) => this.modalInputValue = text}/>
</Item>
</Form>
<Title>{this.state.modalCurrentDisplayItem.key}</Title>
<Subheading>Default: {this.state.modalCurrentDisplayItem.default}</Subheading>
<Subheading>Current: {this.state.modalCurrentDisplayItem.current}</Subheading>
<TextInput
label='New Value'
onChangeText={(text) => this.modalInputValue = text}
/>
<View style={{
flexDirection: 'row',
marginTop: 10,
}}>
<Button success
onPress={() => this.saveNewPrefs(this.state.modalCurrentDisplayItem.key, this.modalInputValue)}>
<Text>Save new value</Text>
<Button
mode="contained"
dark={true}
color={ThemeManager.getCurrentThemeVariables().success}
onPress={() => this.saveNewPrefs(this.state.modalCurrentDisplayItem.key, this.modalInputValue)}>
Save new value
</Button>
<Button
mode="contained"
dark={true}
color={ThemeManager.getCurrentThemeVariables().danger}
onPress={() => this.saveNewPrefs(this.state.modalCurrentDisplayItem.key, this.state.modalCurrentDisplayItem.default)}>
<Text>Reset to default</Text>
Reset to default
</Button>
</View>
@ -150,45 +128,38 @@ export default class DebugScreen extends React.Component<Props, State> {
}
render() {
const nav = this.props.navigation;
return (
<Container>
<View>
<Modalize
ref={this.modalRef}
adjustToContentHeight
modalStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
modalStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().surface}}>
{this.getModalContent()}
</Modalize>
<CustomHeader navigation={nav} title={i18n.t('screens.debug')} hasBackButton={true}/>
<Content padder>
<Card>
<CardItem header>
<Text>
Notifications
</Text>
</CardItem>
<List>
<ScrollView style={{padding: 5}}>
<Card style={{margin: 5}}>
<Card.Title
title={'Notifications'}
/>
<Card.Content>
{DebugScreen.getGeneralItem(() => this.alertCurrentExpoToken(), 'bell', 'Get current Expo Token', '')}
{DebugScreen.getGeneralItem(() => this.forceExpoTokenUpdate(), 'bell-ring', 'Force Expo token update', '')}
</List>
</Card.Content>
</Card>
<Card>
<CardItem header>
<Text>
Preferences
</Text>
</CardItem>
<List>
<Card style={{margin: 5}}>
<Card.Title
title={'Preferences'}
/>
<Card.Content>
{Object.values(this.state.currentPreferences).map((object) =>
<View>
{DebugScreen.getGeneralItem(() => this.showEditModal(object), undefined, object.key, 'Click to edit')}
</View>
)}
</List>
</Card.Content>
</Card>
</Content>
</Container>
</ScrollView>
</View>
);
}
}

View file

@ -1,18 +1,19 @@
// @flow
import * as React from 'react';
import {Image, Linking, TouchableOpacity, View} from 'react-native';
import {Body, Button, Card, CardItem, H1, Left, Text, Thumbnail} from 'native-base';
import {TouchableOpacity, View} from 'react-native';
import i18n from "i18n-js";
import CustomMaterialIcon from '../components/CustomMaterialIcon';
import FetchedDataSectionList from "../components/FetchedDataSectionList";
import Autolink from 'react-native-autolink';
import ThemeManager from "../utils/ThemeManager";
import DashboardItem from "../components/DashboardItem";
import * as WebBrowser from 'expo-web-browser';
import WebSectionList from "../components/WebSectionList";
import {Avatar, Button, Card, Text} from 'react-native-paper';
import FeedItem from "../components/FeedItem";
import SquareDashboardItem from "../components/SquareDashboardItem";
// import DATA from "../dashboard_data.json";
const ICON_AMICALE = require('../assets/amicale.png');
const NAME_AMICALE = 'Amicale INSA Toulouse';
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/dashboard/dashboard_data.json";
@ -25,46 +26,30 @@ const REFRESH_TIME = 1000 * 20; // Refresh every 20 seconds
const CARD_BORDER_RADIUS = 10;
/**
* Opens a link in the device's browser
* @param link The link to open
*/
function openWebLink(link) {
Linking.openURL(link).catch((err) => console.error('Error opening link', err));
type Props = {
navigation: Object,
}
/**
* Class defining the app's home screen
*/
export default class HomeScreen extends FetchedDataSectionList {
export default class HomeScreen extends React.Component<Props> {
onProxiwashClick: Function;
onTutorInsaClick: Function;
onMenuClick: Function;
onProximoClick: Function;
getRenderItem: Function;
createDataset: Function;
constructor() {
super(DATA_URL, REFRESH_TIME);
super();
this.onProxiwashClick = this.onProxiwashClick.bind(this);
this.onTutorInsaClick = this.onTutorInsaClick.bind(this);
this.onMenuClick = this.onMenuClick.bind(this);
this.onProximoClick = this.onProximoClick.bind(this);
}
onProxiwashClick() {
this.props.navigation.navigate('Proxiwash');
}
onTutorInsaClick() {
this.props.navigation.navigate('TutorInsaScreen');
}
onProximoClick() {
this.props.navigation.navigate('Proximo');
}
onMenuClick() {
this.props.navigation.navigate('SelfMenuScreen');
this.getRenderItem = this.getRenderItem.bind(this);
this.createDataset = this.createDataset.bind(this);
}
/**
@ -77,12 +62,20 @@ export default class HomeScreen extends FetchedDataSectionList {
return date.toLocaleString();
}
getHeaderTranslation() {
return i18n.t("screens.home");
onProxiwashClick() {
this.props.navigation.navigate('Proxiwash');
}
getUpdateToastTranslations() {
return [i18n.t("homeScreen.listUpdated"), i18n.t("homeScreen.listUpdateFail")];
onTutorInsaClick() {
WebBrowser.openBrowserAsync("https://www.etud.insa-toulouse.fr/~tutorinsa/");
}
onProximoClick() {
this.props.navigation.navigate('Proximo');
}
onMenuClick() {
this.props.navigation.navigate('SelfMenuScreen');
}
getKeyExtractor(item: Object) {
@ -154,25 +147,6 @@ export default class HomeScreen extends FetchedDataSectionList {
return dataset
}
getRenderSectionHeader(title: string) {
if (title === '') {
return <View/>;
} else {
return (
<View style={{
backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor
}}>
<H1 style={{
marginLeft: 'auto',
marginRight: 'auto',
marginTop: 10,
marginBottom: 10
}}>{title}</H1>
</View>
);
}
}
getDashboardItem(item: Object) {
let content = item['content'];
if (item['id'] === 'event')
@ -318,7 +292,7 @@ export default class HomeScreen extends FetchedDataSectionList {
if (isAvailable)
this.props.navigation.navigate('PlanningDisplayScreen', {data: displayEvent});
else
this.props.navigation.navigate('PlanningScreen');
this.props.navigation.navigate('Planning');
};
@ -345,13 +319,13 @@ export default class HomeScreen extends FetchedDataSectionList {
subtitle = i18n.t('homeScreen.dashboard.todayEventsSubtitleNA');
let displayEvent = this.getDisplayEvent(futureEvents);
const clickAction = this.clickAction.bind(this, isAvailable, displayEvent);
return (
<DashboardItem
subtitle={subtitle}
color={color}
icon={icon}
clickAction={this.clickAction.bind(this, isAvailable, displayEvent)}
clickAction={clickAction}
title={title}
isAvailable={isAvailable}
displayEvent={displayEvent}
@ -398,24 +372,24 @@ export default class HomeScreen extends FetchedDataSectionList {
flexDirection: 'row',
marginLeft: 10,
marginRight: 10,
marginBottom: 10,
}}>
<DashboardItem
isSquare={true}
<SquareDashboardItem
title={menuTitle}
subtitle={menuSubtitle}
color={menuColor}
icon={menuIcon}
clickAction={this.onMenuClick}
title={menuTitle}
isAvailable={isMenuAvailable}
isSquareLeft={true}/>
<DashboardItem
isSquare={true}
isLeft={true}/>
<SquareDashboardItem
title={proximoTitle}
subtitle={proximoSubtitle}
color={proximoColor}
icon={proximoIcon}
clickAction={this.onProximoClick}
title={proximoTitle}
isAvailable={isProximoAvailable}/>
isAvailable={isProximoAvailable}
isLeft={false}/>
</View>
);
}
@ -431,11 +405,11 @@ export default class HomeScreen extends FetchedDataSectionList {
let proxiwashIsAvailable = parseInt(proxiwashData['dryers']) > 0 || parseInt(proxiwashData['washers']) > 0;
let proxiwashSubtitle;
let dryerColor = parseInt(proxiwashData['dryers']) > 0 ?
ThemeManager.getCurrentThemeVariables().textColor :
ThemeManager.getCurrentThemeVariables().listNoteColor;
ThemeManager.getCurrentThemeVariables().text :
ThemeManager.getCurrentThemeVariables().textDisabled;
let washerColor = parseInt(proxiwashData['washers']) > 0 ?
ThemeManager.getCurrentThemeVariables().textColor :
ThemeManager.getCurrentThemeVariables().listNoteColor;
ThemeManager.getCurrentThemeVariables().text :
ThemeManager.getCurrentThemeVariables().textDisabled;
let availableDryers = proxiwashData['dryers'];
let availableWashers = proxiwashData['washers'];
if (proxiwashIsAvailable) {
@ -502,85 +476,59 @@ export default class HomeScreen extends FetchedDataSectionList {
marginLeft: 10,
marginRight: 10,
}}>
<DashboardItem
isSquare={true}
<SquareDashboardItem
title={proxiwashTitle}
subtitle={proxiwashSubtitle}
color={proxiwashColor}
icon={proxiwashIcon}
clickAction={this.onProxiwashClick}
title={proxiwashTitle}
isAvailable={proxiwashIsAvailable}
isSquareLeft={true}/>
<DashboardItem
isSquare={true}
isLeft={true}/>
<SquareDashboardItem
title={tutorinsaTitle}
subtitle={tutorinsaSubtitle}
color={tutorinsaColor}
icon={tutorinsaIcon}
clickAction={this.onTutorInsaClick}
title={tutorinsaTitle}
isAvailable={tutorinsaIsAvailable}/>
isAvailable={tutorinsaIsAvailable}
isLeft={false}/>
</View>
);
}
openLink(link: string) {
WebBrowser.openBrowserAsync(link);
}
getRenderItem(item: Object, section: Object) {
getFeedItem(item: Object) {
const onImagePress = this.openLink.bind(this, item.full_picture);
const onOutLinkPress = this.openLink.bind(this, item.permalink_url);
return (
section['id'] === SECTIONS_ID[0] ? this.getDashboardItem(item) :
<Card style={{
flex: 0,
marginLeft: 10,
marginRight: 10,
borderRadius: CARD_BORDER_RADIUS,
}}>
<CardItem style={{
backgroundColor: 'transparent'
}}>
<Left>
<Thumbnail source={ICON_AMICALE} square/>
<Body>
<Text>{NAME_AMICALE}</Text>
<Text note>{HomeScreen.getFormattedDate(item.created_time)}</Text>
</Body>
</Left>
</CardItem>
<CardItem style={{
backgroundColor: 'transparent'
}}>
<Body>
{item.full_picture !== '' && item.full_picture !== undefined ?
<TouchableOpacity onPress={openWebLink.bind(null, item.full_picture)}
style={{width: '100%', height: 250, marginBottom: 5}}>
<Image source={{uri: item.full_picture}}
style={{flex: 1, resizeMode: "contain"}}
resizeMode="contain"
/>
</TouchableOpacity>
: <View/>}
{item.message !== undefined ?
<Autolink
text={item.message}
hashtag="facebook"
style={{color: ThemeManager.getCurrentThemeVariables().textColor}}
/> : <View/>
}
</Body>
</CardItem>
<CardItem style={{
backgroundColor: 'transparent'
}}>
<Left>
<Button transparent
onPress={openWebLink.bind(null, item.permalink_url)}>
<CustomMaterialIcon
icon="facebook"
color="#57aeff"
width={20}/>
<Text>En savoir plus</Text>
</Button>
</Left>
</CardItem>
</Card>
<FeedItem
title={NAME_AMICALE}
subtitle={HomeScreen.getFormattedDate(item.created_time)}
full_picture={item.full_picture}
message={item.message}
onImagePress={onImagePress}
onOutLinkPress={onOutLinkPress}
/>
);
}
getRenderItem({item, section}: Object) {
return (section['id'] === SECTIONS_ID[0] ?
this.getDashboardItem(item) : this.getFeedItem(item));
}
render() {
const nav = this.props.navigation;
return (
<WebSectionList
createDataset={this.createDataset}
navigation={nav}
refreshTime={REFRESH_TIME}
fetchUrl={DATA_URL}
renderItem={this.getRenderItem}/>
);
}
}

View file

@ -1,16 +1,16 @@
// @flow
import * as React from 'react';
import {Image} from 'react-native';
import {Container, Content, H1, H3, View} from 'native-base';
import CustomHeader from "../components/CustomHeader";
import {Image, ScrollView, View} from 'react-native';
import ThemeManager from "../utils/ThemeManager";
import HTML from "react-native-render-html";
import {Linking} from "expo";
import PlanningEventManager from '../utils/PlanningEventManager';
import {Card} from 'react-native-paper';
type Props = {
navigation: Object,
route: Object
};
function openWebLink(event, link) {
@ -21,48 +21,36 @@ function openWebLink(event, link) {
* Class defining an about screen. This screen shows the user information about the app and it's author.
*/
export default class PlanningDisplayScreen extends React.Component<Props> {
displayData = this.props.route.params['data'];
render() {
// console.log("rendering planningDisplayScreen");
const nav = this.props.navigation;
const displayData = nav.getParam('data', []);
return (
<Container>
<CustomHeader
navigation={nav}
title={displayData.title}
subtitle={PlanningEventManager.getFormattedTime(displayData)}
hasBackButton={true}/>
<Content padder>
<H1>
{displayData.title}
</H1>
<H3 style={{
marginTop: 10,
color: ThemeManager.getCurrentThemeVariables().listNoteColor
}}>
{PlanningEventManager.getFormattedTime(displayData)}
</H3>
{displayData.logo !== null ?
<View style={{width: '100%', height: 300, marginTop: 20, marginBottom: 20}}>
<Image style={{flex: 1, resizeMode: "contain"}}
source={{uri: displayData.logo}}/>
</View>
: <View/>}
<ScrollView style={{paddingLeft: 5, paddingRight: 5}}>
<Card.Title
title={this.displayData.title}
subtitle={PlanningEventManager.getFormattedTime(this.displayData) + ' | ' + PlanningEventManager.getEventStartDate(this.displayData)}
/>
{this.displayData.logo !== null ?
<View style={{width: '100%', height: 300}}>
<Image style={{flex: 1, resizeMode: "contain"}}
source={{uri: this.displayData.logo}}/>
</View>
: <View/>}
{displayData.description !== null ?
// Surround description with div to allow text styling if the description is not html
<HTML html={"<div>" + displayData.description + "</div>"}
{this.displayData.description !== null ?
// Surround description with div to allow text styling if the description is not html
<Card.Content>
<HTML html={"<div>" + this.displayData.description + "</div>"}
tagsStyles={{
p: {
color: ThemeManager.getCurrentThemeVariables().textColor,
fontSize: ThemeManager.getCurrentThemeVariables().fontSizeBase
},
div: {color: ThemeManager.getCurrentThemeVariables().textColor}
p: {color: ThemeManager.getCurrentThemeVariables().text,},
div: {color: ThemeManager.getCurrentThemeVariables().text}
}}
onLinkPress={openWebLink}/>
: <View/>}
</Content>
</Container>
</Card.Content>
: <View/>}
</ScrollView>
);
}
}

View file

@ -1,15 +1,13 @@
// @flow
import * as React from 'react';
import {BackHandler, Image} from 'react-native';
import {H3, Text, View} from 'native-base';
import {BackHandler, View} from 'react-native';
import i18n from "i18n-js";
import ThemeManager from "../utils/ThemeManager";
import BaseContainer from "../components/BaseContainer";
import {Agenda, LocaleConfig} from 'react-native-calendars';
import Touchable from 'react-native-platform-touchable';
import {LocaleConfig} from 'react-native-calendars';
import WebDataManager from "../utils/WebDataManager";
import PlanningEventManager from '../utils/PlanningEventManager';
import {Avatar, Divider, List} from 'react-native-paper';
import CustomAgenda from "../components/CustomAgenda";
LocaleConfig.locales['fr'] = {
monthNames: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
@ -32,7 +30,7 @@ type State = {
const FETCH_URL = "https://amicale-insat.fr/event/json/list";
const AGENDA_MONTH_SPAN = 6;
const AGENDA_MONTH_SPAN = 3;
/**
* Class defining the app's planning screen
@ -61,18 +59,11 @@ export default class PlanningScreen extends React.Component<Props, State> {
onAgendaRef: Function;
onCalendarToggled: Function;
onBackButtonPressAndroid: Function;
currentDate = this.getCurrentDate();
constructor(props: any) {
super(props);
this.webDataManager = new WebDataManager(FETCH_URL);
this.didFocusSubscription = props.navigation.addListener(
'didFocus',
() =>
BackHandler.addEventListener(
'hardwareBackPress',
this.onBackButtonPressAndroid
)
);
if (i18n.currentLocale().startsWith("fr")) {
LocaleConfig.defaultLocale = 'fr';
}
@ -87,16 +78,18 @@ export default class PlanningScreen extends React.Component<Props, State> {
this.onBackButtonPressAndroid = this.onBackButtonPressAndroid.bind(this);
}
shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
return nextState.refreshing === false && this.state.refreshing === true ||
nextState.agendaItems !== this.state.agendaItems ||
nextState.calendarShowing !== this.state.calendarShowing;
}
componentDidMount() {
this.onRefresh();
this.didFocusSubscription = this.props.navigation.addListener(
'focus',
() =>
BackHandler.addEventListener(
'hardwareBackPress',
this.onBackButtonPressAndroid
)
);
this.willBlurSubscription = this.props.navigation.addListener(
'willBlur',
'blur',
() =>
BackHandler.removeEventListener(
'hardwareBackPress',
@ -114,11 +107,6 @@ export default class PlanningScreen extends React.Component<Props, State> {
}
};
componentWillUnmount() {
this.didFocusSubscription && this.didFocusSubscription.remove();
this.willBlurSubscription && this.willBlurSubscription.remove();
}
getCurrentDate() {
let today = new Date();
return this.getFormattedDate(today);
@ -141,70 +129,47 @@ export default class PlanningScreen extends React.Component<Props, State> {
}
getRenderItem(item: Object) {
return (
<Touchable
style={{
backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor,
borderRadius: 10,
marginRight: 10,
marginTop: 17,
}}
onPress={() => this.props.navigation.navigate('PlanningDisplayScreen', {data: item})}>
<View style={{
padding: 10,
flex: 1,
flexDirection: 'row'
}}>
<View style={{
width: item.logo !== null ? '70%' : '100%',
}}>
<Text style={{
color: ThemeManager.getCurrentThemeVariables().listNoteColor,
marginTop: 5,
marginBottom: 10
}}>
{PlanningEventManager.getFormattedTime(item)}
</Text>
<H3 style={{marginBottom: 10}}>{item.title}</H3>
</View>
<View style={{
width: item.logo !== null ? '30%' : 0,
height: 80
}}>
{item.logo !== null ?
<Image source={{uri: item.logo}}
style={{
flex: 1,
resizeMode: "contain"
}}/>
: <View/>}
</View>
const onPress = this.props.navigation.navigate.bind(this, 'PlanningDisplayScreen', {data: item});
if (item.logo !== null) {
return (
<View>
<Divider/>
<List.Item
title={item.title}
description={PlanningEventManager.getFormattedTime(item)}
left={props => <Avatar.Image
source={{uri: item.logo}}
style={{backgroundColor: 'transparent'}}
/>}
onPress={onPress}
/>
</View>
</Touchable>
);
);
} else {
return (
<View>
<Divider/>
<List.Item
title={item.title}
description={PlanningEventManager.getFormattedTime(item)}
onPress={onPress}
/>
</View>
);
}
}
getRenderEmptyDate() {
return (
<View style={{
padding: 10,
flex: 1,
}}>
<View style={{
width: '100%',
height: 1,
backgroundColor: ThemeManager.getCurrentThemeVariables().agendaEmptyLine,
marginTop: 'auto',
marginBottom: 'auto',
}}/>
</View>
<Divider/>
);
}
rowHasChanged(r1: Object, r2: Object) {
if (r1 !== undefined && r2 !== undefined)
return r1.title !== r2.title;
else return !(r1 === undefined && r2 === undefined);
return false;
// if (r1 !== undefined && r2 !== undefined)
// return r1.title !== r2.title;
// else return !(r1 === undefined && r2 === undefined);
}
/**
@ -271,66 +236,36 @@ export default class PlanningScreen extends React.Component<Props, State> {
this.setState({calendarShowing: isCalendarOpened});
}
currentDate = this.getCurrentDate();
render() {
// console.log("rendering PlanningScreen");
return (
<BaseContainer navigation={this.props.navigation} headerTitle={i18n.t('screens.planning')}>
<Agenda
// the list of items that have to be displayed in agenda. If you want to render item as empty date
// the value of date key kas to be an empty array []. If there exists no value for date key it is
// considered that the date in question is not yet loaded
items={this.state.agendaItems}
// initially selected day
selected={this.currentDate}
// Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
minDate={this.currentDate}
// Max amount of months allowed to scroll to the past. Default = 50
pastScrollRange={1}
// Max amount of months allowed to scroll to the future. Default = 50
futureScrollRange={AGENDA_MONTH_SPAN}
// If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make sure to also set the refreshing prop correctly.
onRefresh={this.onRefresh}
// callback that fires when the calendar is opened or closed
onCalendarToggled={this.onCalendarToggled}
// Set this true while waiting for new data from a refresh
refreshing={this.state.refreshing}
renderItem={this.getRenderItem}
renderEmptyDate={this.getRenderEmptyDate}
rowHasChanged={this.rowHasChanged}
// If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
firstDay={1}
// ref to this agenda in order to handle back button event
ref={this.onAgendaRef}
// agenda theme
theme={{
backgroundColor: ThemeManager.getCurrentThemeVariables().agendaBackgroundColor,
calendarBackground: ThemeManager.getCurrentThemeVariables().containerBgColor,
textSectionTitleColor: ThemeManager.getCurrentThemeVariables().listNoteColor,
selectedDayBackgroundColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
selectedDayTextColor: '#ffffff',
todayTextColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
dayTextColor: ThemeManager.getCurrentThemeVariables().textColor,
textDisabledColor: ThemeManager.getCurrentThemeVariables().textDisabledColor,
dotColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
selectedDotColor: '#ffffff',
arrowColor: 'orange',
monthTextColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
indicatorColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
textDayFontWeight: '300',
textMonthFontWeight: 'bold',
textDayHeaderFontWeight: '300',
textDayFontSize: 16,
textMonthFontSize: 16,
textDayHeaderFontSize: 16,
agendaDayTextColor: ThemeManager.getCurrentThemeVariables().listNoteColor,
agendaDayNumColor: ThemeManager.getCurrentThemeVariables().listNoteColor,
agendaTodayColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
agendaKnobColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
}}
/>
</BaseContainer>
<CustomAgenda
// the list of items that have to be displayed in agenda. If you want to render item as empty date
// the value of date key kas to be an empty array []. If there exists no value for date key it is
// considered that the date in question is not yet loaded
items={this.state.agendaItems}
// initially selected day
selected={this.currentDate}
// Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
minDate={this.currentDate}
// Max amount of months allowed to scroll to the past. Default = 50
pastScrollRange={1}
// Max amount of months allowed to scroll to the future. Default = 50
futureScrollRange={AGENDA_MONTH_SPAN}
// If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make sure to also set the refreshing prop correctly.
onRefresh={this.onRefresh}
// callback that fires when the calendar is opened or closed
onCalendarToggled={this.onCalendarToggled}
// Set this true while waiting for new data from a refresh
refreshing={this.state.refreshing}
renderItem={this.getRenderItem}
renderEmptyDate={this.getRenderEmptyDate}
rowHasChanged={this.rowHasChanged}
// If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
firstDay={1}
// ref to this agenda in order to handle back button event
onRef={this.onAgendaRef}
/>
);
}
}

View file

@ -1,11 +1,9 @@
// @flow
import * as React from 'react';
import {Image, View} from 'react-native';
import {Card, CardItem, Container, Content, H2, Left, Text} from 'native-base';
import CustomHeader from "../../components/CustomHeader";
import {Image, ScrollView, View} from 'react-native';
import i18n from "i18n-js";
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
import {Text, Card, List, Paragraph} from 'react-native-paper';
type Props = {
navigation: Object,
@ -17,49 +15,41 @@ type Props = {
export default class ProximoAboutScreen extends React.Component<Props> {
render() {
const nav = this.props.navigation;
return (
<Container>
<CustomHeader navigation={nav} title={i18n.t('screens.proximo')} hasBackButton={true}/>
<Content padder>
<View style={{
width: '100%',
height: 100,
marginTop: 20,
marginBottom: 20,
justifyContent: 'center',
alignItems: 'center'
}}>
<Image
source={require('../../assets/proximo-logo.png')}
style={{flex: 1, resizeMode: "contain"}}
resizeMode="contain"/>
</View>
<Text>{i18n.t('proximoScreen.description')}</Text>
<Card>
<CardItem>
<Left>
<CustomMaterialIcon icon={'clock-outline'}/>
<H2>{i18n.t('proximoScreen.openingHours')}</H2>
</Left>
</CardItem>
<CardItem>
<Text>18h30 - 19h30</Text>
</CardItem>
</Card>
<Card>
<CardItem>
<Left>
<CustomMaterialIcon icon={'cash'}/>
<H2>{i18n.t('proximoScreen.paymentMethods')}</H2>
</Left>
</CardItem>
<CardItem>
<Text>{i18n.t('proximoScreen.paymentMethodsDescription')}</Text>
</CardItem>
</Card>
</Content>
</Container>
<ScrollView style={{padding: 5}}>
<View style={{
width: '100%',
height: 100,
marginTop: 20,
marginBottom: 20,
justifyContent: 'center',
alignItems: 'center'
}}>
<Image
source={require('../../assets/proximo-logo.png')}
style={{flex: 1, resizeMode: "contain"}}
resizeMode="contain"/>
</View>
<Text>{i18n.t('proximoScreen.description')}</Text>
<Card style={{margin: 5}}>
<Card.Title
title={i18n.t('proximoScreen.openingHours')}
left={props => <List.Icon {...props} icon={'clock-outline'}/>}
/>
<Card.Content>
<Paragraph>18h30 - 19h30</Paragraph>
</Card.Content>
</Card>
<Card style={{margin: 5}}>
<Card.Title
title={i18n.t('proximoScreen.paymentMethods')}
left={props => <List.Icon {...props} icon={'cash'}/>}
/>
<Card.Content>
<Paragraph>18{i18n.t('proximoScreen.paymentMethodsDescription')}</Paragraph>
</Card.Content>
</Card>
</ScrollView>
);
}
}

View file

@ -1,20 +1,11 @@
// @flow
import * as React from 'react';
import {Body, Container, Content, H1, H3, Left, ListItem, Right, Text, Thumbnail} from 'native-base';
import CustomHeader from "../../components/CustomHeader";
import {FlatList, Image, Platform, View} from "react-native";
import Touchable from 'react-native-platform-touchable';
import Menu, {MenuItem} from 'react-native-material-menu';
import {FlatList, Image, ScrollView, View} from "react-native";
import i18n from "i18n-js";
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
import ThemeManager from "../../utils/ThemeManager";
import {Modalize} from 'react-native-modalize';
const sortMode = {
price: "0",
name: '1',
};
import {Avatar, IconButton, List, RadioButton, Searchbar, Subheading, Text, Title} from "react-native-paper";
function sortPrice(a, b) {
return a.price - b.price;
@ -25,31 +16,29 @@ function sortPriceReverse(a, b) {
}
function sortName(a, b) {
if (a.name < b.name)
if (a.name.toLowerCase() < b.name.toLowerCase())
return -1;
if (a.name > b.name)
if (a.name.toLowerCase() > b.name.toLowerCase())
return 1;
return 0;
}
function sortNameReverse(a, b) {
if (a.name < b.name)
if (a.name.toLowerCase() < b.name.toLowerCase())
return 1;
if (a.name > b.name)
if (a.name.toLowerCase() > b.name.toLowerCase())
return -1;
return 0;
}
type Props = {
navigation: Object
navigation: Object,
route: Object,
}
type State = {
currentSortMode: string,
isSortReversed: boolean,
sortPriceIcon: React.Node,
sortNameIcon: React.Node,
modalCurrentDisplayItem: Object,
currentSortMode: number,
modalCurrentDisplayItem: React.Node,
currentlyDisplayedData: Array<Object>,
};
@ -60,99 +49,77 @@ export default class ProximoListScreen extends React.Component<Props, State> {
modalRef: { current: null | Modalize };
originalData: Array<Object>;
navData = this.props.navigation.getParam('data', []);
shouldFocusSearchBar = this.props.navigation.getParam('shouldFocusSearchBar', false);
state = {
currentlyDisplayedData: this.navData['data'].sort(sortPrice),
currentSortMode: sortMode.price,
isSortReversed: false,
sortPriceIcon: '',
sortNameIcon: '',
modalCurrentDisplayItem: {},
};
sortMenuRef: Menu;
shouldFocusSearchBar: boolean;
onMenuRef: Function;
onSearchStringChange: Function;
onSelectSortModeName: Function;
onSelectSortModePrice: Function;
onSortMenuPress: Function;
renderItem: Function;
constructor(props: any) {
super(props);
this.modalRef = React.createRef();
this.originalData = this.navData['data'];
this.originalData = this.props.route.params['data']['data'];
this.shouldFocusSearchBar = this.props.route.params['shouldFocusSearchBar'];
this.state = {
currentlyDisplayedData: this.originalData,
currentSortMode: 1,
modalCurrentDisplayItem: <View/>,
};
this.onMenuRef = this.onMenuRef.bind(this);
this.onSearchStringChange = this.onSearchStringChange.bind(this);
this.onSelectSortModeName = this.onSelectSortModeName.bind(this);
this.onSelectSortModePrice = this.onSelectSortModePrice.bind(this);
this.onSortMenuPress = this.onSortMenuPress.bind(this);
this.renderItem = this.renderItem.bind(this);
}
/**
* Saves the reference to the sort menu for later use
*
* @param ref The menu reference
*/
onMenuRef(ref: Menu) {
this.sortMenuRef = ref;
};
/**
* Sets the sort mode based on the one selected.
* If the selected mode is the current one, reverse it.
*
* @param mode The string representing the mode
*/
sortModeSelected(mode: string) {
let isReverse = this.state.isSortReversed;
if (mode === this.state.currentSortMode) // reverse mode
isReverse = !isReverse; // this.state not updating on this function cycle
else
isReverse = false;
this.setSortMode(mode, isReverse);
}
/**
* Set the current sort mode.
*
* @param mode The string representing the mode
* @param isReverse Whether to use a reverse sort
* @param mode The number representing the mode
*/
setSortMode(mode: string, isReverse: boolean) {
setSortMode(mode: number) {
this.setState({
currentSortMode: mode,
isSortReversed: isReverse
});
let data = this.state.currentlyDisplayedData;
switch (mode) {
case sortMode.price:
if (isReverse) {
data.sort(sortPriceReverse);
} else {
data.sort(sortPrice);
}
case 1:
data.sort(sortPrice);
break;
case sortMode.name:
if (isReverse) {
data.sort(sortNameReverse);
} else {
data.sort(sortName);
}
case 2:
data.sort(sortPriceReverse);
break;
case 3:
data.sort(sortName);
break;
case 4:
data.sort(sortNameReverse);
break;
}
this.setupSortIcons(mode, isReverse);
this.sortMenuRef.hide();
if (this.modalRef.current && mode !== this.state.currentSortMode) {
this.modalRef.current.close();
}
}
/**
* Set the sort mode from state when components are ready
*/
componentDidMount() {
this.setSortMode(this.state.currentSortMode, this.state.isSortReversed);
const button = this.getSortMenu.bind(this);
const title = this.getSearchBar.bind(this);
this.props.navigation.setOptions({
headerRight: button,
headerTitle: title,
});
this.setSortMode(1);
}
getSearchBar() {
return (
<Searchbar
placeholder={i18n.t('proximoScreen.search')}
onChangeText={this.onSearchStringChange}
/>
);
}
/**
@ -164,48 +131,14 @@ export default class ProximoListScreen extends React.Component<Props, State> {
getStockColor(availableStock: number) {
let color: string;
if (availableStock > 3)
color = ThemeManager.getCurrentThemeVariables().brandSuccess;
color = ThemeManager.getCurrentThemeVariables().success;
else if (availableStock > 0)
color = ThemeManager.getCurrentThemeVariables().brandWarning;
color = ThemeManager.getCurrentThemeVariables().warning;
else
color = ThemeManager.getCurrentThemeVariables().brandDanger;
color = ThemeManager.getCurrentThemeVariables().danger;
return color;
}
/**
* Set the sort menu icon based on the given mode.
*
* @param mode The string representing the mode
* @param isReverse Whether to use a reversed icon
*/
setupSortIcons(mode: string, isReverse: boolean) {
const downSortIcon =
<CustomMaterialIcon
icon={'sort-descending'}/>;
const upSortIcon =
<CustomMaterialIcon
icon={'sort-ascending'}/>;
switch (mode) {
case sortMode.price:
this.setState({sortNameIcon: ''});
if (isReverse) {
this.setState({sortPriceIcon: upSortIcon});
} else {
this.setState({sortPriceIcon: downSortIcon});
}
break;
case sortMode.name:
this.setState({sortPriceIcon: ''});
if (isReverse) {
this.setState({sortNameIcon: upSortIcon});
} else {
this.setState({sortNameIcon: downSortIcon});
}
break;
}
}
sanitizeString(str: string) {
return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
}
@ -234,113 +167,130 @@ export default class ProximoListScreen extends React.Component<Props, State> {
})
}
getModalContent() {
getModalItemContent(item: Object) {
return (
<View style={{
flex: 1,
padding: 20
}}>
<H1>{this.state.modalCurrentDisplayItem.name}</H1>
<Title>{item.name}</Title>
<View style={{
flexDirection: 'row',
width: '100%',
marginTop: 10,
}}>
<H3 style={{
color: this.getStockColor(parseInt(this.state.modalCurrentDisplayItem.quantity)),
<Subheading style={{
color: this.getStockColor(parseInt(item.quantity)),
}}>
{this.state.modalCurrentDisplayItem.quantity + ' ' + i18n.t('proximoScreen.inStock')}
</H3>
<H3 style={{marginLeft: 'auto'}}>{this.state.modalCurrentDisplayItem.price}</H3>
{item.quantity + ' ' + i18n.t('proximoScreen.inStock')}
</Subheading>
<Subheading style={{marginLeft: 'auto'}}>{item.price}</Subheading>
</View>
<Content>
<ScrollView>
<View style={{width: '100%', height: 150, marginTop: 20, marginBottom: 20}}>
<Image style={{flex: 1, resizeMode: "contain"}}
source={{uri: this.state.modalCurrentDisplayItem.image}}/>
source={{uri: item.image}}/>
</View>
<Text>{this.state.modalCurrentDisplayItem.description}</Text>
</Content>
<Text>{item.description}</Text>
</ScrollView>
</View>
);
}
getModalSortMenu() {
return (
<View style={{
flex: 1,
padding: 20
}}>
<Title>Sort Order</Title>
<RadioButton.Group
onValueChange={value => this.setSortMode(value)}
value={this.state.currentSortMode}
>
<View style={{
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center'
}}>
<Text>{i18n.t('proximoScreen.sortPrice')}</Text>
<RadioButton value={1}/>
</View>
<View style={{
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center'
}}>
<Text>{i18n.t('proximoScreen.sortPriceReverse')}</Text>
<RadioButton value={2}/>
</View>
<View style={{
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center'
}}>
<Text>{i18n.t('proximoScreen.sortName')}</Text>
<RadioButton value={3}/>
</View>
<View style={{
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center'
}}>
<Text>{i18n.t('proximoScreen.sortNameReverse')}</Text>
<RadioButton value={4}/>
</View>
</RadioButton.Group>
</View>
);
}
onListItemPress(item: Object) {
this.setState({
modalCurrentDisplayItem: item
modalCurrentDisplayItem: this.getModalItemContent(item)
});
if (this.modalRef.current) {
this.modalRef.current.open();
}
}
onSelectSortModeName() {
this.sortModeSelected(sortMode.name);
}
onSelectSortModePrice() {
this.sortModeSelected(sortMode.price);
}
onSortMenuPress() {
this.sortMenuRef.show();
this.setState({
modalCurrentDisplayItem: this.getModalSortMenu()
});
if (this.modalRef.current) {
this.modalRef.current.open();
}
}
getSortMenu() {
return (
<Menu
ref={this.onMenuRef}
button={
<Touchable
style={{padding: 6}}
onPress={this.onSortMenuPress}>
<CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon={'sort'}/>
</Touchable>
}
>
<MenuItem
onPress={this.onSelectSortModeName}>
{this.state.sortNameIcon}
{i18n.t('proximoScreen.sortName')}
</MenuItem>
<MenuItem
onPress={this.onSelectSortModePrice}>
{this.state.sortPriceIcon}
{i18n.t('proximoScreen.sortPrice')}
</MenuItem>
</Menu>
<IconButton
icon="sort"
color={ThemeManager.getCurrentThemeVariables().text}
size={26}
onPress={this.onSortMenuPress}
/>
);
}
renderItem({item}: Object) {
const onListItemPress = this.onListItemPress.bind(this, item);
return (<ListItem
thumbnail
onPress={onListItemPress}
>
<Left>
<Thumbnail square source={{uri: item.image}}/>
</Left>
<Body>
<Text style={{marginLeft: 20}}>
{item.name}
</Text>
<Text note style={{
marginLeft: 20,
color: this.getStockColor(parseInt(item.quantity))
}}>
{item.quantity + ' ' + i18n.t('proximoScreen.inStock')}
</Text>
</Body>
<Right>
<Text style={{fontWeight: "bold"}}>
{item.price}
</Text>
</Right>
</ListItem>);
const onPress = this.onListItemPress.bind(this, item);
return (
<List.Item
title={item.name}
description={item.quantity + ' ' + i18n.t('proximoScreen.inStock')}
descriptionStyle={{color: this.getStockColor(parseInt(item.quantity))}}
onPress={onPress}
left={props => <Avatar.Image style={{backgroundColor: 'transparent'}} size={64}
source={{uri: item.image}}/>}
right={props =>
<Text style={{fontWeight: "bold"}}>
{item.price}
</Text>}
/>
);
}
keyExtractor(item: Object) {
@ -348,24 +298,19 @@ export default class ProximoListScreen extends React.Component<Props, State> {
}
render() {
// console.log("rendering ProximoListScreen");
const nav = this.props.navigation;
return (
<Container>
<Modalize ref={this.modalRef}
adjustToContentHeight
modalStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
{this.getModalContent()}
<View style={{
height: '100%'
}}>
<Modalize
ref={this.modalRef}
adjustToContentHeight
handlePosition={'inside'}
modalStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().card}}
handleStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().text}}
>
{this.state.modalCurrentDisplayItem}
</Modalize>
<CustomHeader
hasBackButton={true}
navigation={nav}
hasSearchField={true}
searchCallback={this.onSearchStringChange}
shouldFocusSearchBar={this.shouldFocusSearchBar}
rightButton={this.getSortMenu()}
/>
<FlatList
data={this.state.currentlyDisplayedData}
extraData={this.state.currentlyDisplayedData}
@ -373,7 +318,7 @@ export default class ProximoListScreen extends React.Component<Props, State> {
style={{minHeight: 300, width: '100%'}}
renderItem={this.renderItem}
/>
</Container>
</View>
);
}
}

View file

@ -1,30 +1,42 @@
// @flow
import * as React from 'react';
import {Platform, View} from 'react-native'
import {Body, Left, ListItem, Right, Text} from 'native-base';
import {View} from 'react-native'
import i18n from "i18n-js";
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
import FetchedDataSectionList from "../../components/FetchedDataSectionList";
import ThemeManager from "../../utils/ThemeManager";
import Touchable from "react-native-platform-touchable";
import WebSectionList from "../../components/WebSectionList";
import {IconButton, List} from 'react-native-paper';
import HeaderButton from "../../components/HeaderButton";
const DATA_URL = "https://etud.insa-toulouse.fr/~proximo/data/stock-v2.json";
type Props = {
navigation: Object,
}
type State = {
fetchedData: Object,
}
/**
* Class defining the main proximo screen. This screen shows the different categories of articles
* offered by proximo.
*/
export default class ProximoMainScreen extends FetchedDataSectionList {
export default class ProximoMainScreen extends React.Component<Props, State> {
articles: Object;
onPressSearchBtn: Function;
onPressAboutBtn: Function;
getRenderItem: Function;
createDataset: Function;
constructor() {
super(DATA_URL, 0);
super();
this.onPressSearchBtn = this.onPressSearchBtn.bind(this);
this.onPressAboutBtn = this.onPressAboutBtn.bind(this);
this.getRenderItem = this.getRenderItem.bind(this);
this.createDataset = this.createDataset.bind(this);
}
static sortFinalData(a: Object, b: Object) {
@ -45,12 +57,11 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
return 0;
}
getHeaderTranslation() {
return i18n.t("screens.proximo");
}
getUpdateToastTranslations() {
return [i18n.t("proximoScreen.listUpdated"), i18n.t("proximoScreen.listUpdateFail")];
componentDidMount() {
const rightButton = this.getRightButton.bind(this);
this.props.navigation.setOptions({
headerRight: rightButton,
});
}
getKeyExtractor(item: Object) {
@ -62,7 +73,7 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
{
title: '',
data: this.generateData(fetchedData),
extraData: super.state,
extraData: this.state,
keyExtractor: this.getKeyExtractor
}
];
@ -77,21 +88,22 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
*/
generateData(fetchedData: Object) {
let finalData = [];
this.articles = undefined;
if (fetchedData.types !== undefined && fetchedData.articles !== undefined) {
let types = fetchedData.types;
let articles = fetchedData.articles;
this.articles = fetchedData.articles;
finalData.push({
type: {
id: -1,
name: i18n.t('proximoScreen.all'),
icon: 'star'
},
data: this.getAvailableArticles(articles, undefined)
data: this.getAvailableArticles(this.articles, undefined)
});
for (let i = 0; i < types.length; i++) {
finalData.push({
type: types[i],
data: this.getAvailableArticles(articles, types[i])
data: this.getAvailableArticles(this.articles, types[i])
});
}
@ -128,8 +140,8 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
name: i18n.t('proximoScreen.all'),
icon: 'star'
},
data: this.state.fetchedData.articles !== undefined ?
this.getAvailableArticles(this.state.fetchedData.articles, undefined) : []
data: this.articles !== undefined ?
this.getAvailableArticles(this.articles, undefined) : []
},
};
this.props.navigation.navigate('ProximoListScreen', searchScreenData);
@ -143,63 +155,49 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
return (
<View
style={{
flexDirection: 'row'
flexDirection: 'row',
}}>
<Touchable
style={{padding: 6}}
onPress={this.onPressSearchBtn}>
<CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon="magnify"/>
</Touchable>
<Touchable
style={{padding: 6}}
onPress={this.onPressAboutBtn}>
<CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon="information"/>
</Touchable>
<HeaderButton icon={'magnify'} onPress={this.onPressSearchBtn}/>
<HeaderButton icon={'information'} onPress={this.onPressAboutBtn}/>
</View>
);
}
getRenderItem(item: Object, section: Object) {
getRenderItem({item}: Object) {
let dataToSend = {
shouldFocusSearchBar: false,
data: item,
};
const subtitle = item.data.length + " " + (item.data.length > 1 ? i18n.t('proximoScreen.articles') : i18n.t('proximoScreen.article'));
const onPress = this.props.navigation.navigate.bind(this, 'ProximoListScreen', dataToSend);
if (item.data.length > 0) {
return (
<ListItem
button
thumbnail
<List.Item
title={item.type.name}
description={subtitle}
onPress={onPress}
>
<Left>
<CustomMaterialIcon
icon={item.type.icon}
fontSize={30}
color={ThemeManager.getCurrentThemeVariables().brandPrimary}
/>
</Left>
<Body>
<Text>
{item.type.name}
</Text>
<Text note>
{item.data.length} {item.data.length > 1 ? i18n.t('proximoScreen.articles') : i18n.t('proximoScreen.article')}
</Text>
</Body>
<Right>
<CustomMaterialIcon icon="chevron-right"/>
</Right>
</ListItem>
left={props => <List.Icon
{...props}
icon={item.type.icon}
color={ThemeManager.getCurrentThemeVariables().primary}/>}
right={props => <List.Icon {...props} icon={'chevron-right'}/>}
/>
);
} else {
} else
return <View/>;
}
}
render() {
const nav = this.props.navigation;
return (
<WebSectionList
createDataset={this.createDataset}
navigation={nav}
refreshTime={0}
fetchUrl={DATA_URL}
renderItem={this.getRenderItem}/>
);
}
}

View file

@ -1,12 +1,9 @@
// @flow
import * as React from 'react';
import {Image, View} from 'react-native';
import {Body, Card, CardItem, Container, Content, H2, H3, Left, Tab, TabHeading, Tabs, Text} from 'native-base';
import CustomHeader from "../../components/CustomHeader";
import {Image, View, ScrollView} from 'react-native';
import i18n from "i18n-js";
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
import ThemeManager from "../../utils/ThemeManager";
import {Card, List, Paragraph, Text, Title} from 'react-native-paper';
type Props = {
navigation: Object,
@ -18,132 +15,68 @@ type Props = {
export default class ProxiwashAboutScreen extends React.Component<Props> {
render() {
const nav = this.props.navigation;
return (
<Container>
<CustomHeader
navigation={nav} title={i18n.t('screens.proxiwash')}
hasBackButton={true}
hasTabs={true}/>
<Tabs
tabContainerStyle={{
elevation: 0, // Fix for android shadow
}}>
<Tab
heading={
<TabHeading>
<CustomMaterialIcon
icon={'information'}
color={ThemeManager.getCurrentThemeVariables().tabIconColor}
fontSize={20}
/>
<Text>{i18n.t('proxiwashScreen.informationTab')}</Text>
</TabHeading>
}
key={1}
style={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
<Content padder>
<View style={{
width: '100%',
height: 100,
marginTop: 20,
marginBottom: 20,
justifyContent: 'center',
alignItems: 'center'
}}>
<Image
source={require('../../assets/proxiwash-logo.png')}
style={{flex: 1, resizeMode: "contain"}}
resizeMode="contain"/>
</View>
<Text>{i18n.t('proxiwashScreen.description')}</Text>
<Card>
<CardItem>
<Left>
<CustomMaterialIcon icon={'tumble-dryer'}/>
<H2>{i18n.t('proxiwashScreen.dryer')}</H2>
</Left>
</CardItem>
<CardItem>
<Body>
<H3>{i18n.t('proxiwashScreen.procedure')}</H3>
<Text>{i18n.t('proxiwashScreen.dryerProcedure')}</Text>
</Body>
</CardItem>
<CardItem>
<Body>
<H3>{i18n.t('proxiwashScreen.tips')}</H3>
<Text>{i18n.t('proxiwashScreen.dryerTips')}</Text>
</Body>
</CardItem>
</Card>
<Card>
<CardItem>
<Left>
<CustomMaterialIcon icon={'washing-machine'}/>
<H2>{i18n.t('proxiwashScreen.washer')}</H2>
</Left>
</CardItem>
<CardItem>
<Body>
<H3>{i18n.t('proxiwashScreen.procedure')}</H3>
<Text>{i18n.t('proxiwashScreen.washerProcedure')}</Text>
</Body>
</CardItem>
<CardItem>
<Body>
<H3>{i18n.t('proxiwashScreen.tips')}</H3>
<Text>{i18n.t('proxiwashScreen.washerTips')}</Text>
</Body>
</CardItem>
</Card>
</Content>
</Tab>
<Tab
heading={
<TabHeading>
<CustomMaterialIcon
icon={'cash'}
color={ThemeManager.getCurrentThemeVariables().tabIconColor}
fontSize={20}
/>
<Text>{i18n.t('proxiwashScreen.paymentTab')}</Text>
</TabHeading>
}
key={2}
style={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
<Content padder>
<Card>
<CardItem>
<Left>
<CustomMaterialIcon icon={'coins'}/>
<H2>{i18n.t('proxiwashScreen.tariffs')}</H2>
</Left>
</CardItem>
<CardItem>
<Body>
<Text>{i18n.t('proxiwashScreen.washersTariff')}</Text>
<Text>{i18n.t('proxiwashScreen.dryersTariff')}</Text>
</Body>
</CardItem>
</Card>
<Card>
<CardItem>
<Left>
<CustomMaterialIcon icon={'cash'}/>
<H2>{i18n.t('proxiwashScreen.paymentMethods')}</H2>
</Left>
</CardItem>
<CardItem>
<Body>
<Text>{i18n.t('proxiwashScreen.paymentMethodsDescription')}</Text>
</Body>
</CardItem>
</Card>
</Content>
</Tab>
</Tabs>
</Container>
<ScrollView style={{padding: 5}}>
<View style={{
width: '100%',
height: 100,
marginTop: 20,
marginBottom: 20,
justifyContent: 'center',
alignItems: 'center'
}}>
<Image
source={require('../../assets/proxiwash-logo.png')}
style={{flex: 1, resizeMode: "contain"}}
resizeMode="contain"/>
</View>
<Text>{i18n.t('proxiwashScreen.description')}</Text>
<Card style={{margin: 5}}>
<Card.Title
title={i18n.t('proxiwashScreen.dryer')}
left={props => <List.Icon {...props} icon={'tumble-dryer'}/>}
/>
<Card.Content>
<Title>{i18n.t('proxiwashScreen.procedure')}</Title>
<Paragraph>{i18n.t('proxiwashScreen.dryerProcedure')}</Paragraph>
<Title>{i18n.t('proxiwashScreen.tips')}</Title>
<Paragraph>{i18n.t('proxiwashScreen.dryerTips')}</Paragraph>
</Card.Content>
</Card>
<Card style={{margin: 5}}>
<Card.Title
title={i18n.t('proxiwashScreen.washer')}
left={props => <List.Icon {...props} icon={'washing-machine'}/>}
/>
<Card.Content>
<Title>{i18n.t('proxiwashScreen.procedure')}</Title>
<Paragraph>{i18n.t('proxiwashScreen.washerProcedure')}</Paragraph>
<Title>{i18n.t('proxiwashScreen.tips')}</Title>
<Paragraph>{i18n.t('proxiwashScreen.washerTips')}</Paragraph>
</Card.Content>
</Card>
<Card style={{margin: 5}}>
<Card.Title
title={i18n.t('proxiwashScreen.tariffs')}
left={props => <List.Icon {...props} icon={'coins'}/>}
/>
<Card.Content>
<Paragraph>{i18n.t('proxiwashScreen.washersTariff')}</Paragraph>
<Paragraph>{i18n.t('proxiwashScreen.dryersTariff')}</Paragraph>
</Card.Content>
</Card>
<Card style={{margin: 5}}>
<Card.Title
title={i18n.t('proxiwashScreen.paymentMethods')}
left={props => <List.Icon {...props} icon={'cash'}/>}
/>
<Card.Content>
<Paragraph>{i18n.t('proxiwashScreen.paymentMethodsDescription')}</Paragraph>
</Card.Content>
</Card>
</ScrollView>
);
}
}

View file

@ -2,90 +2,113 @@
import * as React from 'react';
import {Alert, Platform, View} from 'react-native';
import {Body, Card, CardItem, Left, Right, Text} from 'native-base';
import ThemeManager from '../../utils/ThemeManager';
import i18n from "i18n-js";
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
import FetchedDataSectionList from "../../components/FetchedDataSectionList";
import WebSectionList from "../../components/WebSectionList";
import NotificationsManager from "../../utils/NotificationsManager";
import PlatformTouchable from "react-native-platform-touchable";
import Touchable from "react-native-platform-touchable";
import AsyncStorageManager from "../../utils/AsyncStorageManager";
import * as Expo from "expo";
import {Avatar, Banner, Button, Card, Text} from 'react-native-paper';
import HeaderButton from "../../components/HeaderButton";
import ProxiwashListItem from "../../components/ProxiwashListItem";
import ProxiwashConstants from "../../constants/ProxiwashConstants";
import {Modalize} from "react-native-modalize";
import ThemeManager from "../../utils/ThemeManager";
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/washinsa/washinsa.json";
const MACHINE_STATES = {
"TERMINE": "0",
"DISPONIBLE": "1",
"EN COURS": "2",
"HS": "3",
"ERREUR": "4"
};
let stateStrings = {};
let modalStateStrings = {};
let stateIcons = {};
let stateColors = {};
const REFRESH_TIME = 1000 * 10; // Refresh every 10 seconds
type Props = {
navigation: Object,
}
type State = {
refreshing: boolean,
firstLoading: boolean,
modalCurrentDisplayItem: React.Node,
machinesWatched: Array<string>,
bannerVisible: boolean,
};
/**
* Class defining the app's proxiwash screen. This screen shows information about washing machines and
* dryers, taken from a scrapper reading proxiwash website
*/
export default class ProxiwashScreen extends FetchedDataSectionList {
export default class ProxiwashScreen extends React.Component<Props, State> {
modalRef: { current: null | Modalize };
onAboutPress: Function;
getRenderItem: Function;
getRenderSectionHeader: Function;
createDataset: Function;
onHideBanner: Function;
fetchedData: Object;
state = {
refreshing: false,
firstLoading: true,
fetchedData: {},
// machinesWatched: JSON.parse(dataString),
machinesWatched: [],
modalCurrentDisplayItem: null,
bannerVisible: AsyncStorageManager.getInstance().preferences.proxiwashShowBanner.current === '1',
};
/**
* Creates machine state parameters using current theme and translations
*/
constructor() {
super(DATA_URL, REFRESH_TIME);
let colors = ThemeManager.getCurrentThemeVariables();
stateColors[MACHINE_STATES.TERMINE] = colors.proxiwashFinishedColor;
stateColors[MACHINE_STATES.DISPONIBLE] = colors.proxiwashReadyColor;
stateColors[MACHINE_STATES["EN COURS"]] = colors.proxiwashRunningColor;
stateColors[MACHINE_STATES.HS] = colors.proxiwashBrokenColor;
stateColors[MACHINE_STATES.ERREUR] = colors.proxiwashErrorColor;
super();
this.modalRef = React.createRef();
stateStrings[ProxiwashConstants.machineStates.TERMINE] = i18n.t('proxiwashScreen.states.finished');
stateStrings[ProxiwashConstants.machineStates.DISPONIBLE] = i18n.t('proxiwashScreen.states.ready');
stateStrings[ProxiwashConstants.machineStates["EN COURS"]] = i18n.t('proxiwashScreen.states.running');
stateStrings[ProxiwashConstants.machineStates.HS] = i18n.t('proxiwashScreen.states.broken');
stateStrings[ProxiwashConstants.machineStates.ERREUR] = i18n.t('proxiwashScreen.states.error');
stateStrings[MACHINE_STATES.TERMINE] = i18n.t('proxiwashScreen.states.finished');
stateStrings[MACHINE_STATES.DISPONIBLE] = i18n.t('proxiwashScreen.states.ready');
stateStrings[MACHINE_STATES["EN COURS"]] = i18n.t('proxiwashScreen.states.running');
stateStrings[MACHINE_STATES.HS] = i18n.t('proxiwashScreen.states.broken');
stateStrings[MACHINE_STATES.ERREUR] = i18n.t('proxiwashScreen.states.error');
modalStateStrings[ProxiwashConstants.machineStates.TERMINE] = i18n.t('proxiwashScreen.modal.finished');
modalStateStrings[ProxiwashConstants.machineStates.DISPONIBLE] = i18n.t('proxiwashScreen.modal.ready');
modalStateStrings[ProxiwashConstants.machineStates["EN COURS"]] = i18n.t('proxiwashScreen.modal.running');
modalStateStrings[ProxiwashConstants.machineStates.HS] = i18n.t('proxiwashScreen.modal.broken');
modalStateStrings[ProxiwashConstants.machineStates.ERREUR] = i18n.t('proxiwashScreen.modal.error');
modalStateStrings[MACHINE_STATES.TERMINE] = i18n.t('proxiwashScreen.modal.finished');
modalStateStrings[MACHINE_STATES.DISPONIBLE] = i18n.t('proxiwashScreen.modal.ready');
modalStateStrings[MACHINE_STATES["EN COURS"]] = i18n.t('proxiwashScreen.modal.running');
modalStateStrings[MACHINE_STATES.HS] = i18n.t('proxiwashScreen.modal.broken');
modalStateStrings[MACHINE_STATES.ERREUR] = i18n.t('proxiwashScreen.modal.error');
stateIcons[MACHINE_STATES.TERMINE] = 'check-circle';
stateIcons[MACHINE_STATES.DISPONIBLE] = 'radiobox-blank';
stateIcons[MACHINE_STATES["EN COURS"]] = 'progress-check';
stateIcons[MACHINE_STATES.HS] = 'alert-octagram-outline';
stateIcons[MACHINE_STATES.ERREUR] = 'alert';
stateIcons[ProxiwashConstants.machineStates.TERMINE] = 'check-circle';
stateIcons[ProxiwashConstants.machineStates.DISPONIBLE] = 'radiobox-blank';
stateIcons[ProxiwashConstants.machineStates["EN COURS"]] = 'progress-check';
stateIcons[ProxiwashConstants.machineStates.HS] = 'alert-octagram-outline';
stateIcons[ProxiwashConstants.machineStates.ERREUR] = 'alert';
// let dataString = AsyncStorageManager.getInstance().preferences.proxiwashWatchedMachines.current;
this.state = {
refreshing: false,
firstLoading: true,
fetchedData: {},
// machinesWatched: JSON.parse(dataString),
machinesWatched: [],
};
this.setMinTimeRefresh(30);
this.onAboutPress = this.onAboutPress.bind(this);
this.getRenderItem = this.getRenderItem.bind(this);
this.getRenderSectionHeader = this.getRenderSectionHeader.bind(this);
this.createDataset = this.createDataset.bind(this);
this.onHideBanner = this.onHideBanner.bind(this);
}
onHideBanner() {
this.setState({bannerVisible: false});
AsyncStorageManager.getInstance().savePref(
AsyncStorageManager.getInstance().preferences.proxiwashShowBanner.key,
'0'
);
}
/**
* Setup notification channel for android and add listeners to detect notifications fired
*/
componentDidMount() {
super.componentDidMount();
const rightButton = this.getRightButton.bind(this);
this.props.navigation.setOptions({
headerRight: rightButton,
});
if (AsyncStorageManager.getInstance().preferences.expoToken.current !== '') {
// Get latest watchlist from server
NotificationsManager.getMachineNotificationWatchlist((fetchedList) => {
@ -107,14 +130,6 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
}
}
getHeaderTranslation() {
return i18n.t("screens.proxiwash");
}
getUpdateToastTranslations() {
return [i18n.t("proxiwashScreen.listUpdated"), i18n.t("proxiwashScreen.listUpdateFail")];
}
getDryersKeyExtractor(item: Object) {
return item !== undefined ? "dryer" + item.number : undefined;
}
@ -211,84 +226,192 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
}
createDataset(fetchedData: Object) {
this.fetchedData = fetchedData;
return [
{
title: i18n.t('proxiwashScreen.washers'),
icon: 'washing-machine',
data: fetchedData.washers === undefined ? [] : fetchedData.washers,
extraData: super.state,
keyExtractor: this.getWashersKeyExtractor
},
{
title: i18n.t('proxiwashScreen.dryers'),
icon: 'tumble-dryer',
data: fetchedData.dryers === undefined ? [] : fetchedData.dryers,
extraData: super.state,
extraData: this.state,
keyExtractor: this.getDryersKeyExtractor
},
{
title: i18n.t('proxiwashScreen.washers'),
icon: 'washing-machine',
data: fetchedData.washers === undefined ? [] : fetchedData.washers,
extraData: this.state,
keyExtractor: this.getWashersKeyExtractor
},
];
}
hasTabs(): boolean {
return true;
showModal(title: string, item: Object, isDryer: boolean) {
this.setState({
modalCurrentDisplayItem: this.getModalContent(title, item, isDryer)
});
if (this.modalRef.current) {
this.modalRef.current.open();
}
}
/**
* Show an alert fo a machine, allowing to enable/disable notifications if running
*
* @param title
* @param item
* @param isDryer
*/
showAlert(title: string, item: Object, isDryer: boolean) {
let buttons = [{text: i18n.t("proxiwashScreen.modal.ok")}];
let message = modalStateStrings[MACHINE_STATES[item.state]];
const onPress = this.setupNotifications.bind(this, item.number);
if (MACHINE_STATES[item.state] === MACHINE_STATES["EN COURS"]) {
buttons = [
onSetupNotificationsPress(machineId: string) {
if (this.modalRef.current) {
this.modalRef.current.close();
}
this.setupNotifications(machineId)
}
getModalContent(title: string, item: Object, isDryer: boolean) {
let button = {
text: i18n.t("proxiwashScreen.modal.ok"),
icon: '',
onPress: undefined
};
let message = modalStateStrings[ProxiwashConstants.machineStates[item.state]];
const onPress = this.onSetupNotificationsPress.bind(this, item.number);
if (ProxiwashConstants.machineStates[item.state] === ProxiwashConstants.machineStates["EN COURS"]) {
button =
{
text: this.isMachineWatched(item.number) ?
i18n.t("proxiwashScreen.modal.disableNotifications") :
i18n.t("proxiwashScreen.modal.enableNotifications"),
icon: '',
onPress: onPress
},
{
text: i18n.t("proxiwashScreen.modal.cancel")
}
];
;
message = i18n.t('proxiwashScreen.modal.running',
{
start: item.startTime,
end: item.endTime,
remaining: item.remainingTime
});
} else if (MACHINE_STATES[item.state] === MACHINE_STATES.DISPONIBLE) {
} else if (ProxiwashConstants.machineStates[item.state] === ProxiwashConstants.machineStates.DISPONIBLE) {
if (isDryer)
message += '\n' + i18n.t('proxiwashScreen.dryersTariff');
else
message += '\n' + i18n.t('proxiwashScreen.washersTariff');
}
Alert.alert(
title,
message,
buttons
return (
<View style={{
flex: 1,
padding: 20
}}>
<Card.Title
title={title}
left={() => <Avatar.Icon
icon={isDryer ? 'tumble-dryer' : 'washing-machine'}
color={ThemeManager.getCurrentThemeVariables().text}
style={{backgroundColor: 'transparent'}}/>}
/>
<Card.Content>
<Text>{message}</Text>
</Card.Content>
{button.onPress !== undefined ?
<Card.Actions>
<Button
icon={button.icon}
mode="contained"
onPress={button.onPress}
style={{marginLeft: 'auto', marginRight: 'auto'}}
>
{button.text}
</Button>
</Card.Actions> : null}
</View>
);
}
onAboutPress() {
this.props.navigation.navigate('ProxiwashAboutScreen');
}
getRightButton(): * {
getRightButton() {
return (
<Touchable
style={{padding: 6}}
onPress={this.onAboutPress}>
<CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon="information"/>
</Touchable>
<HeaderButton icon={'information'} onPress={this.onAboutPress}/>
);
}
render() {
const nav = this.props.navigation;
return (
<View>
<Banner
visible={this.state.bannerVisible}
actions={[
{
label: 'OK',
onPress: this.onHideBanner,
},
]}
icon={() => <Avatar.Icon
icon={'information'}
size={40}
/>}
>
{i18n.t('proxiwashScreen.enableNotificationsTip')}
</Banner>
<Modalize ref={this.modalRef}
adjustToContentHeight
handlePosition={'inside'}
modalStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().surface}}
handleStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().text}}
>
{this.state.modalCurrentDisplayItem}
</Modalize>
<WebSectionList
createDataset={this.createDataset}
navigation={nav}
refreshTime={REFRESH_TIME}
fetchUrl={DATA_URL}
renderItem={this.getRenderItem}
renderSectionHeader={this.getRenderSectionHeader}/>
</View>
);
}
getMachineAvailableNumber(isDryer: boolean) {
let data;
if (isDryer)
data = this.fetchedData.dryers;
else
data = this.fetchedData.washers;
let count = 0;
for (let i = 0; i < data.length; i++) {
if (ProxiwashConstants.machineStates[data[i].state] === ProxiwashConstants.machineStates["DISPONIBLE"])
count += 1;
}
return count;
}
getRenderSectionHeader({section}: Object) {
const subtitle = this.getMachineAvailableNumber(section.title === i18n.t('proxiwashScreen.dryers')) + ' ' + i18n.t('proxiwashScreen.numAvailable');
return (
<Card style={{
width: '60%',
marginLeft: 'auto',
marginRight: 'auto',
marginBottom: 10,
marginTop: 20,
elevation: 4,
}}>
<Card.Title
title={section.title}
subtitle={subtitle}
titleStyle={{
textAlign: 'center'
}}
subtitleStyle={{
textAlign: 'center'
}}
style={{
paddingLeft: 0,
}}
/>
</Card>
);
}
@ -299,77 +422,26 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
* @param section The object describing the current SectionList section
* @returns {React.Node}
*/
getRenderItem(item: Object, section: Object) {
let isMachineRunning = MACHINE_STATES[item.state] === MACHINE_STATES["EN COURS"];
let machineName = (section.title === i18n.t('proxiwashScreen.dryers') ? i18n.t('proxiwashScreen.dryer') : i18n.t('proxiwashScreen.washer')) + ' n°' + item.number;
let isDryer = section.title === i18n.t('proxiwashScreen.dryers');
const onPress = this.showAlert.bind(this, machineName, item, isDryer);
getRenderItem({item, section}: Object) {
const isMachineRunning = ProxiwashConstants.machineStates[item.state] === ProxiwashConstants.machineStates["EN COURS"];
const machineName = (section.title === i18n.t('proxiwashScreen.dryers') ? i18n.t('proxiwashScreen.dryer') : i18n.t('proxiwashScreen.washer')) + ' n°' + item.number;
const isDryer = section.title === i18n.t('proxiwashScreen.dryers');
const onPress = this.showModal.bind(this, machineName, item, isDryer);
let width = item.donePercent !== '' ? (parseInt(item.donePercent)).toString() + '%' : 0;
if (ProxiwashConstants.machineStates[item.state] === '0')
width = '100%';
return (
<Card style={{
flex: 0,
height: 64,
marginLeft: 10,
marginRight: 10
}}>
<CardItem
style={{
backgroundColor: stateColors[MACHINE_STATES[item.state]],
paddingRight: 0,
paddingLeft: 0,
height: '100%',
}}
>
<View style={{
height: 64,
position: 'absolute',
right: 0,
width: item.donePercent !== '' ? (100 - parseInt(item.donePercent)).toString() + '%' : 0,
backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor
}}/>
<PlatformTouchable
onPress={onPress}
style={{
height: 64,
position: 'absolute',
zIndex: 10, // Make sure the button is above the text
right: 0,
width: '100%'
}}
>
<View/>
</PlatformTouchable>
<Left style={{marginLeft: 10}}>
<CustomMaterialIcon
icon={isDryer ? 'tumble-dryer' : 'washing-machine'}
fontSize={30}
/>
<Body>
<Text>
{machineName + ' '}
{this.isMachineWatched(item.number) ?
<CustomMaterialIcon
icon='bell-ring'
color={ThemeManager.getCurrentThemeVariables().brandPrimary}
fontSize={20}
/> : ''}
</Text>
<Text note>
{isMachineRunning ? item.startTime + '/' + item.endTime : ''}
</Text>
</Body>
</Left>
<Right style={{marginRight: 10}}>
<Text style={MACHINE_STATES[item.state] === MACHINE_STATES.TERMINE ?
{fontWeight: 'bold'} : {}}
>
{stateStrings[MACHINE_STATES[item.state]]}
</Text>
<CustomMaterialIcon icon={stateIcons[MACHINE_STATES[item.state]]}
fontSize={25}
/>
</Right>
</CardItem>
</Card>);
<ProxiwashListItem
title={machineName}
description={isMachineRunning ? item.startTime + '/' + item.endTime : ''}
onPress={onPress}
progress={width}
state={item.state}
isWatched={this.isMachineWatched(item.number)}
isDryer={isDryer}
statusText={stateStrings[ProxiwashConstants.machineStates[item.state]]}
statusIcon={stateIcons[ProxiwashConstants.machineStates[item.state]]}
/>
);
}
}

View file

@ -2,25 +2,33 @@
import * as React from 'react';
import {View} from 'react-native';
import {Card, CardItem, H2, H3, Text} from 'native-base';
import ThemeManager from "../utils/ThemeManager";
import i18n from "i18n-js";
import FetchedDataSectionList from "../components/FetchedDataSectionList";
import WebSectionList from "../components/WebSectionList";
import {Card, Text, Title} from 'react-native-paper';
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/menu/menu_data.json";
type Props = {
navigation: Object,
}
/**
* Class defining the app's menu screen.
* This screen fetches data from etud to render the RU menu
*/
export default class SelfMenuScreen extends FetchedDataSectionList {
export default class SelfMenuScreen extends React.Component<Props> {
// Hard code strings as toLocaleDateString does not work on current android JS engine
daysOfWeek = [];
monthsOfYear = [];
getRenderItem: Function;
getRenderSectionHeader: Function;
createDataset: Function;
constructor() {
super(DATA_URL, 0);
super();
this.daysOfWeek.push(i18n.t("date.daysOfWeek.monday"));
this.daysOfWeek.push(i18n.t("date.daysOfWeek.tuesday"));
this.daysOfWeek.push(i18n.t("date.daysOfWeek.wednesday"));
@ -41,32 +49,16 @@ export default class SelfMenuScreen extends FetchedDataSectionList {
this.monthsOfYear.push(i18n.t("date.monthsOfYear.october"));
this.monthsOfYear.push(i18n.t("date.monthsOfYear.november"));
this.monthsOfYear.push(i18n.t("date.monthsOfYear.december"));
}
getHeaderTranslation() {
return i18n.t("screens.menuSelf");
}
getUpdateToastTranslations() {
return [i18n.t("homeScreen.listUpdated"), i18n.t("homeScreen.listUpdateFail")];
this.getRenderItem = this.getRenderItem.bind(this);
this.getRenderSectionHeader = this.getRenderSectionHeader.bind(this);
this.createDataset = this.createDataset.bind(this);
}
getKeyExtractor(item: Object) {
return item !== undefined ? item['name'] : undefined;
}
hasBackButton() {
return true;
}
hasStickyHeader(): boolean {
return true;
}
hasSideMenu(): boolean {
return false;
}
createDataset(fetchedData: Object) {
let result = [];
// Prevent crash by giving a default value when fetchedData is empty (not yet available)
@ -101,64 +93,62 @@ export default class SelfMenuScreen extends FetchedDataSectionList {
return this.daysOfWeek[date.getDay() - 1] + " " + date.getDate() + " " + this.monthsOfYear[date.getMonth()] + " " + date.getFullYear();
}
getRenderSectionHeader(title: string) {
getRenderSectionHeader({section}: Object) {
return (
<Card style={{
marginLeft: 10,
marginRight: 10,
marginTop: 10,
width: '90%',
marginLeft: 'auto',
marginRight: 'auto',
marginBottom: 10,
borderRadius: 50
marginTop: 20,
elevation: 4,
}}>
<H2 style={{
textAlign: 'center',
marginTop: 10,
marginBottom: 10
}}>{title}</H2>
<Card.Title
title={section.title}
titleStyle={{
textAlign: 'center'
}}
subtitleStyle={{
textAlign: 'center'
}}
style={{
paddingLeft: 0,
}}
/>
</Card>
);
}
getRenderItem(item: Object, section: Object) {
getRenderItem({item}: Object) {
return (
<Card style={{
flex: 0,
marginLeft: 20,
marginRight: 20
margin: 10,
}}>
<CardItem style={{
paddingBottom: 0,
flexDirection: 'column'
}}>
<H3 style={{
marginTop: 10,
marginBottom: 0,
color: ThemeManager.getCurrentThemeVariables().listNoteColor
}}>{item.name}</H3>
<Card.Title
title={item.name}
/>
<View style={{
width: '80%',
marginLeft: 'auto',
marginRight: 'auto',
borderBottomWidth: 1,
borderBottomColor: ThemeManager.getCurrentThemeVariables().listBorderColor,
borderBottomColor: ThemeManager.getCurrentThemeVariables().primary,
marginTop: 10,
marginBottom: 5,
}}/>
</CardItem>
<CardItem style={{
flexDirection: 'column',
paddingTop: 0,
}}>
<Card.Content>
{item.dishes.map((object) =>
<View>
{object.name !== "" ?
<Text style={{
marginTop: 5,
marginBottom: 5
marginBottom: 5,
textAlign: 'center'
}}>{this.formatName(object.name)}</Text>
: <View/>}
</View>)}
</CardItem>
</Card.Content>
</Card>
);
}
@ -167,5 +157,18 @@ export default class SelfMenuScreen extends FetchedDataSectionList {
return name.charAt(0) + name.substr(1).toLowerCase();
}
render() {
const nav = this.props.navigation;
return (
<WebSectionList
createDataset={this.createDataset}
navigation={nav}
refreshTime={0}
fetchUrl={DATA_URL}
renderItem={this.getRenderItem}
renderSectionHeader={this.getRenderSectionHeader}
stickyHeader={true}/>
);
}
}

View file

@ -1,27 +1,12 @@
// @flow
import * as React from 'react';
import {
Body,
Card,
CardItem,
CheckBox,
Container,
Content,
Left,
List,
ListItem,
Picker,
Right,
Text,
} from "native-base";
import CustomHeader from "../components/CustomHeader";
import {ScrollView} from "react-native";
import ThemeManager from '../utils/ThemeManager';
import i18n from "i18n-js";
import {NavigationActions, StackActions} from "react-navigation";
import CustomMaterialIcon from "../components/CustomMaterialIcon";
import AsyncStorageManager from "../utils/AsyncStorageManager";
import NotificationsManager from "../utils/NotificationsManager";
import {Card, List, Switch, ToggleButton} from 'react-native-paper';
type Props = {
navigation: Object,
@ -54,39 +39,6 @@ export default class SettingsScreen extends React.Component<Props, State> {
this.onToggleNightMode = this.onToggleNightMode.bind(this);
}
/**
* Get a list item using the specified control
*
* @param control The custom control to use
* @param icon The icon name to display on the list item
* @param title The text to display as this list item title
* @param subtitle The text to display as this list item subtitle
* @returns {React.Node}
*/
static getGeneralItem(control: React.Node, icon: string, title: string, subtitle: string) {
return (
<ListItem
thumbnail
>
<Left>
<CustomMaterialIcon icon={icon}/>
</Left>
<Body>
<Text>
{title}
</Text>
<Text note>
{subtitle}
</Text>
</Body>
<Right>
{control}
</Right>
</ListItem>
);
}
/**
* Save the value for the proxiwash reminder notification time
*
@ -110,11 +62,13 @@ export default class SettingsScreen extends React.Component<Props, State> {
* @param value The value to store
*/
onStartScreenPickerValueChange(value: string) {
let key = AsyncStorageManager.getInstance().preferences.defaultStartScreen.key;
AsyncStorageManager.getInstance().savePref(key, value);
this.setState({
startScreenPickerSelected: value
});
if (value != null) {
let key = AsyncStorageManager.getInstance().preferences.defaultStartScreen.key;
AsyncStorageManager.getInstance().savePref(key, value);
this.setState({
startScreenPickerSelected: value
});
}
}
/**
@ -124,19 +78,14 @@ export default class SettingsScreen extends React.Component<Props, State> {
*/
getProxiwashNotifPicker() {
return (
<Picker
note
mode="dropdown"
style={{width: 120}}
selectedValue={this.state.proxiwashNotifPickerSelected}
<ToggleButton.Row
onValueChange={this.onProxiwashNotifPickerValueChange}
value={this.state.proxiwashNotifPickerSelected}
>
<Picker.Item label={i18n.t('settingsScreen.proxiwashNotifReminderPicker.never')} value="never"/>
<Picker.Item label={i18n.t('settingsScreen.proxiwashNotifReminderPicker.5')} value="5"/>
<Picker.Item label={i18n.t('settingsScreen.proxiwashNotifReminderPicker.10')} value="10"/>
<Picker.Item label={i18n.t('settingsScreen.proxiwashNotifReminderPicker.20')} value="20"/>
<Picker.Item label={i18n.t('settingsScreen.proxiwashNotifReminderPicker.30')} value="30"/>
</Picker>
<ToggleButton icon="close" value="never"/>
<ToggleButton icon="numeric-2" value="2"/>
<ToggleButton icon="numeric-5" value="5"/>
</ToggleButton.Row>
);
}
@ -147,19 +96,16 @@ export default class SettingsScreen extends React.Component<Props, State> {
*/
getStartScreenPicker() {
return (
<Picker
note
mode="dropdown"
style={{width: 120}}
selectedValue={this.state.startScreenPickerSelected}
<ToggleButton.Row
onValueChange={this.onStartScreenPickerValueChange}
value={this.state.startScreenPickerSelected}
>
<Picker.Item label={i18n.t('screens.home')} value="Home"/>
<Picker.Item label={i18n.t('screens.planning')} value="Planning"/>
<Picker.Item label={i18n.t('screens.proxiwash')} value="Proxiwash"/>
<Picker.Item label={i18n.t('screens.proximo')} value="Proximo"/>
<Picker.Item label={'Planex'} value="Planex"/>
</Picker>
<ToggleButton icon="shopping" value="Proximo"/>
<ToggleButton icon="calendar-range" value="Planning"/>
<ToggleButton icon="triangle" value="Home"/>
<ToggleButton icon="washing-machine" value="Proxiwash"/>
<ToggleButton icon="timetable" value="Planex"/>
</ToggleButton.Row>
);
}
@ -169,19 +115,6 @@ export default class SettingsScreen extends React.Component<Props, State> {
onToggleNightMode() {
ThemeManager.getInstance().setNightMode(!this.state.nightMode);
this.setState({nightMode: !this.state.nightMode});
this.resetStack();
}
/**
* Reset react navigation stack to allow for a theme reset
*/
resetStack() {
const resetAction = StackActions.reset({
index: 0,
key: null,
actions: [NavigationActions.navigate({routeName: 'Main'})],
});
this.props.navigation.dispatch(resetAction);
}
/**
@ -195,58 +128,56 @@ export default class SettingsScreen extends React.Component<Props, State> {
*/
getToggleItem(onPressCallback: Function, icon: string, title: string, subtitle: string) {
return (
<ListItem
button
thumbnail
onPress={onPressCallback}
>
<Left>
<CustomMaterialIcon icon={icon}/>
</Left>
<Body>
<Text>
{title}
</Text>
<Text note>
{subtitle}
</Text>
</Body>
<Right>
<CheckBox
checked={this.state.nightMode}
onPress={onPressCallback}
style={{marginRight: 20}}/>
</Right>
</ListItem>
<List.Item
title={title}
description={subtitle}
left={props => <List.Icon {...props} icon={icon}/>}
right={props =>
<Switch
value={this.state.nightMode}
onValueChange={onPressCallback}
/>}
/>
);
}
render() {
const nav = this.props.navigation;
return (
<Container>
<CustomHeader navigation={nav} title={i18n.t('screens.settings')} hasBackButton={true}/>
<Content padder>
<Card>
<CardItem header>
<Text>{i18n.t('settingsScreen.generalCard')}</Text>
</CardItem>
<List>
{this.getToggleItem(this.onToggleNightMode, 'theme-light-dark', i18n.t('settingsScreen.nightMode'), i18n.t('settingsScreen.nightModeSub'))}
{SettingsScreen.getGeneralItem(this.getStartScreenPicker(), 'power', i18n.t('settingsScreen.startScreen'), i18n.t('settingsScreen.startScreenSub'))}
</List>
</Card>
<Card>
<CardItem header>
<Text>Proxiwash</Text>
</CardItem>
<List>
{SettingsScreen.getGeneralItem(this.getProxiwashNotifPicker(), 'washing-machine', i18n.t('settingsScreen.proxiwashNotifReminder'), i18n.t('settingsScreen.proxiwashNotifReminderSub'))}
</List>
</Card>
</Content>
</Container>
<ScrollView>
<Card style={{margin: 5}}>
<Card.Title title={i18n.t('settingsScreen.generalCard')}/>
<List.Section>
{this.getToggleItem(
this.onToggleNightMode,
'theme-light-dark',
i18n.t('settingsScreen.nightMode'),
this.state.nightMode ?
i18n.t('settingsScreen.nightModeSubOn') :
i18n.t('settingsScreen.nightModeSubOff')
)}
<List.Accordion
title={i18n.t('settingsScreen.startScreen')}
description={i18n.t('settingsScreen.startScreenSub')}
left={props => <List.Icon {...props} icon="power"/>}
>
{this.getStartScreenPicker()}
</List.Accordion>
</List.Section>
</Card>
<Card style={{margin: 5}}>
<Card.Title title="Proxiwash"/>
<List.Section>
<List.Accordion
title={i18n.t('settingsScreen.proxiwashNotifReminder')}
description={i18n.t('settingsScreen.proxiwashNotifReminderSub')}
left={props => <List.Icon {...props} icon="washing-machine"/>}
>
{this.getProxiwashNotifPicker()}
</List.Accordion>
</List.Section>
</Card>
</ScrollView>
);
}
}

View file

@ -1,38 +0,0 @@
// @flow
import * as React from 'react';
import WebViewScreen from "../../components/WebViewScreen";
type Props = {
navigation: Object,
}
const URL = 'https://amicale-insat.fr/';
/**
* Class defining the app's planex screen.
* This screen uses a webview to render the planex page
*/
export default class AmicaleScreen extends React.Component<Props> {
render() {
const nav = this.props.navigation;
return (
<WebViewScreen
navigation={nav}
data={[
{
url: URL,
icon: '',
name: '',
customJS: ''
},
]}
headerTitle={'Amicale'}
hasHeaderBackButton={true}
hasSideMenu={false}/>
);
}
}

View file

@ -11,9 +11,7 @@ type Props = {
const ROOM_URL = 'http://planex.insa-toulouse.fr/salles.php';
const PC_URL = 'http://planex.insa-toulouse.fr/sallesInfo.php';
const BIB_URL = 'https://bibbox.insa-toulouse.fr/';
const CUSTOM_CSS_GENERAL = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/rooms/customMobile.css';
const CUSTOM_CSS_Bib = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/rooms/customBibMobile.css';
/**
* Class defining the app's planex screen.
@ -32,17 +30,6 @@ export default class AvailableRoomScreen extends React.Component<Props> {
'let header = $(".table tbody tr:first");' +
'$("table").prepend("<thead></thead>");true;' + // Fix for crash on ios
'$("thead").append(header);true;';
this.customBibInjectedJS =
'document.querySelector(\'head\').innerHTML += \'<meta name="viewport" content="width=device-width, initial-scale=1.0">\';' +
'document.querySelector(\'head\').innerHTML += \'<link rel="stylesheet" href="' + CUSTOM_CSS_Bib + '" type="text/css"/>\';' +
'if ($(".hero-unit-form").length > 0 && $("#customBackButton").length === 0)' +
'$(".hero-unit-form").append("' +
'<div style=\'width: 100%; display: flex\'>' +
'<a style=\'margin: auto\' href=\'' + BIB_URL + '\'>' +
'<button id=\'customBackButton\' class=\'btn btn-primary\'>Retour</button>' +
'</a>' +
'</div>");true;';
}
render() {
@ -63,12 +50,6 @@ export default class AvailableRoomScreen extends React.Component<Props> {
name: i18n.t('availableRoomScreen.computerRoom'),
customJS: this.customInjectedJS
},
{
url: BIB_URL,
icon: 'book',
name: i18n.t('availableRoomScreen.bibRoom'),
customJS: this.customBibInjectedJS
},
]}
customInjectedJS={this.customInjectedJS}
headerTitle={i18n.t('screens.availableRooms')}

View file

@ -0,0 +1,66 @@
// @flow
import * as React from 'react';
import WebViewScreen from "../../components/WebViewScreen";
import i18n from "i18n-js";
type Props = {
navigation: Object,
}
const BIB_URL = 'https://bibbox.insa-toulouse.fr/';
const CUSTOM_CSS_GENERAL = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/rooms/customMobile.css';
const CUSTOM_CSS_Bib = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/rooms/customBibMobile.css';
/**
* Class defining the app's planex screen.
* This screen uses a webview to render the planex page
*/
export default class AvailableRoomScreen extends React.Component<Props> {
customInjectedJS: string;
customBibInjectedJS: string;
constructor() {
super();
this.customInjectedJS =
'document.querySelector(\'head\').innerHTML += \'<meta name="viewport" content="width=device-width, initial-scale=1.0">\';' +
'document.querySelector(\'head\').innerHTML += \'<link rel="stylesheet" href="' + CUSTOM_CSS_GENERAL + '" type="text/css"/>\';' +
'let header = $(".table tbody tr:first");' +
'$("table").prepend("<thead></thead>");true;' + // Fix for crash on ios
'$("thead").append(header);true;';
this.customBibInjectedJS =
'document.querySelector(\'head\').innerHTML += \'<meta name="viewport" content="width=device-width, initial-scale=1.0">\';' +
'document.querySelector(\'head\').innerHTML += \'<link rel="stylesheet" href="' + CUSTOM_CSS_Bib + '" type="text/css"/>\';' +
'if ($(".hero-unit-form").length > 0 && $("#customBackButton").length === 0)' +
'$(".hero-unit-form").append("' +
'<div style=\'width: 100%; display: flex\'>' +
'<a style=\'margin: auto\' href=\'' + BIB_URL + '\'>' +
'<button id=\'customBackButton\' class=\'btn btn-primary\'>Retour</button>' +
'</a>' +
'</div>");true;';
}
render() {
const nav = this.props.navigation;
return (
<WebViewScreen
navigation={nav}
data={[
{
url: BIB_URL,
icon: 'book',
name: i18n.t('availableRoomScreen.bibRoom'),
customJS: this.customBibInjectedJS
},
]}
customInjectedJS={this.customInjectedJS}
headerTitle={i18n.t('screens.availableRooms')}
hasHeaderBackButton={true}
hasSideMenu={false}
hasFooter={false}/>
);
}
}

View file

@ -1,52 +0,0 @@
// @flow
import * as React from 'react';
import WebViewScreen from "../../components/WebViewScreen";
import i18n from "i18n-js";
type Props = {
navigation: Object,
}
const URL = 'https://etud-mel.insa-toulouse.fr/webmail/';
const CUSTOM_CSS_GENERAL = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/bluemind/customMobile.css';
/**
* Class defining the app's planex screen.
* This screen uses a webview to render the planex page
*/
export default class BlueMindScreen extends React.Component<Props> {
customInjectedJS: string;
constructor() {
super();
// Breaks website on ios
this.customInjectedJS = '';
// '$("head").append(\'<meta name="viewport" content="width=device-width, initial-scale=1.0">\');' +
// '$("head").append(\'<link rel="stylesheet" href="' + CUSTOM_CSS_GENERAL + '" type="text/css"/>\');true;';
}
render() {
const nav = this.props.navigation;
return (
<WebViewScreen
navigation={nav}
data={[
{
url: URL,
icon: '',
name: '',
customJS: this.customInjectedJS
},
]}
headerTitle={i18n.t('screens.bluemind')}
hasHeaderBackButton={true}
hasSideMenu={false}/>
);
}
}

View file

@ -1,38 +0,0 @@
// @flow
import * as React from 'react';
import WebViewScreen from "../../components/WebViewScreen";
type Props = {
navigation: Object,
}
const URL = 'https://etud.insa-toulouse.fr/~eeinsat/';
/**
* Class defining the app's planex screen.
* This screen uses a webview to render the planex page
*/
export default class ElusEtudScreen extends React.Component<Props> {
render() {
const nav = this.props.navigation;
return (
<WebViewScreen
navigation={nav}
data={[
{
url: URL,
icon: '',
name: '',
customJS: ''
},
]}
headerTitle={'Élus Étudiants'}
hasHeaderBackButton={true}
hasSideMenu={false}/>
);
}
}

View file

@ -1,90 +0,0 @@
// @flow
import * as React from 'react';
import WebViewScreen from "../../components/WebViewScreen";
import i18n from "i18n-js";
type Props = {
navigation: Object,
}
const URL = 'https://ent.insa-toulouse.fr/';
const CUSTOM_CSS_GENERAL = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/ent/customMobile.css';
// let stylesheet = document.createElement('link');
// stylesheet.type = 'text/css';
// stylesheet.rel = 'stylesheet';
// stylesheet.href = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/ent/customMobile.css';
// let mobileSpec = document.createElement('meta');
// mobileSpec.name = 'viewport';
// mobileSpec.content = 'width=device-width, initial-scale=1.0';
// document.getElementsByTagName('head')[0].appendChild(mobileSpec);
// // document.getElementsByTagName('head')[0].appendChild(stylesheet);
// document.getElementsByClassName('preference-items')[0].style.display = 'none';
// document.getElementsByClassName('logoInsa')[0].style.display = 'none';
// document.getElementsByClassName('logoPress')[0].style.display = 'none';
// document.getElementsByClassName('ent')[0].style.display = 'none';
// document.getElementById('portal-page-header').style.margin = 0;
// document.querySelectorAll('.uportal-navigation-category').forEach(element => {
// element.style.cssText = "width: 100%; display: flex; height: 50px;";
// if (element.children.length > 0)
// element.children[0].style.margin = 'auto';
// });
// true;
/**
* Class defining the app's ent screen.
* This screen uses a webview to render the ent page
*/
export default class EntScreen extends React.Component<Props> {
customInjectedJS: string;
constructor() {
super();
this.customInjectedJS =
'let stylesheet = document.createElement(\'link\');\n' +
'stylesheet.type = \'text/css\';\n' +
'stylesheet.rel = \'stylesheet\';\n' +
'stylesheet.href = \'' + CUSTOM_CSS_GENERAL + '\';\n' +
'let mobileSpec = document.createElement(\'meta\');\n' +
'mobileSpec.name = \'viewport\';\n' +
'mobileSpec.content = \'width=device-width, initial-scale=1.0\';\n' +
'document.getElementsByTagName(\'head\')[0].appendChild(mobileSpec);\n' +
'document.getElementsByTagName(\'head\')[0].appendChild(stylesheet);\n' +
'document.getElementsByClassName(\'preference-items\')[0].style.display = \'none\';\n' +
'document.getElementsByClassName(\'logoInsa\')[0].style.display = \'none\';\n' +
'document.getElementsByClassName(\'logoPress\')[0].style.display = \'none\';\n' +
'document.getElementsByClassName(\'ent\')[0].style.display = \'none\';\n' +
'document.getElementById(\'portal-page-header\').style.margin = 0;\n' +
'document.querySelectorAll(\'.uportal-navigation-category\').forEach(element => {\n' +
' element.style.cssText = "width: 100%; display: flex; height: 50px;";\n' +
' if (element.children.length > 0)\n' +
' element.children[0].style.margin = \'auto\';\n' +
'});' +
'true;';
}
render() {
const nav = this.props.navigation;
return (
<WebViewScreen
navigation={nav}
data={[
{
url: URL,
icon: '',
name: '',
customJS: this.customInjectedJS
},
]}
headerTitle={i18n.t('screens.ent')}
hasHeaderBackButton={true}
hasSideMenu={false}/>
);
}
}

View file

@ -3,11 +3,19 @@
import * as React from 'react';
import ThemeManager from "../../utils/ThemeManager";
import WebViewScreen from "../../components/WebViewScreen";
import {Avatar, Banner} from "react-native-paper";
import i18n from "i18n-js";
import {View} from "react-native";
import AsyncStorageManager from "../../utils/AsyncStorageManager";
type Props = {
navigation: Object,
}
type State = {
bannerVisible: boolean,
}
const PLANEX_URL = 'http://planex.insa-toulouse.fr/';
@ -75,9 +83,11 @@ const OBSERVE_MUTATIONS_INJECTED =
* Class defining the app's planex screen.
* This screen uses a webview to render the planex page
*/
export default class PlanexScreen extends React.Component<Props> {
export default class PlanexScreen extends React.Component<Props, State> {
customInjectedJS: string;
onHideBanner: Function;
onGoToSettings: Function;
constructor() {
super();
@ -93,26 +103,70 @@ export default class PlanexScreen extends React.Component<Props> {
this.customInjectedJS +=
'removeAlpha();' +
'});true;'; // Prevent crash on ios
this.onHideBanner = this.onHideBanner.bind(this);
this.onGoToSettings = this.onGoToSettings.bind(this);
}
state = {
bannerVisible:
AsyncStorageManager.getInstance().preferences.planexShowBanner.current === '1' &&
AsyncStorageManager.getInstance().preferences.defaultStartScreen.current !== 'Planex',
};
onHideBanner() {
this.setState({bannerVisible: false});
AsyncStorageManager.getInstance().savePref(
AsyncStorageManager.getInstance().preferences.planexShowBanner.key,
'0'
);
}
onGoToSettings() {
this.onHideBanner();
this.props.navigation.navigate('SettingsScreen');
}
render() {
const nav = this.props.navigation;
return (
<WebViewScreen
navigation={nav}
data={[
{
url: PLANEX_URL,
icon: '',
name: '',
customJS: this.customInjectedJS
},
]}
customInjectedJS={this.customInjectedJS}
headerTitle={'Planex'}
hasHeaderBackButton={false}
hasFooter={false}/>
<View style={{
height: '100%'
}}>
<Banner
visible={this.state.bannerVisible}
actions={[
{
label: i18n.t('planexScreen.enableStartOK'),
onPress: this.onGoToSettings,
},
{
label: i18n.t('planexScreen.enableStartCancel'),
onPress: this.onHideBanner,
},
]}
icon={() => <Avatar.Icon
icon={'information'}
size={40}
/>}
>
{i18n.t('planexScreen.enableStartScreen')}
</Banner>
<WebViewScreen
navigation={nav}
data={[
{
url: PLANEX_URL,
icon: '',
name: '',
customJS: this.customInjectedJS
},
]}
customInjectedJS={this.customInjectedJS}
headerTitle={'Planex'}
hasHeaderBackButton={false}
hasFooter={false}/>
</View>
);
}
}

View file

@ -1,38 +0,0 @@
// @flow
import * as React from 'react';
import WebViewScreen from "../../components/WebViewScreen";
type Props = {
navigation: Object,
}
const URL = 'https://www.etud.insa-toulouse.fr/~tutorinsa/';
/**
* Class defining the app's planex screen.
* This screen uses a webview to render the planex page
*/
export default class TutorInsaScreen extends React.Component<Props> {
render() {
const nav = this.props.navigation;
return (
<WebViewScreen
navigation={nav}
data={[
{
url: URL,
icon: '',
name: '',
customJS: ''
},
]}
headerTitle={'Tutor\'INSA'}
hasHeaderBackButton={true}
hasSideMenu={false}/>
);
}
}

View file

@ -1,38 +0,0 @@
// @flow
import * as React from 'react';
import WebViewScreen from "../../components/WebViewScreen";
type Props = {
navigation: Object,
}
const URL = 'https://wiki.etud.insa-toulouse.fr/';
/**
* Class defining the app's planex screen.
* This screen uses a webview to render the planex page
*/
export default class WiketudScreen extends React.Component<Props> {
render() {
const nav = this.props.navigation;
return (
<WebViewScreen
navigation={nav}
data={[
{
url: URL,
icon: '',
name: '',
customJS: ''
},
]}
headerTitle={'Wiketud'}
hasHeaderBackButton={true}
hasSideMenu={false}/>
);
}
}

View file

@ -8,6 +8,7 @@
"menuSelf": "RU Menu",
"settings": "Settings",
"availableRooms": "Available rooms",
"bib": "Bib'Box",
"bluemind": "INSA Mails",
"ent": "INSA ENT",
"about": "About",
@ -60,21 +61,12 @@
"settingsScreen": {
"generalCard": "General",
"nightMode": "Night Mode",
"nightModeSub": "Switch the app to a dark or light theme",
"nightModeSubOn": "Your eyes are at peace",
"nightModeSubOff": "Your eyes are burning",
"startScreen": "Start Screen",
"startScreenSub": "Select which screen to start the app on",
"proxiwashNotifReminder": "Machine running reminder",
"proxiwashNotifReminderSub": "Choose when to send a notification to remind you a machine is running with your laundry",
"proxiwashNotifReminderPicker": {
"never": "Never",
"1": "1 min",
"2": "2 min",
"3": "3 min",
"5": "5 min",
"10": "10 min",
"20": "20 min",
"30": "30 min"
}
"proxiwashNotifReminderSub": "How many minutes before"
},
"homeScreen": {
"listUpdated": "List updated!",
@ -131,7 +123,9 @@
"article": "Article",
"articles": "Articles",
"sortName": "Sort by name",
"sortNameReverse": "Sort by name (reverse)",
"sortPrice": "Sort by price",
"sortPriceReverse": "Sort by price (reverse)",
"listUpdated": "Article list updated!",
"listUpdateFail": "Error while updating article list",
"loading": "Loading...",
@ -167,6 +161,8 @@
"dryerTips": "The advised dryer length is 35 minutes for 14 kg of laundry. You can choose a shorter length if the dryer is not fully charged.",
"procedure": "Procedure",
"tips": "Tips",
"enableNotificationsTip": "Click on a running machine to enable notifications",
"numAvailable": "available",
"modal": {
"enableNotifications": "Notify me",
"disableNotifications": "Stop notifications",
@ -195,8 +191,9 @@
}
},
"planexScreen": {
"rotateToLandscape": "Turn your screen to see the whole week",
"rotateToPortrait": "Turn your screen to see only 2 days"
"enableStartScreen": "Come here often? Set it as default screen!",
"enableStartOK": "Yes please!",
"enableStartCancel": "Later"
},
"availableRoomScreen": {
"normalRoom": "Work",

View file

@ -8,6 +8,7 @@
"menuSelf": "Menu du RU",
"settings": "Paramètres",
"availableRooms": "Salles dispo",
"bib": "Bib'Box",
"bluemind": "Mails INSA",
"ent": "ENT INSA",
"about": "À Propos",
@ -60,21 +61,12 @@
"settingsScreen": {
"generalCard": "Général",
"nightMode": "Mode Nuit",
"nightModeSub": "Passer l'application dans un thème sombre ou clair",
"nightModeSubOn": "Vos yeux brulent",
"nightModeSubOff": "Vos yeux vous remercient",
"startScreen": "Écran de démarrage",
"startScreenSub": "Choisissez l'écran utilisé au démarrage",
"proxiwashNotifReminder": "Rappel de machine en cours",
"proxiwashNotifReminderSub": "Choississez quand envoyer une notification pour vous rappeler qu'une machine avec votre linge est en cours",
"proxiwashNotifReminderPicker": {
"never": "Jamais",
"1": "1 min",
"2": "2 min",
"3": "3 min",
"5": "5 min",
"10": "10 min",
"20": "20 min",
"30": "30 min"
}
"proxiwashNotifReminderSub": "Combien de minutes avant"
},
"homeScreen": {
"listUpdated": "List mise à jour!",
@ -131,7 +123,9 @@
"article": "Article",
"articles": "Articles",
"sortName": "Trier par nom",
"sortNameReverse": "Trier par nom (inversé)",
"sortPrice": "Trier par prix",
"sortPriceReverse": "Trier par prix (inversé)",
"listUpdated": "Liste d'articles mise à jour !",
"listUpdateFail": "Erreur lors de la mise à jour de la list d'articles",
"loading": "Chargement...",
@ -167,7 +161,8 @@
"dryerTips": "La durée conseillée est de 35 minutes pour 14kg de linge. Vous pouvez choisir une durée plus courte si le sèche-linge n'est pas chargé.",
"procedure": "Procédure",
"tips": "Conseils",
"enableNotificationsTip": "Cliquez sur une machine en cours pour activer les notifications",
"numAvailable": "disponibles",
"modal": {
"enableNotifications": "Me Notifier",
"disableNotifications": "Désactiver les notifications",
@ -197,8 +192,9 @@
}
},
"planexScreen": {
"rotateToLandscape": "Tournez votre téléphone pour voir la semaine entière",
"rotateToPortrait": "Tournez votre téléphone pour voir seulement 2 jours"
"enableStartScreen": "Vous venez souvent ici ? Démarrez l'appli sur cette page!",
"enableStartOK": "Oui svp!",
"enableStartCancel": "Plus tard"
},
"availableRoomScreen": {
"normalRoom": "Travail",

View file

@ -63,7 +63,17 @@ export default class AsyncStorageManager {
key: 'defaultStartScreen',
default: 'Home',
current: '',
}
},
proxiwashShowBanner: {
key: 'proxiwashShowBanner',
default: '1',
current: '',
},
planexShowBanner: {
key: 'planexShowBanner',
default: '1',
current: '',
},
};
/**

View file

@ -123,7 +123,10 @@ export default class NotificationsManager {
'Content-Type': 'application/json',
}),
body: JSON.stringify(data) // <-- Post parameters
});
}).then((response) => response.json())
.then((responseJson) => {
callback(responseJson);
});
}
}

View file

@ -1,10 +1,8 @@
// @flow
import platform from '../native-base-theme/variables/platform';
import platformDark from '../native-base-theme/variables/platformDark';
import getTheme from '../native-base-theme/components';
import AsyncStorageManager from "./AsyncStorageManager";
// import {DarkTheme as NavDarkTheme, DefaultTheme as NavDefaultTheme} from '@react-navigation/native';
import {DarkTheme, DefaultTheme} from 'react-native-paper';
/**
* Singleton class used to manage themes
*/
@ -17,6 +15,83 @@ export default class ThemeManager {
this.updateThemeCallback = null;
}
static getWhiteTheme() {
return {
...DefaultTheme,
colors: {
...DefaultTheme.colors,
primary: '#be1522',
accent: '#be1522',
tabIcon: "#929292",
card: "rgb(255, 255, 255)",
dividerBackground: '#e2e2e2',
textDisabled: '#c1c1c1',
icon: '#5d5d5d',
success: "#5cb85c",
warning: "#f0ad4e",
danger: "#d9534f",
// Calendar/Agenda
agendaBackgroundColor: '#f3f3f4',
agendaDayTextColor: '#636363',
// PROXIWASH
proxiwashFinishedColor: "#a5dc9d",
proxiwashReadyColor: "transparent",
proxiwashRunningColor: "#a0ceff",
proxiwashRunningBgColor: "#c7e3ff",
proxiwashBrokenColor: "#8e8e8e",
proxiwashErrorColor: "rgba(204,7,0,0.31)#e35f57",
// Screens
planningColor: '#d9b10a',
proximoColor: '#ec5904',
proxiwashColor: '#1fa5ee',
menuColor: '#e91314',
tutorinsaColor: '#f93943',
},
};
}
static getDarkTheme() {
return {
...DarkTheme,
colors: {
...DarkTheme.colors,
primary: '#be1522',
accent: '#be1522',
tabBackground: "#181818",
tabIcon: "#6d6d6d",
card: "rgb(18, 18, 18)",
dividerBackground: '#222222',
textDisabled: '#5b5b5b',
icon: '#b3b3b3',
success: "#5cb85c",
warning: "#f0ad4e",
danger: "#d9534f",
// Calendar/Agenda
agendaBackgroundColor: '#171717',
agendaDayTextColor: '#6d6d6d',
// PROXIWASH
proxiwashFinishedColor: "#31682c",
proxiwashReadyColor: "transparent",
proxiwashRunningColor: "#213c79",
proxiwashRunningBgColor: "#1a2033",
proxiwashBrokenColor: "#656565",
proxiwashErrorColor: "#7e2e2f",
// Screens
planningColor: '#d99e09',
proximoColor: '#ec5904',
proxiwashColor: '#1fa5ee',
menuColor: '#b81213',
tutorinsaColor: '#f93943',
},
};
}
/**
* Get this class instance or create one if none is found
* @returns {ThemeManager}
@ -27,6 +102,32 @@ export default class ThemeManager {
ThemeManager.instance;
}
/**
* @returns {boolean} Night mode state
*/
static getNightMode(): boolean {
return AsyncStorageManager.getInstance().preferences.nightMode.current === '1';
}
/**
* Get the current theme based on night mode
* @returns {Object}
*/
static getCurrentTheme(): Object {
if (ThemeManager.getNightMode())
return ThemeManager.getDarkTheme();
else
return ThemeManager.getWhiteTheme();
}
/**
* Get the variables contained in the current theme
* @returns {Object}
*/
static getCurrentThemeVariables(): Object {
return ThemeManager.getCurrentTheme().colors;
}
/**
* Set the function to be called when the theme is changed (allows for general reload of the app)
* @param callback Function to call after theme change
@ -47,30 +148,4 @@ export default class ThemeManager {
this.updateThemeCallback();
}
/**
* @returns {boolean} Night mode state
*/
static getNightMode(): boolean {
return AsyncStorageManager.getInstance().preferences.nightMode.current === '1';
}
/**
* Get the current theme based on night mode
* @returns {Object}
*/
static getCurrentTheme(): Object {
if (ThemeManager.getNightMode())
return getTheme(platformDark);
else
return getTheme(platform);
}
/**
* Get the variables contained in the current theme
* @returns {Object}
*/
static getCurrentThemeVariables(): Object {
return ThemeManager.getCurrentTheme().variables;
}
};

View file

@ -1,4 +1,3 @@
import {Toast} from "native-base";
/**
* Class used to get json data from the web
@ -25,39 +24,10 @@ export default class WebDataManager {
let response = await fetch(this.FETCH_URL);
fetchedData = await response.json();
} catch (error) {
// console.log('Could not read FetchedData from server');
// console.log(error);
throw new Error('Could not read FetchedData from server');
}
this.lastDataFetched = fetchedData;
return fetchedData;
}
/**
* Detects if the fetched data is not an empty object
*
* @return
*/
isDataObjectValid(): boolean {
return Object.keys(this.lastDataFetched).length > 0;
}
/**
* Show a toast message depending on the validity of the fetched data
*
* @param successString
* @param errorString
*/
showUpdateToast(successString, errorString) {
let isSuccess = this.isDataObjectValid();
if (!isSuccess) {
Toast.show({
text: isSuccess ? successString : errorString,
buttonText: 'OK',
type: isSuccess ? "success" : "danger",
duration: 2000
});
}
}
}