Compare commits
No commits in common. "3d3444ed00f4d39f771b5189d3a2b9af791d99c7" and "e3e5dac314cd89b0b75c72c6c2d7a38d6209d265" have entirely different histories.
3d3444ed00
...
e3e5dac314
112 changed files with 8353 additions and 3471 deletions
92
App.js
92
App.js
|
|
@ -2,18 +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 {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 {AppLoading} from 'expo';
|
||||
import NotificationsManager from "./utils/NotificationsManager";
|
||||
import {Provider as PaperProvider} from 'react-native-paper';
|
||||
import AprilFoolsManager from "./utils/AprilFoolsManager";
|
||||
import Update from "./constants/Update";
|
||||
import ThemeManager from './utils/ThemeManager';
|
||||
|
||||
type Props = {};
|
||||
|
||||
|
|
@ -21,41 +19,39 @@ type State = {
|
|||
isLoading: boolean,
|
||||
showIntro: boolean,
|
||||
showUpdate: boolean,
|
||||
showAprilFools: boolean,
|
||||
currentTheme: ?Object,
|
||||
};
|
||||
|
||||
const Stack = createStackNavigator();
|
||||
|
||||
export default class App extends React.Component<Props, State> {
|
||||
|
||||
state = {
|
||||
isLoading: true,
|
||||
showIntro: true,
|
||||
showUpdate: true,
|
||||
showAprilFools: false,
|
||||
currentTheme: null,
|
||||
};
|
||||
|
||||
onIntroDone: Function;
|
||||
onUpdateTheme: Function;
|
||||
loadAssetsAsync: Function;
|
||||
onLoadFinished: Function;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
constructor(props: Object) {
|
||||
super(props);
|
||||
LocaleManager.initTranslations();
|
||||
this.onIntroDone = this.onIntroDone.bind(this);
|
||||
this.onUpdateTheme = this.onUpdateTheme.bind(this);
|
||||
SplashScreen.preventAutoHide();
|
||||
this.loadAssetsAsync = this.loadAssetsAsync.bind(this);
|
||||
this.onLoadFinished = this.onLoadFinished.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the theme
|
||||
* Updates the theme and clears the cache to force reloading the app colors. Need to edit shoutem theme for ti to work
|
||||
*/
|
||||
onUpdateTheme() {
|
||||
updateTheme() {
|
||||
this.setState({
|
||||
currentTheme: ThemeManager.getCurrentTheme()
|
||||
});
|
||||
this.setupStatusBar();
|
||||
clearThemeCache();
|
||||
}
|
||||
|
||||
setupStatusBar() {
|
||||
|
|
@ -75,38 +71,35 @@ export default class App extends React.Component<Props, State> {
|
|||
this.setState({
|
||||
showIntro: false,
|
||||
showUpdate: false,
|
||||
showAprilFools: false,
|
||||
});
|
||||
AsyncStorageManager.getInstance().savePref(AsyncStorageManager.getInstance().preferences.showIntro.key, '0');
|
||||
AsyncStorageManager.getInstance().savePref(AsyncStorageManager.getInstance().preferences.updateNumber.key, Update.number.toString());
|
||||
AsyncStorageManager.getInstance().savePref(AsyncStorageManager.getInstance().preferences.showAprilFoolsStart.key, '0');
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
await this.loadAssetsAsync();
|
||||
AsyncStorageManager.getInstance().savePref(AsyncStorageManager.getInstance().preferences.showUpdate5.key, '0');
|
||||
}
|
||||
|
||||
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'),
|
||||
});
|
||||
await AsyncStorageManager.getInstance().loadPreferences();
|
||||
ThemeManager.getInstance().setUpdateThemeCallback(this.onUpdateTheme);
|
||||
ThemeManager.getInstance().setUpdateThemeCallback(() => this.updateTheme());
|
||||
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,
|
||||
currentTheme: ThemeManager.getCurrentTheme(),
|
||||
showIntro: AsyncStorageManager.getInstance().preferences.showIntro.current === '1',
|
||||
showUpdate: AsyncStorageManager.getInstance().preferences.updateNumber.current !== Update.number.toString(),
|
||||
showAprilFools: AprilFoolsManager.getInstance().isAprilFoolsEnabled() && AsyncStorageManager.getInstance().preferences.showAprilFoolsStart.current === '1',
|
||||
showUpdate: AsyncStorageManager.getInstance().preferences.showUpdate5.current === '1'
|
||||
});
|
||||
// Status bar goes dark if set too fast
|
||||
setTimeout(this.setupStatusBar, 1000);
|
||||
SplashScreen.hide();
|
||||
setTimeout(this.setupStatusBar,
|
||||
1000
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -114,22 +107,25 @@ export default class App extends React.Component<Props, State> {
|
|||
*/
|
||||
render() {
|
||||
if (this.state.isLoading) {
|
||||
return null;
|
||||
} else if (this.state.showIntro || this.state.showUpdate || this.state.showAprilFools) {
|
||||
return <CustomIntroSlider
|
||||
onDone={this.onIntroDone}
|
||||
isUpdate={this.state.showUpdate && !this.state.showIntro}
|
||||
isAprilFools={this.state.showAprilFools && !this.state.showIntro}
|
||||
/>;
|
||||
} else {
|
||||
return (
|
||||
<PaperProvider theme={this.state.currentTheme}>
|
||||
<NavigationContainer theme={this.state.currentTheme}>
|
||||
<Stack.Navigator headerMode="none">
|
||||
<Stack.Screen name="Root" component={DrawerNavigator}/>
|
||||
</Stack.Navigator>
|
||||
</NavigationContainer>
|
||||
</PaperProvider>
|
||||
<AppLoading
|
||||
startAsync={this.loadAssetsAsync}
|
||||
onFinish={this.onLoadFinished}
|
||||
onError={console.warn}
|
||||
/>
|
||||
);
|
||||
}
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
62
README.md
62
README.md
|
|
@ -1,16 +1,13 @@
|
|||
# CAMPUS - Application pour l'Amicale
|
||||
# Application pour l'Amicale
|
||||
|
||||
Créée pendant l'été 2019, cette application compatible Android et iOS permet aux étudiants d'avoir un accès facile aux informations du campus :
|
||||
- News de l'amicale
|
||||
- État des machines à laver
|
||||
- Liste des événements sur le campus
|
||||
- Stock du Proximo
|
||||
- Emploi du temps
|
||||
- Menu du RU
|
||||
- Disponibilité des salles libre accès
|
||||
- Réservation des Bib'Box
|
||||
|
||||
Ce dépot contient la source de cette application, modifiable par les étudiants de l'INSA Toulouse, sous licence GPLv3.
|
||||
|
||||
Ce dépot contient les sources de cette application, modifiable par les étudiants de l'INSA Toulouse, sous licence GPLv3.
|
||||
|
||||
## Contribuer
|
||||
|
||||
|
|
@ -18,52 +15,46 @@ Vous voulez influencer le développement ? C'est très simple !
|
|||
|
||||
Pas besoin de connaissance, il est possible d'aider simplement en proposant des améliorations ou en rapportant des bugs par mail (vergnet@etud.insa-toulouse.fr) ou sur [cette page](https://git.etud.insa-toulouse.fr/vergnet/application-amicale/issues), en vous connectant avec vos login INSA.
|
||||
|
||||
Si vous avez assez de connaissances et vous souhaitez proposer des modification dans le code, installez l'application sur votre machine, réalisez votre modification et créez une 'pull request'.
|
||||
Si vous avez assez de connaissances et vous souhaitez proposer des modifications dans le code, installez l'application sur votre machine, réalisez votre modification et créez une 'pull request'.
|
||||
|
||||
## Technologies Utilisées
|
||||
Cette application est faite en JavaScript avec React Native (framework Open Source créé par Facebook), combinée avec Expo.
|
||||
|
||||
Cette combinaison permet de n'avoir qu'un seul code JavaScript à écrire pour Android et iOS. Pour compiler pour la plateforme souhaitée, il suffit d'effectuer une commande, qui envoie le code sur les serveurs d'Expo pour compilation (voir section Installer). Plus besoin de Mac pour développer une application iOS ! (Mais toujours besoin d'un pour publier sur l'App store...)
|
||||
Cette combinaison permet de n'avoir qu'un seul code JavaScript à écrire pour Android et iOS. Pour compiler pour la plateforme souhaitée, il suffit d'effectuer une commande, qui envoie le code sur les serveurs d'Expo pour compilation (voir section Installer). Plus besoin de Mac pour développer une application iOS !
|
||||
|
||||
|
||||
## Installer l'application depuis ce dépot
|
||||
|
||||
**Avant de commencer, installez git, node et npm sur votre machine, puis clonez ce dépot.**
|
||||
**Avant de commencer, installez git et npm sur votre machine, puis clonez ce dépot.**
|
||||
|
||||
### Téléchargement du dépot et des dépendances
|
||||
|
||||
Il est conseillé d'utiliser un logiciel comme **PHPStorm** (logiciel pro gratuit pour les étudiants) pour éditer l'application car ce logiciel est compatible avec les technologies utilisées.
|
||||
|
||||
Une fois le dépot sur votre machine, ouvrez le projet dans PHPStorm, ouvrez le terminal et tapez `npm install`. Ceci installera toutes les dépendances listées dans le fichier _package.json_. Cette opération peut prendre quelques minutes et utilisera beaucoup d'espace disque (plus de 300Mo).
|
||||
Une fois le dépot sur votre machine, ouvrez le projet dans PHPStorm, ouvrez le terminal et tapez `npm install`. Ceci installera toutes les dépendances listées dans le fichier _package.json_. Cette opération peut prendre quelques minutes et utilisera beaucoup d'espace disque (plus de 400Mo).
|
||||
|
||||
### Lancement de l'appli
|
||||
**--> /!\ Pour pouvoir changer de mode nuit/jour dynamiquement sans redémarrer l'application, j'ai été obligé de modifier une librairie. Il est possible que l'appplication plante si vous ne refaites pas les modifications vous même /!\ <--**
|
||||
|
||||
#### En console
|
||||
Ceci est temporaire (on espère), car cette modification devrait être implémentée dans la librairie originale (un jour...).
|
||||
|
||||
Ouvrez simplement une console dans le répertoire du projet et tapez :
|
||||
En attendant, allez dans le dossier de la librairie **native-base-shoutem-theme**, et ouvrez le fichier _index.js_ et _src/connectStyle.js_. Ensuite, faites les modifications [comme indiqué ici](https://github.com/GeekyAnts/theme/pull/5/files/91f67c55ca6e65fe3af779586b506950c9f331be#diff-4cfc2dd4d5dae7954012899f2268a422).
|
||||
|
||||
`expo start`
|
||||
Ces modifications ont été acceptées dans la librairie originale, mais pas encore présentes dans la version sur npm.
|
||||
|
||||
Cette commande va démarrer le Metro Bundler permettant de lancer l'appli. Attendez quelques instants, quand un QR code apparait, l'application est prête à être lancée sur votre téléphone.
|
||||
### Paramétrage de PHPStorm
|
||||
|
||||
**Ne stoppez pas le Metro Bundler dans la console a chaque changement !** Toutes les modifications sont appliquées automatiquement, pas besoin de stopper et de redémarrer pour des petits changements ! Il est seulement nécessaire de redémarrer le Metro Bundler quand vous changez des librairies ou des fichiers.
|
||||
|
||||
#### Directement avec PHPStorm
|
||||
|
||||
Si vous n'aimez pas la console et voulez utiliser le merveilleux bouton play de PHPStorm, il faut le paramétrer. Nous utilisons ici expo, il faut donc dire à PHPStorm de lancer une commande expo quand nous cliquons sur le bouton play.
|
||||
Il faut maintenant paramétrer PHPStorm pour pouvoir lancer facilement l'application. Nous utilisons ici expo, il faut donc dire à PHPStorm de lancer une commande expo quand nous cliquons sur le bouton play.
|
||||
|
||||
Pour cela, cliquez sur **Edit Configurations** en haut à droite, dans la nouvelle fenêtre, cliquez sur **+**, et choisissez **React Native**.
|
||||
|
||||
Donnez un petit nom à cette configuration, décochez **Build and launch application** (nous utilisons expo pour ça, pas react native), mettez `127.0.0.1` dans le champ **Bundler Host**, et `19001` dans **Bundler Port**.
|
||||
|
||||
Ensuite, dans **Before Launch**; cliquez sur **+** pour ajouter une nouvelle configuration, et choisissez **Start React Native Bundler** si il n'est pas déjà présent. Une fois ajouté, cliquez dessus, puis sur le bouton éditer (une icone de crayon). Dans la nouvelle fenetre, choisissez **npm script** dans le champ **Command** et **start** dans **Script**. Vérifiez que vous utilisez bien l'interpreteur Node associé au projet (pour utiliser les bonnes dépendances installées précédement), et cliquez sur OK.
|
||||
Ensuite, dans **Before Launch**; cliquez sur **+** pour ajouter une nouvelle configuration, et choisissez **Start React Native Bundler** si il n'est pas déjà présent. Une fois ajouté, cliquez dessus, puis sur le bouton éditer (une icone de crayon). Dans la nouvelle fenêtre, choisissez **npm script** dans le champ **Command** et **start** dans **Script**. Vérifiez que vous utilisez bien l'interpreteur Node associé au projet (pour utiliser les bonnes dépendances installées précédement), et cliquez sur OK.
|
||||
|
||||
[Plus d'informations ici](https://www.jetbrains.com/help/phpstorm/react-native.html)
|
||||
|
||||
Le projet est maintenant pret, quand vous cliquez sur run (ou shift+F10), le projet sera lancé (cela peut prendre plusieurs minutes).
|
||||
Quand un QR code apparait, vous pouvez tester sur un appareil.
|
||||
|
||||
**Ne stoppez pas le Metro Bundler dans la console a chaque changement !** Toutes les modifications sont appliquées automatiquement, pas besoin de stopper et de redémarrer pour des petits changements ! Il est seulement nécessaire de redémarrer le Metro Bundler quand vous changez des librairies ou des fichiers.
|
||||
Le projet est maintenant prêt, quand vous cliquez sur run (ou shift+F10), le projet sera lancé (cela peut prendre plusieurs minutes).
|
||||
Une fois lancé, vous pouvez tester sur un appareil.
|
||||
|
||||
### Tester sur un appareil
|
||||
|
||||
|
|
@ -71,24 +62,21 @@ Assurez vous d'avoir installé et lancé le projet comme expliqué plus haut.
|
|||
|
||||
#### Émulateur android
|
||||
|
||||
[Suivez la procédure sur ce lien pour installer un émulateur](https://docs.expo.io/versions/latest/workflow/android-studio-emulator/).
|
||||
[Suivez la procédure sur ce lien](https://docs.expo.io/versions/latest/workflow/android-studio-emulator/).
|
||||
|
||||
Une fois l'emulateur installé et démarré, lancez le projet, puis appuyez sur la touche **a** dans la console, cela lancera l'aplication dans l'émulateur.
|
||||
Une fois l'emulateur installé et démarré, lancez le projet, puis appuyez sur la touche **a** dans la console _Run_, cela lancera l'aplication dans l'émulateur.
|
||||
|
||||
**Ne stoppez pas l'application depuis PhpStorm ! Toutes les modifications sont appliquées automatiquement, pas besoin de stopper et de redémarrer !**
|
||||
|
||||
#### Appareil Physique
|
||||
|
||||
Installez l'application **Expo** sur votre appareil (android ou iOS), assurez vous d'avoir démarré le projet et d'avoir votre machine de développement et le téléphone sur le même réseau wifi (non publique). Ouvrez l'application expo, Votre projet devrait apparaitre dans la liste. Cliquez dessus et c'est bon !
|
||||
Installez l'application **Expo** sur votre appareil (android ou iOS), assurez vous d'avoir démarré le projet et d'avoir votre machine de développement et le téléphone sur le même réseau wifi (non public). Ouvrez l'application expo, votre projet devrait apparaitre dans la liste. Cliquez dessus et c'est bon !
|
||||
|
||||
**Ne stoppez pas l'application depuis PhpStorm ! Toutes les modifications sont appliquées automatiquement, pas besoin de stopper et de redémarrer !**
|
||||
|
||||
Si vous utilisez le réseau Wifirst des résidences INSA (ou tout autre wifi publique), il y a une méthode très simple pour créer un réseau privé entre votre PC et votre téléphone (en tout cas avec un téléphone android). Connectez votre téléphone en Wifi au réseau, puis connectez le en USB à votre PC. Une fois connecté, allez dans les paramètres et activez le "USB Tethering". Votre PC est maintenant connecté en réseau filaire à votre téléphone, qui lui est connecté à Internet par la wifi. Si vous voulez connecter d'autres appareils, il suffit de créer un Hotspot sur votre PC et de connecter vos autres appareils à ce Hotspot. Profitez de votre réseau privé dans votre Promolo !
|
||||
|
||||
## Compilation
|
||||
|
||||
Avant de compiler, créez vous un compte Expo. Ensuite, lancez le Metro Bundler et connectez vous a votre compte dans la console (les touches sont indiquées).
|
||||
Pour compiler sur android, tapez la commande `expo build:android` dans une terminal dans le projet. Ensuite attendez.
|
||||
|
||||
Pour compiler sur android, vous avez deux solutions:
|
||||
- Vous voulez générer un `.apk` pour pour l'installer sur votre téléphone, lancez cette commande dans un terminal dans le projet : `expo build:android`. Cette commande va générer les paquets nécessaires à Expo et les envoyer sur leurs serveurs. Ne touchez à rien pendant la création des paquets (cela peut prendre une à deux minutes). Une fois que vous voyez écrit `Build in progress...`, vous pouvez fermer votre console : les serveurs ont pris la main et vous avez un lien pour analyser la progression. Ce processus dure en général 8 minutes. Si vous ne fermez pas la console, vous aurez un lien direct pour télécharger le fichier `.apk`, sinon connectez vous sur votre compte Expo, rubrique Builds pour le télécharger.
|
||||
|
||||
- Vous voulez compiler pour ensuite publier sur le Play Store, lancez cette commande dans un terminal dans le projet : `expo build:android -t app-bundle`. Cette commande fait exactement la même chose que la précédente à une chose près. Vous obtiendre un fichier `.aab`, qui est un format optimisé pour le Play Store. Ce fichier est plus volumineux mais permet au Play Store de générer les apk les plus optimisés possible pour différentes architectures de téléphone.
|
||||
|
||||
|
||||
Pou compiler sur iOS, vous aurez besoin du compte développeur de l'amicale car un tel compte est payant.
|
||||
Pou compiler sur iOS, vous aurez besoin du compte développeur de l'amicale.
|
||||
|
|
|
|||
5
app.json
5
app.json
|
|
@ -10,10 +10,9 @@
|
|||
"android",
|
||||
"web"
|
||||
],
|
||||
"version": "2.0.0",
|
||||
"version": "1.5.1",
|
||||
"orientation": "portrait",
|
||||
"primaryColor": "#be1522",
|
||||
"userInterfaceStyle": "automatic",
|
||||
"icon": "./assets/android.icon.png",
|
||||
"splash": {
|
||||
"backgroundColor": "#be1522",
|
||||
|
|
@ -37,7 +36,7 @@
|
|||
},
|
||||
"android": {
|
||||
"package": "fr.amicaleinsat.application",
|
||||
"versionCode": 16,
|
||||
"versionCode": 14,
|
||||
"icon": "./assets/android.icon.png",
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/android.adaptive-icon.png",
|
||||
|
|
|
|||
143
components/BaseContainer.js
Normal file
143
components/BaseContainer.js
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
// @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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
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);
|
||||
150
components/CustomHeader.js
Normal file
150
components/CustomHeader.js
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
// @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(),
|
||||
},
|
||||
});
|
||||
|
|
@ -3,11 +3,10 @@
|
|||
import * as React from 'react';
|
||||
import {LinearGradient} from "expo-linear-gradient";
|
||||
import {Image, StyleSheet, View} from "react-native";
|
||||
import {MaterialCommunityIcons} from "@expo/vector-icons";
|
||||
import {Text} from "react-native-paper";
|
||||
import CustomMaterialIcon from "./CustomMaterialIcon";
|
||||
import {Text} from "native-base";
|
||||
import i18n from 'i18n-js';
|
||||
import AppIntroSlider from "react-native-app-intro-slider";
|
||||
import Update from "../constants/Update";
|
||||
|
||||
// Content to be used int the intro slides
|
||||
|
||||
|
|
@ -40,15 +39,13 @@ const styles = StyleSheet.create({
|
|||
|
||||
type Props = {
|
||||
onDone: Function,
|
||||
isUpdate: boolean,
|
||||
isAprilFools: boolean,
|
||||
isUpdate: boolean
|
||||
};
|
||||
|
||||
export default class CustomIntroSlider extends React.Component<Props> {
|
||||
|
||||
introSlides: Array<Object>;
|
||||
updateSlides: Array<Object>;
|
||||
aprilFoolsSlides: Array<Object>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
|
@ -106,21 +103,12 @@ export default class CustomIntroSlider extends React.Component<Props> {
|
|||
this.updateSlides = [
|
||||
{
|
||||
key: '1',
|
||||
title: Update.getInstance().title,
|
||||
text: Update.getInstance().description,
|
||||
icon: Update.icon,
|
||||
title: i18n.t('intro.updateSlide.title'),
|
||||
text: i18n.t('intro.updateSlide.text'),
|
||||
icon: 'email',
|
||||
colors: ['#e01928', '#be1522'],
|
||||
},
|
||||
];
|
||||
this.aprilFoolsSlides = [
|
||||
{
|
||||
key: '1',
|
||||
title: i18n.t('intro.aprilFoolsSlide.title'),
|
||||
text: i18n.t('intro.aprilFoolsSlide.text'),
|
||||
icon: 'fish',
|
||||
colors: ['#e01928', '#be1522'],
|
||||
},
|
||||
];
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -143,10 +131,7 @@ export default class CustomIntroSlider extends React.Component<Props> {
|
|||
>
|
||||
{item.image !== undefined ?
|
||||
<Image source={item.image} style={styles.image}/>
|
||||
: <MaterialCommunityIcons
|
||||
name={item.icon}
|
||||
color={'#fff'}
|
||||
size={200}/>}
|
||||
: <CustomMaterialIcon icon={item.icon} color={'#fff'} fontSize={200} width={200}/>}
|
||||
<View style={{marginTop: 20}}>
|
||||
<Text style={styles.title}>{item.title}</Text>
|
||||
<Text style={styles.text}>{item.text}</Text>
|
||||
|
|
@ -156,15 +141,10 @@ export default class CustomIntroSlider extends React.Component<Props> {
|
|||
}
|
||||
|
||||
render() {
|
||||
let slides = this.introSlides;
|
||||
if (this.props.isUpdate)
|
||||
slides = this.updateSlides;
|
||||
else if (this.props.isAprilFools)
|
||||
slides = this.aprilFoolsSlides;
|
||||
return (
|
||||
<AppIntroSlider
|
||||
renderItem={CustomIntroSlider.getIntroRenderItem}
|
||||
slides={slides}
|
||||
slides={this.props.isUpdate ? this.updateSlides : this.introSlides}
|
||||
onDone={this.props.onDone}
|
||||
bottomButton
|
||||
showSkipButton
|
||||
|
|
|
|||
61
components/CustomMaterialIcon.js
Normal file
61
components/CustomMaterialIcon.js
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// @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
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {withTheme} from 'react-native-paper';
|
||||
import {Modalize} from "react-native-modalize";
|
||||
|
||||
function CustomModal(props) {
|
||||
const { colors } = props.theme;
|
||||
return (
|
||||
<Modalize
|
||||
ref={props.onRef}
|
||||
adjustToContentHeight
|
||||
handlePosition={'inside'}
|
||||
modalStyle={{backgroundColor: colors.card}}
|
||||
handleStyle={{backgroundColor: colors.primary}}
|
||||
>
|
||||
{props.children}
|
||||
</Modalize>
|
||||
);
|
||||
}
|
||||
|
||||
export default withTheme(CustomModal);
|
||||
|
||||
249
components/DashboardItem.js
Normal file
249
components/DashboardItem.js
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {Body, Card, CardItem, H3, Left, Text, Thumbnail} from "native-base";
|
||||
import CustomMaterialIcon from "./CustomMaterialIcon";
|
||||
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;
|
||||
|
||||
type Props = {
|
||||
isAvailable: boolean,
|
||||
icon: string,
|
||||
color: string,
|
||||
title: string,
|
||||
subtitle: React.Node,
|
||||
clickAction: Function,
|
||||
isSquare: boolean,
|
||||
isSquareLeft: boolean,
|
||||
displayEvent: ?Object,
|
||||
}
|
||||
|
||||
export default class DashboardItem extends React.Component<Props> {
|
||||
static defaultProps = {
|
||||
isSquare: false,
|
||||
isSquareLeft: true,
|
||||
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
|
||||
* @return {Date}
|
||||
*/
|
||||
stringToDate(dateString: ?string): ?Date {
|
||||
let date = new Date();
|
||||
if (dateString === undefined || dateString === null)
|
||||
date = undefined;
|
||||
else if (dateString.split(' ').length > 1) {
|
||||
let timeStr = dateString.split(' ')[1];
|
||||
date.setHours(parseInt(timeStr.split(':')[0]), parseInt(timeStr.split(':')[1]), 0);
|
||||
} else
|
||||
date = undefined;
|
||||
return date;
|
||||
}
|
||||
|
||||
padStr(i: number) {
|
||||
return (i < 10) ? "0" + i : "" + i;
|
||||
}
|
||||
|
||||
getFormattedEventTime(event: Object): string {
|
||||
let formattedStr = '';
|
||||
let startDate = this.stringToDate(event['date_begin']);
|
||||
let endDate = this.stringToDate(event['date_end']);
|
||||
if (startDate !== undefined && startDate !== null && endDate !== undefined && endDate !== null)
|
||||
formattedStr = this.padStr(startDate.getHours()) + ':' + this.padStr(startDate.getMinutes()) +
|
||||
' - ' + this.padStr(endDate.getHours()) + ':' + this.padStr(endDate.getMinutes());
|
||||
else if (startDate !== undefined && startDate !== null)
|
||||
formattedStr = this.padStr(startDate.getHours()) + ':' + this.padStr(startDate.getMinutes());
|
||||
return formattedStr
|
||||
}
|
||||
|
||||
getEventPreviewContainer() {
|
||||
if (this.props.displayEvent !== undefined && this.props.displayEvent !== 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,
|
||||
overflow: 'hidden',
|
||||
}}>
|
||||
<HTML html={"<div>" + this.props.displayEvent['description'] + "</div>"}
|
||||
tagsStyles={{
|
||||
p: {
|
||||
color: ThemeManager.getCurrentThemeVariables().textColor,
|
||||
fontSize: ThemeManager.getCurrentThemeVariables().fontSizeBase,
|
||||
},
|
||||
div: {color: ThemeManager.getCurrentThemeVariables().textColor},
|
||||
}}/>
|
||||
<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',
|
||||
marginTop: 'auto',
|
||||
flexDirection: 'row'
|
||||
}}>
|
||||
<Text style={{
|
||||
marginTop: 'auto',
|
||||
marginBottom: 'auto',
|
||||
padding: 0,
|
||||
}}>
|
||||
{i18n.t("homeScreen.dashboard.seeMore")}
|
||||
</Text>
|
||||
<CustomMaterialIcon icon={'chevron-right'}/>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
</Body>
|
||||
</CardItem>
|
||||
</View>
|
||||
);
|
||||
} else
|
||||
return <View/>
|
||||
}
|
||||
|
||||
getIcon() {
|
||||
return (
|
||||
<CustomMaterialIcon
|
||||
icon={this.props.icon}
|
||||
color={
|
||||
this.props.isAvailable ?
|
||||
this.props.color :
|
||||
ThemeManager.getCurrentThemeVariables().textDisabledColor
|
||||
}
|
||||
fontSize={this.props.isSquare ? 50 : 40}
|
||||
width={this.props.isSquare ? 50 : 40}/>
|
||||
);
|
||||
}
|
||||
|
||||
getText() {
|
||||
return (
|
||||
<View style={{
|
||||
width: this.props.isSquare ? '100%' : 'auto',
|
||||
}}>
|
||||
<H3 style={{
|
||||
color: this.props.isAvailable ?
|
||||
ThemeManager.getCurrentThemeVariables().textColor :
|
||||
ThemeManager.getCurrentThemeVariables().listNoteColor,
|
||||
textAlign: this.props.isSquare ? 'center' : 'left',
|
||||
width: this.props.isSquare ? '100%' : 'auto',
|
||||
}}>
|
||||
{this.props.title}
|
||||
</H3>
|
||||
<Text style={{
|
||||
color: this.props.isAvailable ?
|
||||
ThemeManager.getCurrentThemeVariables().listNoteColor :
|
||||
ThemeManager.getCurrentThemeVariables().textDisabledColor,
|
||||
textAlign: this.props.isSquare ? 'center' : 'left',
|
||||
width: this.props.isSquare ? '100%' : 'auto',
|
||||
}}>
|
||||
{this.props.subtitle}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
getContent() {
|
||||
if (this.props.isSquare) {
|
||||
return (
|
||||
<Body>
|
||||
<View style={{marginLeft: 'auto', marginRight: 'auto'}}>
|
||||
{this.getIcon()}
|
||||
</View>
|
||||
{this.getText()}
|
||||
</Body>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Left>
|
||||
{this.getIcon()}
|
||||
<Body>
|
||||
{this.getText()}
|
||||
</Body>
|
||||
</Left>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
// console.log("rendering DashboardItem " + this.props.title);
|
||||
let marginRight = 10;
|
||||
if (this.props.isSquare) {
|
||||
if (this.props.isSquareLeft)
|
||||
marginRight = '4%';
|
||||
else
|
||||
marginRight = 0
|
||||
}
|
||||
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',
|
||||
}}
|
||||
>
|
||||
<View>
|
||||
<CardItem style={{
|
||||
backgroundColor: 'transparent',
|
||||
}}>
|
||||
{this.getContent()}
|
||||
</CardItem>
|
||||
{this.getEventPreviewContainer()}
|
||||
</View>
|
||||
</PlatformTouchable>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
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);
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {Avatar, Card, withTheme} from 'react-native-paper';
|
||||
|
||||
function EventDashBoardItem(props) {
|
||||
const {colors} = props.theme;
|
||||
const iconColor = props.isAvailable ?
|
||||
colors.planningColor :
|
||||
colors.textDisabled;
|
||||
const textColor = props.isAvailable ?
|
||||
colors.text :
|
||||
colors.textDisabled;
|
||||
return (
|
||||
<Card
|
||||
style={{
|
||||
width: 'auto',
|
||||
marginLeft: 10,
|
||||
marginRight: 10,
|
||||
marginTop: 10,
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
onPress={props.clickAction}>
|
||||
|
||||
<Card.Title
|
||||
title={props.title}
|
||||
titleStyle={{color: textColor}}
|
||||
subtitle={props.subtitle}
|
||||
subtitleStyle={{color: textColor}}
|
||||
left={() =>
|
||||
<Avatar.Icon
|
||||
icon={props.icon}
|
||||
color={iconColor}
|
||||
size={60}
|
||||
style={{backgroundColor: 'transparent'}}/>}
|
||||
/>
|
||||
<Card.Content>
|
||||
{props.children}
|
||||
</Card.Content>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default withTheme(EventDashBoardItem);
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
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 getAvatar() {
|
||||
return (
|
||||
<Avatar.Image size={48} source={ICON_AMICALE}
|
||||
style={{backgroundColor: 'transparent'}}/>
|
||||
);
|
||||
}
|
||||
|
||||
function FeedItem(props) {
|
||||
const {colors} = props.theme;
|
||||
return (
|
||||
<Card style={{margin: 10}}>
|
||||
<Card.Title
|
||||
title={props.title}
|
||||
subtitle={props.subtitle}
|
||||
left={getAvatar}
|
||||
/>
|
||||
{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);
|
||||
399
components/FetchedDataSectionList.js
Normal file
399
components/FetchedDataSectionList.js
Normal file
|
|
@ -0,0 +1,399 @@
|
|||
// @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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
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);
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {View} from "react-native";
|
||||
import HTML from "react-native-render-html";
|
||||
import i18n from "i18n-js";
|
||||
import {Avatar, Button, Card, withTheme} from 'react-native-paper';
|
||||
import PlanningEventManager from "../utils/PlanningEventManager";
|
||||
|
||||
|
||||
function PreviewEventDashboardItem(props) {
|
||||
const {colors} = props.theme;
|
||||
const isEmpty = props.event === undefined ? true : PlanningEventManager.isDescriptionEmpty(props.event['description']);
|
||||
if (props.event !== undefined && props.event !== null) {
|
||||
const hasImage = props.event['logo'] !== '' && props.event['logo'] !== null;
|
||||
const getImage = () => <Avatar.Image
|
||||
source={{uri: props.event['logo']}}
|
||||
size={50}
|
||||
style={{backgroundColor: 'transparent'}}/>;
|
||||
return (
|
||||
<Card
|
||||
style={{marginBottom: 10}}
|
||||
onPress={props.clickAction}
|
||||
elevation={3}
|
||||
>
|
||||
{hasImage ?
|
||||
<Card.Title
|
||||
title={props.event['title']}
|
||||
subtitle={PlanningEventManager.getFormattedEventTime(props.event)}
|
||||
left={getImage}
|
||||
/> :
|
||||
<Card.Title
|
||||
title={props.event['title']}
|
||||
subtitle={PlanningEventManager.getFormattedEventTime(props.event)}
|
||||
/>}
|
||||
{!isEmpty ?
|
||||
<Card.Content style={{
|
||||
maxHeight: 150,
|
||||
overflow: 'hidden',
|
||||
}}>
|
||||
<HTML html={"<div>" + props.event['description'] + "</div>"}
|
||||
tagsStyles={{
|
||||
p: {color: colors.text,},
|
||||
div: {color: colors.text},
|
||||
}}/>
|
||||
|
||||
</Card.Content> : null}
|
||||
|
||||
<Card.Actions style={{
|
||||
marginLeft: 'auto',
|
||||
marginTop: 'auto',
|
||||
flexDirection: 'row'
|
||||
}}>
|
||||
<Button
|
||||
icon={'chevron-right'}
|
||||
>
|
||||
{i18n.t("homeScreen.dashboard.seeMore")}
|
||||
</Button>
|
||||
</Card.Actions>
|
||||
</Card>
|
||||
);
|
||||
} else
|
||||
return <View/>
|
||||
}
|
||||
|
||||
export default withTheme(PreviewEventDashboardItem);
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import {Avatar, Card, 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}
|
||||
titleStyle={{fontSize: 17}}
|
||||
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);
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import {FlatList} from "react-native";
|
||||
|
||||
type Props = {
|
||||
data: Array<Object>,
|
||||
keyExtractor: Function,
|
||||
renderItem: Function,
|
||||
updateData: number,
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a pure component, meaning it will only update if a shallow comparison of state and props is different.
|
||||
* To force the component to update, change the value of updateData.
|
||||
*/
|
||||
export default class PureFlatList extends React.PureComponent<Props>{
|
||||
|
||||
static defaultProps = {
|
||||
updateData: null,
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<FlatList
|
||||
data={this.props.data}
|
||||
keyExtractor={this.props.keyExtractor}
|
||||
style={{minHeight: 300, width: '100%'}}
|
||||
renderItem={this.props.renderItem}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,18 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {Dimensions, FlatList, Image, Platform, StyleSheet, View} from 'react-native';
|
||||
import {Dimensions, FlatList, Image, Linking, Platform, StyleSheet} from 'react-native';
|
||||
import {Badge, Container, Left, ListItem, Right, Text} from "native-base";
|
||||
import i18n from "i18n-js";
|
||||
import * as WebBrowser from 'expo-web-browser';
|
||||
import SidebarDivider from "./SidebarDivider";
|
||||
import SidebarItem from "./SidebarItem";
|
||||
import CustomMaterialIcon from '../components/CustomMaterialIcon';
|
||||
import ThemeManager from "../utils/ThemeManager";
|
||||
|
||||
const deviceWidth = Dimensions.get("window").width;
|
||||
|
||||
const drawerCover = require("../assets/drawer-cover.png");
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
state: Object,
|
||||
};
|
||||
|
||||
type State = {
|
||||
|
|
@ -21,7 +22,7 @@ type State = {
|
|||
/**
|
||||
* Class used to define a navigation drawer
|
||||
*/
|
||||
export default class SideBar extends React.PureComponent<Props, State> {
|
||||
export default class SideBar extends React.Component<Props, State> {
|
||||
|
||||
dataSet: Array<Object>;
|
||||
|
||||
|
|
@ -41,18 +42,42 @@ export default class SideBar extends React.PureComponent<Props, State> {
|
|||
// Dataset used to render the drawer
|
||||
this.dataSet = [
|
||||
{
|
||||
name: i18n.t('screens.home'),
|
||||
route: "Main",
|
||||
icon: "home",
|
||||
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('sidenav.divider2'),
|
||||
route: "Divider2"
|
||||
},
|
||||
{
|
||||
name: i18n.t('screens.menuSelf'),
|
||||
route: "SelfMenuScreen",
|
||||
icon: "silverware-fork-knife",
|
||||
name: i18n.t('screens.bluemind'),
|
||||
route: "BlueMindScreen",
|
||||
icon: "email",
|
||||
},
|
||||
{
|
||||
name: i18n.t('screens.ent'),
|
||||
route: "EntScreen",
|
||||
icon: "notebook",
|
||||
},
|
||||
{
|
||||
name: i18n.t('screens.availableRooms'),
|
||||
|
|
@ -60,49 +85,9 @@ export default class SideBar extends React.PureComponent<Props, State> {
|
|||
icon: "calendar-check",
|
||||
},
|
||||
{
|
||||
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('screens.menuSelf'),
|
||||
route: "SelfMenuScreen",
|
||||
icon: "silverware-fork-knife",
|
||||
},
|
||||
{
|
||||
name: i18n.t('sidenav.divider3'),
|
||||
|
|
@ -122,11 +107,13 @@ export default class SideBar extends React.PureComponent<Props, State> {
|
|||
this.getRenderItem = this.getRenderItem.bind(this);
|
||||
}
|
||||
|
||||
onListItemPress(item: Object) {
|
||||
if (item.link === undefined)
|
||||
this.props.navigation.navigate(item.route);
|
||||
else
|
||||
WebBrowser.openBrowserAsync(item.link);
|
||||
shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
|
||||
return nextState.active !== this.state.active;
|
||||
}
|
||||
|
||||
|
||||
onListItemPress(route: string) {
|
||||
this.props.navigation.navigate(route);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -136,34 +123,66 @@ export default class SideBar extends React.PureComponent<Props, State> {
|
|||
|
||||
|
||||
getRenderItem({item}: Object) {
|
||||
const onListItemPress = this.onListItemPress.bind(this, item);
|
||||
const onListItemPress = this.onListItemPress.bind(this, item.route);
|
||||
|
||||
if (item.icon !== undefined) {
|
||||
return (
|
||||
<SidebarItem
|
||||
title={item.name}
|
||||
icon={item.icon}
|
||||
<ListItem
|
||||
button
|
||||
noBorder
|
||||
selected={this.state.active === item.route}
|
||||
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 (
|
||||
<SidebarDivider title={item.name}/>
|
||||
<ListItem itemDivider>
|
||||
<Text>{item.name}</Text>
|
||||
</ListItem>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
// console.log("rendering SideBar");
|
||||
return (
|
||||
<View style={{height: '100%'}}>
|
||||
<Image source={require("../assets/drawer-cover.png")} style={styles.drawerCover}/>
|
||||
<Container style={{
|
||||
backgroundColor: ThemeManager.getCurrentThemeVariables().sideMenuBgColor,
|
||||
}}>
|
||||
<Image source={drawerCover} style={styles.drawerCover}/>
|
||||
<FlatList
|
||||
data={this.dataSet}
|
||||
extraData={this.state}
|
||||
keyExtractor={this.listKeyExtractor}
|
||||
renderItem={this.getRenderItem}
|
||||
/>
|
||||
</View>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
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);
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
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);
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import {Badge, IconButton, withTheme} from 'react-native-paper';
|
||||
import {View} from "react-native";
|
||||
|
||||
function SquareDashboardItem(props) {
|
||||
const {colors} = props.theme;
|
||||
return (
|
||||
<View>
|
||||
<IconButton
|
||||
icon={props.icon}
|
||||
color={
|
||||
props.isAvailable ?
|
||||
props.color :
|
||||
colors.textDisabled
|
||||
}
|
||||
size={35}
|
||||
onPress={props.clickAction}
|
||||
/>
|
||||
{
|
||||
props.badgeNumber > 0 ?
|
||||
<Badge
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 5,
|
||||
right: 5
|
||||
}}>{props.badgeNumber}</Badge> : null
|
||||
}
|
||||
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
export default withTheme(SquareDashboardItem);
|
||||
|
|
@ -1,228 +0,0 @@
|
|||
// @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,
|
||||
autoRefreshTime: number,
|
||||
refreshOnFocus: boolean,
|
||||
renderItem: React.Node,
|
||||
renderSectionHeader: React.Node,
|
||||
stickyHeader: boolean,
|
||||
createDataset: Function,
|
||||
updateData: number,
|
||||
}
|
||||
|
||||
type State = {
|
||||
refreshing: boolean,
|
||||
firstLoading: boolean,
|
||||
fetchedData: Object,
|
||||
snackbarVisible: boolean
|
||||
};
|
||||
|
||||
|
||||
const MIN_REFRESH_TIME = 5 * 1000;
|
||||
/**
|
||||
* This is a pure component, meaning it will only update if a shallow comparison of state and props is different.
|
||||
* To force the component to update, change the value of updateData.
|
||||
*/
|
||||
export default class WebSectionList extends React.PureComponent<Props, State> {
|
||||
|
||||
static defaultProps = {
|
||||
renderSectionHeader: null,
|
||||
stickyHeader: false,
|
||||
updateData: null,
|
||||
};
|
||||
|
||||
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);
|
||||
this.onRefresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh data when focusing the screen and setup a refresh interval if asked to
|
||||
*/
|
||||
onScreenFocus() {
|
||||
if (this.props.refreshOnFocus && this.lastRefresh !== undefined)
|
||||
this.onRefresh();
|
||||
if (this.props.autoRefreshTime > 0)
|
||||
this.refreshInterval = setInterval(this.onRefresh, this.props.autoRefreshTime)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()) > MIN_REFRESH_TIME;
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {View} from 'react-native';
|
||||
import {Linking, Platform, View} from 'react-native';
|
||||
import {Body, Footer, Left, Right, Spinner, Tab, TabHeading, Tabs, Text} from 'native-base';
|
||||
import WebView from "react-native-webview";
|
||||
import {ActivityIndicator, withTheme} from 'react-native-paper';
|
||||
import HeaderButton from "./HeaderButton";
|
||||
import Touchable from "react-native-platform-touchable";
|
||||
import CustomMaterialIcon from "../components/CustomMaterialIcon";
|
||||
import ThemeManager from "../utils/ThemeManager";
|
||||
import BaseContainer from "../components/BaseContainer";
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
|
|
@ -23,80 +26,87 @@ type Props = {
|
|||
/**
|
||||
* Class defining a webview screen.
|
||||
*/
|
||||
class WebViewScreen extends React.PureComponent<Props> {
|
||||
export default class WebViewScreen extends React.Component<Props> {
|
||||
|
||||
static defaultProps = {
|
||||
hasBackButton: false,
|
||||
hasSideMenu: true,
|
||||
hasFooter: true,
|
||||
};
|
||||
webviewRef: Object;
|
||||
webviewArray: Array<WebView> = [];
|
||||
|
||||
onRefreshClicked: Function;
|
||||
onWebviewRef: Function;
|
||||
onGoBackWebview: Function;
|
||||
onGoForwardWebview: Function;
|
||||
getRenderLoading: Function;
|
||||
onOpenWebLink: Function;
|
||||
|
||||
colors: Object;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
constructor() {
|
||||
super();
|
||||
this.onRefreshClicked = this.onRefreshClicked.bind(this);
|
||||
this.onWebviewRef = this.onWebviewRef.bind(this);
|
||||
this.onGoBackWebview = this.onGoBackWebview.bind(this);
|
||||
this.onGoForwardWebview = this.onGoForwardWebview.bind(this);
|
||||
this.getRenderLoading = this.getRenderLoading.bind(this);
|
||||
this.colors = props.theme.colors;
|
||||
this.onOpenWebLink = this.onOpenWebLink.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const rightButton = this.getRefreshButton.bind(this);
|
||||
this.props.navigation.setOptions({
|
||||
headerRight: rightButton,
|
||||
});
|
||||
openWebLink(url: string) {
|
||||
Linking.openURL(url).catch((err) => console.error('Error opening link', err));
|
||||
}
|
||||
|
||||
getHeaderButton(clickAction: Function, icon: string) {
|
||||
return (
|
||||
<HeaderButton icon={icon} onPress={clickAction}/>
|
||||
<Touchable
|
||||
style={{padding: 6}}
|
||||
onPress={clickAction}>
|
||||
<CustomMaterialIcon
|
||||
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
|
||||
icon={icon}/>
|
||||
</Touchable>
|
||||
);
|
||||
}
|
||||
|
||||
getRefreshButton() {
|
||||
return (
|
||||
<View style={{
|
||||
flexDirection: 'row',
|
||||
marginRight: 10
|
||||
}}>
|
||||
<View style={{flexDirection: 'row'}}>
|
||||
{this.getHeaderButton(this.onRefreshClicked, 'refresh')}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
onRefreshClicked() {
|
||||
if (this.webviewRef !== null)
|
||||
this.webviewRef.reload();
|
||||
for (let view of this.webviewArray) {
|
||||
if (view !== null)
|
||||
view.reload();
|
||||
}
|
||||
}
|
||||
|
||||
onGoBackWebview() {
|
||||
if (this.webviewRef !== null)
|
||||
this.webviewRef.goBack();
|
||||
for (let view of this.webviewArray) {
|
||||
if (view !== null)
|
||||
view.goBack();
|
||||
}
|
||||
}
|
||||
|
||||
onGoForwardWebview() {
|
||||
if (this.webviewRef !== null)
|
||||
this.webviewRef.goForward();
|
||||
for (let view of this.webviewArray) {
|
||||
if (view !== null)
|
||||
view.goForward();
|
||||
}
|
||||
}
|
||||
|
||||
onWebviewRef(ref: Object) {
|
||||
this.webviewRef = ref
|
||||
onOpenWebLink() {
|
||||
this.openWebLink(this.props.data[0]['url'])
|
||||
}
|
||||
|
||||
onWebviewRef(ref: WebView) {
|
||||
this.webviewArray.push(ref)
|
||||
}
|
||||
|
||||
getRenderLoading() {
|
||||
return (
|
||||
<View style={{
|
||||
backgroundColor: this.colors.background,
|
||||
backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
right: 0,
|
||||
|
|
@ -106,31 +116,104 @@ class WebViewScreen extends React.PureComponent<Props> {
|
|||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}>
|
||||
<ActivityIndicator
|
||||
animating={true}
|
||||
size={'large'}
|
||||
color={this.colors.primary}/>
|
||||
<Spinner/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
// console.log("rendering WebViewScreen");
|
||||
getWebview(obj: Object) {
|
||||
return (
|
||||
<WebView
|
||||
ref={this.onWebviewRef}
|
||||
source={{uri: this.props.data[0]['url']}}
|
||||
source={{uri: obj['url']}}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
startInLoadingState={true}
|
||||
injectedJavaScript={this.props.data[0]['customJS']}
|
||||
injectedJavaScript={obj['customJS']}
|
||||
javaScriptEnabled={true}
|
||||
renderLoading={this.getRenderLoading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTheme(WebViewScreen);
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
export default {
|
||||
machineStates: {
|
||||
"TERMINE": "0",
|
||||
"DISPONIBLE": "1",
|
||||
"EN COURS": "2",
|
||||
"HS": "3",
|
||||
"ERREUR": "4"
|
||||
},
|
||||
};
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
import i18n from "i18n-js";
|
||||
|
||||
export default class Update {
|
||||
|
||||
static number = 5;
|
||||
static icon = 'surround-sound-2-0';
|
||||
|
||||
static instance: Update | null = null;
|
||||
|
||||
constructor() {
|
||||
this.title = i18n.t('intro.updateSlide.title');
|
||||
this.description = i18n.t('intro.updateSlide.text');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this class instance or create one if none is found
|
||||
* @returns {Update}
|
||||
*/
|
||||
static getInstance(): Update {
|
||||
return Update.instance === null ?
|
||||
Update.instance = new Update() :
|
||||
Update.instance;
|
||||
}
|
||||
|
||||
};
|
||||
39
native-base-theme/components/Badge.js
Normal file
39
native-base-theme/components/Badge.js
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// @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;
|
||||
};
|
||||
11
native-base-theme/components/Body.js
Normal file
11
native-base-theme/components/Body.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// @flow
|
||||
|
||||
export default () => {
|
||||
const bodyTheme = {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
alignSelf: 'center'
|
||||
};
|
||||
|
||||
return bodyTheme;
|
||||
};
|
||||
386
native-base-theme/components/Button.js
Normal file
386
native-base-theme/components/Button.js
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
// @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;
|
||||
};
|
||||
37
native-base-theme/components/Card.js
Normal file
37
native-base-theme/components/Card.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// @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;
|
||||
};
|
||||
198
native-base-theme/components/CardItem.js
Normal file
198
native-base-theme/components/CardItem.js
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
// @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;
|
||||
};
|
||||
38
native-base-theme/components/CheckBox.js
Normal file
38
native-base-theme/components/CheckBox.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// @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;
|
||||
};
|
||||
17
native-base-theme/components/Container.js
Normal file
17
native-base-theme/components/Container.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// @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;
|
||||
};
|
||||
14
native-base-theme/components/Content.js
Normal file
14
native-base-theme/components/Content.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// @flow
|
||||
|
||||
export default () => {
|
||||
const contentTheme = {
|
||||
flex: 1,
|
||||
backgroundColor: 'transparent',
|
||||
'NativeBase.Segment': {
|
||||
borderWidth: 0,
|
||||
backgroundColor: 'transparent'
|
||||
}
|
||||
};
|
||||
|
||||
return contentTheme;
|
||||
};
|
||||
25
native-base-theme/components/Fab.js
Normal file
25
native-base-theme/components/Fab.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// @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;
|
||||
};
|
||||
119
native-base-theme/components/Footer.js
Normal file
119
native-base-theme/components/Footer.js
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
// @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;
|
||||
};
|
||||
79
native-base-theme/components/FooterTab.js
Normal file
79
native-base-theme/components/FooterTab.js
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
// @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;
|
||||
};
|
||||
86
native-base-theme/components/Form.js
Normal file
86
native-base-theme/components/Form.js
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// @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;
|
||||
};
|
||||
13
native-base-theme/components/H1.js
Normal file
13
native-base-theme/components/H1.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// @flow
|
||||
|
||||
import variable from './../variables/platform';
|
||||
|
||||
export default (variables /* : * */ = variable) => {
|
||||
const h1Theme = {
|
||||
color: variables.textColor,
|
||||
fontSize: variables.fontSizeH1,
|
||||
lineHeight: variables.lineHeightH1
|
||||
};
|
||||
|
||||
return h1Theme;
|
||||
};
|
||||
13
native-base-theme/components/H2.js
Normal file
13
native-base-theme/components/H2.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// @flow
|
||||
|
||||
import variable from './../variables/platform';
|
||||
|
||||
export default (variables /* : * */ = variable) => {
|
||||
const h2Theme = {
|
||||
color: variables.textColor,
|
||||
fontSize: variables.fontSizeH2,
|
||||
lineHeight: variables.lineHeightH2
|
||||
};
|
||||
|
||||
return h2Theme;
|
||||
};
|
||||
13
native-base-theme/components/H3.js
Normal file
13
native-base-theme/components/H3.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// @flow
|
||||
|
||||
import variable from './../variables/platform';
|
||||
|
||||
export default (variables /* : * */ = variable) => {
|
||||
const h3Theme = {
|
||||
color: variables.textColor,
|
||||
fontSize: variables.fontSizeH3,
|
||||
lineHeight: variables.lineHeightH3
|
||||
};
|
||||
|
||||
return h3Theme;
|
||||
};
|
||||
419
native-base-theme/components/Header.js
Normal file
419
native-base-theme/components/Header.js
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
// @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;
|
||||
};
|
||||
12
native-base-theme/components/Icon.js
Normal file
12
native-base-theme/components/Icon.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// @flow
|
||||
|
||||
import variable from './../variables/platform';
|
||||
|
||||
export default (variables /* : * */ = variable) => {
|
||||
const iconTheme = {
|
||||
fontSize: variables.iconFontSize,
|
||||
color: variable.textColor
|
||||
};
|
||||
|
||||
return iconTheme;
|
||||
};
|
||||
19
native-base-theme/components/Input.js
Normal file
19
native-base-theme/components/Input.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// @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;
|
||||
};
|
||||
132
native-base-theme/components/InputGroup.js
Normal file
132
native-base-theme/components/InputGroup.js
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
// @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;
|
||||
};
|
||||
241
native-base-theme/components/Item.js
Normal file
241
native-base-theme/components/Item.js
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
// @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;
|
||||
};
|
||||
12
native-base-theme/components/Label.js
Normal file
12
native-base-theme/components/Label.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// @flow
|
||||
|
||||
export default () => {
|
||||
const labelTheme = {
|
||||
'.focused': {
|
||||
width: 0
|
||||
},
|
||||
fontSize: 17
|
||||
};
|
||||
|
||||
return labelTheme;
|
||||
};
|
||||
11
native-base-theme/components/Left.js
Normal file
11
native-base-theme/components/Left.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// @flow
|
||||
|
||||
export default () => {
|
||||
const leftTheme = {
|
||||
flex: 1,
|
||||
alignSelf: 'center',
|
||||
alignItems: 'flex-start'
|
||||
};
|
||||
|
||||
return leftTheme;
|
||||
};
|
||||
446
native-base-theme/components/ListItem.js
Normal file
446
native-base-theme/components/ListItem.js
Normal file
|
|
@ -0,0 +1,446 @@
|
|||
// @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;
|
||||
};
|
||||
14
native-base-theme/components/Picker.android.js
Normal file
14
native-base-theme/components/Picker.android.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// @flow
|
||||
|
||||
export default () => {
|
||||
const pickerTheme = {
|
||||
'.note': {
|
||||
color: '#8F8E95'
|
||||
},
|
||||
// width: 90,
|
||||
marginRight: -4,
|
||||
flexGrow: 1
|
||||
};
|
||||
|
||||
return pickerTheme;
|
||||
};
|
||||
7
native-base-theme/components/Picker.ios.js
Normal file
7
native-base-theme/components/Picker.ios.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
// @flow
|
||||
|
||||
export default () => {
|
||||
const pickerTheme = {};
|
||||
|
||||
return pickerTheme;
|
||||
};
|
||||
14
native-base-theme/components/Picker.js
Normal file
14
native-base-theme/components/Picker.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// @flow
|
||||
|
||||
export default () => {
|
||||
const pickerTheme = {
|
||||
'.note': {
|
||||
color: '#8F8E95'
|
||||
},
|
||||
// width: 90,
|
||||
marginRight: -4,
|
||||
flexGrow: 1
|
||||
};
|
||||
|
||||
return pickerTheme;
|
||||
};
|
||||
31
native-base-theme/components/Radio.js
Normal file
31
native-base-theme/components/Radio.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// @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;
|
||||
};
|
||||
14
native-base-theme/components/Right.js
Normal file
14
native-base-theme/components/Right.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// @flow
|
||||
|
||||
export default () => {
|
||||
const rightTheme = {
|
||||
'NativeBase.Button': {
|
||||
alignSelf: null
|
||||
},
|
||||
flex: 1,
|
||||
alignSelf: 'center',
|
||||
alignItems: 'flex-end'
|
||||
};
|
||||
|
||||
return rightTheme;
|
||||
};
|
||||
57
native-base-theme/components/Segment.js
Normal file
57
native-base-theme/components/Segment.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// @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;
|
||||
};
|
||||
49
native-base-theme/components/Separator.js
Normal file
49
native-base-theme/components/Separator.js
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// @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;
|
||||
};
|
||||
9
native-base-theme/components/Spinner.js
Normal file
9
native-base-theme/components/Spinner.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// @flow
|
||||
|
||||
export default () => {
|
||||
const spinnerTheme = {
|
||||
height: 80
|
||||
};
|
||||
|
||||
return spinnerTheme;
|
||||
};
|
||||
19
native-base-theme/components/Subtitle.js
Normal file
19
native-base-theme/components/Subtitle.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// @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;
|
||||
};
|
||||
46
native-base-theme/components/SwipeRow.js
Normal file
46
native-base-theme/components/SwipeRow.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// @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;
|
||||
};
|
||||
9
native-base-theme/components/Switch.js
Normal file
9
native-base-theme/components/Switch.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// @flow
|
||||
|
||||
export default () => {
|
||||
const switchTheme = {
|
||||
marginVertical: -5
|
||||
};
|
||||
|
||||
return switchTheme;
|
||||
};
|
||||
10
native-base-theme/components/Tab.js
Normal file
10
native-base-theme/components/Tab.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// @flow
|
||||
|
||||
export default () => {
|
||||
const tabTheme = {
|
||||
flex: 1,
|
||||
backgroundColor: '#FFF'
|
||||
};
|
||||
|
||||
return tabTheme;
|
||||
};
|
||||
57
native-base-theme/components/TabBar.js
Normal file
57
native-base-theme/components/TabBar.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// @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;
|
||||
};
|
||||
26
native-base-theme/components/TabContainer.js
Normal file
26
native-base-theme/components/TabContainer.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// @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;
|
||||
};
|
||||
40
native-base-theme/components/TabHeading.js
Normal file
40
native-base-theme/components/TabHeading.js
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// @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;
|
||||
};
|
||||
17
native-base-theme/components/Text.js
Normal file
17
native-base-theme/components/Text.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// @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;
|
||||
};
|
||||
25
native-base-theme/components/Textarea.js
Normal file
25
native-base-theme/components/Textarea.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// @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;
|
||||
};
|
||||
40
native-base-theme/components/Thumbnail.js
Normal file
40
native-base-theme/components/Thumbnail.js
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// @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;
|
||||
};
|
||||
21
native-base-theme/components/Title.js
Normal file
21
native-base-theme/components/Title.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// @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;
|
||||
};
|
||||
41
native-base-theme/components/Toast.js
Normal file
41
native-base-theme/components/Toast.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// @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;
|
||||
};
|
||||
13
native-base-theme/components/View.js
Normal file
13
native-base-theme/components/View.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// @flow
|
||||
|
||||
import variable from './../variables/platform';
|
||||
|
||||
export default (variables /* : * */ = variable) => {
|
||||
const viewTheme = {
|
||||
'.padder': {
|
||||
padding: variables.contentPadding
|
||||
}
|
||||
};
|
||||
|
||||
return viewTheme;
|
||||
};
|
||||
249
native-base-theme/components/index.js
Normal file
249
native-base-theme/components/index.js
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
/* 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;
|
||||
};
|
||||
311
native-base-theme/variables/commonColor.js
Normal file
311
native-base-theme/variables/commonColor.js
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
// @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
|
||||
}
|
||||
}
|
||||
};
|
||||
304
native-base-theme/variables/material.js
Normal file
304
native-base-theme/variables/material.js
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
// @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
|
||||
}
|
||||
}
|
||||
};
|
||||
362
native-base-theme/variables/platform.js
Normal file
362
native-base-theme/variables/platform.js
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
// @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
|
||||
}
|
||||
}
|
||||
};
|
||||
362
native-base-theme/variables/platformDark.js
Normal file
362
native-base-theme/variables/platformDark.js
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
// @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
|
||||
}
|
||||
}
|
||||
};
|
||||
14
navigation/AppNavigator.js
Normal file
14
navigation/AppNavigator.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// @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};
|
||||
|
|
@ -1,207 +1,79 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {createDrawerNavigator} from '@react-navigation/drawer';
|
||||
import TabNavigator from './MainTabNavigator';
|
||||
import { createDrawerNavigator } from 'react-navigation-drawer';
|
||||
import {createMaterialBottomTabNavigatorWithInitialRoute} 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/About/DebugScreen';
|
||||
import DebugScreen from '../screens/DebugScreen';
|
||||
import Sidebar from "../components/Sidebar";
|
||||
import {createStackNavigator, TransitionPresets} from "@react-navigation/stack";
|
||||
import HeaderButton from "../components/HeaderButton";
|
||||
import i18n from "i18n-js";
|
||||
import {createStackNavigator, TransitionPresets} from "react-navigation-stack";
|
||||
|
||||
const defaultScreenOptions = {
|
||||
gestureEnabled: true,
|
||||
cardOverlayEnabled: true,
|
||||
...TransitionPresets.SlideFromRightIOS,
|
||||
};
|
||||
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,
|
||||
},
|
||||
});
|
||||
|
||||
function getDrawerButton(navigation: Object) {
|
||||
return (
|
||||
<HeaderButton icon={'menu'} onPress={navigation.openDrawer}/>
|
||||
);
|
||||
|
||||
// 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,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
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>
|
||||
);
|
||||
/**
|
||||
* 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 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>
|
||||
);
|
||||
}
|
||||
export {createDrawerNavigatorWithInitialRoute};
|
||||
|
|
|
|||
|
|
@ -1,244 +1,127 @@
|
|||
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/Planning/PlanningScreen';
|
||||
import PlanningDisplayScreen from '../screens/Planning/PlanningDisplayScreen';
|
||||
import PlanningScreen from '../screens/PlanningScreen';
|
||||
import PlanningDisplayScreen from '../screens/PlanningDisplayScreen';
|
||||
import ProxiwashScreen from '../screens/Proxiwash/ProxiwashScreen';
|
||||
import ProxiwashAboutScreen from '../screens/Proxiwash/ProxiwashAboutScreen';
|
||||
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 {MaterialCommunityIcons} from "@expo/vector-icons";
|
||||
import AsyncStorageManager from "../utils/AsyncStorageManager";
|
||||
import HeaderButton from "../components/HeaderButton";
|
||||
import {withTheme} from 'react-native-paper';
|
||||
import i18n from "i18n-js";
|
||||
|
||||
import CustomMaterialIcon from "../components/CustomMaterialIcon";
|
||||
import ThemeManager from "../utils/ThemeManager";
|
||||
|
||||
const TAB_ICONS = {
|
||||
Home: 'triangle',
|
||||
Planning: 'calendar-range',
|
||||
Proxiwash: 'tshirt-crew',
|
||||
Proximo: 'cart',
|
||||
Planex: 'clock',
|
||||
Proxiwash: 'washing-machine',
|
||||
Proximo: 'shopping',
|
||||
Planex: 'timetable',
|
||||
};
|
||||
|
||||
const defaultScreenOptions = {
|
||||
gestureEnabled: true,
|
||||
cardOverlayEnabled: true,
|
||||
...TransitionPresets.SlideFromRightIOS,
|
||||
};
|
||||
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,
|
||||
},
|
||||
});
|
||||
|
||||
function getDrawerButton(navigation: Object) {
|
||||
return (
|
||||
<HeaderButton icon={'menu'} onPress={navigation.openDrawer}/>
|
||||
);
|
||||
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},
|
||||
});
|
||||
}
|
||||
|
||||
const ProximoStack = createStackNavigator();
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
export {createMaterialBottomTabNavigatorWithInitialRoute};
|
||||
|
||||
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: i18n.t('screens.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}
|
||||
options={{title: i18n.t('screens.home')}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="Proxiwash"
|
||||
component={ProxiwashStackComponent}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="Planex"
|
||||
component={PlanexStackComponent}
|
||||
/>
|
||||
</Tab.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
export default withTheme(TabNavigator);
|
||||
|
|
|
|||
23
package.json
23
package.json
|
|
@ -8,18 +8,15 @@
|
|||
"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",
|
||||
|
|
@ -27,15 +24,21 @@
|
|||
"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.6.0",
|
||||
"react-native-paper": "^3.5.1",
|
||||
"react-native-platform-touchable": "^1.1.1",
|
||||
"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-native-appearance": "~0.3.1",
|
||||
"expo-linear-gradient": "~8.0.0"
|
||||
"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"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-preset-expo": "^8.0.0"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
// @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 packageJson from '../../package';
|
||||
import {List} from 'react-native-paper';
|
||||
import i18n from "i18n-js";
|
||||
|
||||
function generateListFromObject(object) {
|
||||
let list = [];
|
||||
|
|
@ -16,8 +17,7 @@ function generateListFromObject(object) {
|
|||
}
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
route: Object
|
||||
navigation: Object
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -26,18 +26,28 @@ type Props = {
|
|||
export default class AboutDependenciesScreen extends React.Component<Props> {
|
||||
|
||||
render() {
|
||||
const data = generateListFromObject(packageJson.dependencies);
|
||||
const nav = this.props.navigation;
|
||||
const data = generateListFromObject(nav.getParam('data', {}));
|
||||
return (
|
||||
<FlatList
|
||||
data={data}
|
||||
keyExtractor={(item) => item.name}
|
||||
style={{minHeight: 300, width: '100%'}}
|
||||
renderItem={({item}) =>
|
||||
<List.Item
|
||||
title={item.name}
|
||||
description={item.version.replace('^', '').replace('~', '')}
|
||||
/>}
|
||||
/>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@
|
|||
|
||||
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 CustomModal from "../../components/CustomModal";
|
||||
import {Avatar, Button, Card, List, Text, Title, withTheme} from 'react-native-paper';
|
||||
import {Modalize} from "react-native-modalize";
|
||||
import ThemeManager from "../../utils/ThemeManager";
|
||||
|
||||
const links = {
|
||||
appstore: 'https://apps.apple.com/us/app/campus-amicale-insat/id1477722148',
|
||||
|
|
@ -58,10 +62,10 @@ function openWebLink(link) {
|
|||
/**
|
||||
* Class defining an about screen. This screen shows the user information about the app and it's author.
|
||||
*/
|
||||
class AboutScreen extends React.Component<Props, State> {
|
||||
export default class AboutScreen extends React.Component<Props, State> {
|
||||
|
||||
debugTapCounter = 0;
|
||||
modalRef: Object;
|
||||
modalRef: { current: null | Modalize };
|
||||
|
||||
state = {
|
||||
isDebugUnlocked: AsyncStorageManager.getInstance().preferences.debugUnlocked.current === '1'
|
||||
|
|
@ -165,7 +169,7 @@ class AboutScreen extends React.Component<Props, State> {
|
|||
showChevron: true
|
||||
},
|
||||
{
|
||||
onPressCallback: () => this.props.navigation.navigate('AboutDependenciesScreen'),
|
||||
onPressCallback: () => this.props.navigation.navigate('AboutDependenciesScreen', {data: packageJson.dependencies}),
|
||||
icon: 'developer-board',
|
||||
text: i18n.t('aboutScreen.libs'),
|
||||
showChevron: true
|
||||
|
|
@ -185,113 +189,95 @@ class AboutScreen extends React.Component<Props, State> {
|
|||
|
||||
getCardItem: Function;
|
||||
getMainCard: Function;
|
||||
onModalRef: Function;
|
||||
onPressMail: Function;
|
||||
onPressGit: Function;
|
||||
|
||||
colors: Object;
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.modalRef = React.createRef();
|
||||
this.getCardItem = this.getCardItem.bind(this);
|
||||
this.getMainCard = this.getMainCard.bind(this);
|
||||
this.onModalRef = this.onModalRef.bind(this);
|
||||
this.onPressMail = openWebLink.bind(this, links.bugsMail);
|
||||
this.onPressGit = openWebLink.bind(this, links.bugsGit);
|
||||
this.colors = props.theme.colors;
|
||||
}
|
||||
|
||||
getAppIcon(props) {
|
||||
return (
|
||||
<Avatar.Image
|
||||
{...props}
|
||||
source={require('../../assets/android.icon.png')}
|
||||
style={{backgroundColor: 'transparent'}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
keyExtractor(item: Object) {
|
||||
return item.icon;
|
||||
}
|
||||
|
||||
getAppCard() {
|
||||
return (
|
||||
<Card style={{marginBottom: 10}}>
|
||||
<Card.Title
|
||||
title={appJson.expo.name}
|
||||
subtitle={appJson.expo.version}
|
||||
left={this.getAppIcon}/>
|
||||
<Card.Content>
|
||||
<FlatList
|
||||
data={this.appData}
|
||||
extraData={this.state}
|
||||
keyExtractor={this.keyExtractor}
|
||||
listKey={"app"}
|
||||
renderItem={this.getCardItem}
|
||||
/>
|
||||
</Card.Content>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
getTeamCard() {
|
||||
return (
|
||||
<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={this.keyExtractor}
|
||||
listKey={"team1"}
|
||||
renderItem={this.getCardItem}
|
||||
/>
|
||||
<Title>{i18n.t('aboutScreen.additionalDev')}</Title>
|
||||
<FlatList
|
||||
data={this.additionalDevData}
|
||||
extraData={this.state}
|
||||
keyExtractor={this.keyExtractor}
|
||||
listKey={"team2"}
|
||||
renderItem={this.getCardItem}
|
||||
/>
|
||||
</Card.Content>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
getTechnoCard() {
|
||||
return (
|
||||
<Card style={{marginBottom: 10}}>
|
||||
<Card.Content>
|
||||
<Title>{i18n.t('aboutScreen.technologies')}</Title>
|
||||
<FlatList
|
||||
data={this.technoData}
|
||||
extraData={this.state}
|
||||
keyExtractor={this.keyExtractor}
|
||||
listKey={"techno"}
|
||||
renderItem={this.getCardItem}
|
||||
/>
|
||||
</Card.Content>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
getChevronIcon(props: Object) {
|
||||
return (
|
||||
<List.Icon {...props} icon={'chevron-right'}/>
|
||||
);
|
||||
}
|
||||
|
||||
getItemIcon(item: Object, props: Object) {
|
||||
return (
|
||||
<List.Icon {...props} icon={item.icon}/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a clickable card item to be rendered inside a card.
|
||||
*
|
||||
|
|
@ -299,28 +285,28 @@ class AboutScreen extends React.Component<Props, State> {
|
|||
*/
|
||||
getCardItem({item}: Object) {
|
||||
let shouldShow = !item.showOnlyInDebug || (item.showOnlyInDebug && this.state.isDebugUnlocked);
|
||||
const getItemIcon = this.getItemIcon.bind(this, item);
|
||||
if (shouldShow) {
|
||||
if (item.showChevron) {
|
||||
return (
|
||||
<List.Item
|
||||
title={item.text}
|
||||
left={getItemIcon}
|
||||
right={this.getChevronIcon}
|
||||
onPress={item.onPressCallback}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<List.Item
|
||||
title={item.text}
|
||||
left={getItemIcon}
|
||||
onPress={item.onPressCallback}
|
||||
/>
|
||||
);
|
||||
}
|
||||
} else
|
||||
return null;
|
||||
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>)
|
||||
;
|
||||
} else {
|
||||
return <View/>
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
tryUnlockDebugMode() {
|
||||
|
|
@ -337,48 +323,52 @@ class AboutScreen extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
getBugReportModal() {
|
||||
const onPressMail = openWebLink.bind(this, links.bugsMail);
|
||||
const onPressGit = openWebLink.bind(this, links.bugsGit);
|
||||
return (
|
||||
<View style={{
|
||||
flex: 1,
|
||||
padding: 20
|
||||
}}>
|
||||
<Title>{i18n.t('aboutScreen.bugs')}</Title>
|
||||
<Text>
|
||||
{i18n.t('aboutScreen.bugsDescription')}
|
||||
</Text>
|
||||
<Button
|
||||
icon="email"
|
||||
mode="contained"
|
||||
dark={true}
|
||||
color={this.colors.primary}
|
||||
style={{
|
||||
marginTop: 20,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
}}
|
||||
onPress={this.onPressMail}>
|
||||
<Text>{i18n.t('aboutScreen.bugsMail')}</Text>
|
||||
</Button>
|
||||
<Button
|
||||
icon="git"
|
||||
mode="contained"
|
||||
dark={true}
|
||||
color={this.colors.primary}
|
||||
style={{
|
||||
marginTop: 20,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
}}
|
||||
onPress={this.onPressGit}>
|
||||
<Text>{i18n.t('aboutScreen.bugsGit')}</Text>
|
||||
</Button>
|
||||
</View>
|
||||
<Modalize ref={this.modalRef}
|
||||
adjustToContentHeight
|
||||
modalStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
|
||||
<View style={{
|
||||
flex: 1,
|
||||
padding: 20
|
||||
}}>
|
||||
<H1>{i18n.t('aboutScreen.bugs')}</H1>
|
||||
<Text>
|
||||
{i18n.t('aboutScreen.bugsDescription')}
|
||||
</Text>
|
||||
<Button
|
||||
style={{
|
||||
marginTop: 20,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
}}
|
||||
onPress={onPressMail}>
|
||||
<CustomMaterialIcon
|
||||
icon={'email'}
|
||||
color={'#fff'}/>
|
||||
<Text>{i18n.t('aboutScreen.bugsMail')}</Text>
|
||||
</Button>
|
||||
<Button
|
||||
style={{
|
||||
marginTop: 20,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
}}
|
||||
onPress={onPressGit}>
|
||||
<CustomMaterialIcon
|
||||
icon={'git'}
|
||||
color={'#fff'}/>
|
||||
<Text>{i18n.t('aboutScreen.bugsGit')}</Text>
|
||||
</Button>
|
||||
</View>
|
||||
</Modalize>
|
||||
);
|
||||
}
|
||||
|
||||
openBugReportModal() {
|
||||
if (this.modalRef) {
|
||||
this.modalRef.open();
|
||||
if (this.modalRef.current) {
|
||||
this.modalRef.current.open();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -394,16 +384,12 @@ class AboutScreen extends React.Component<Props, State> {
|
|||
return <View/>;
|
||||
}
|
||||
|
||||
onModalRef(ref: Object) {
|
||||
this.modalRef = ref;
|
||||
}
|
||||
|
||||
render() {
|
||||
const nav = this.props.navigation;
|
||||
return (
|
||||
<View style={{padding: 5}}>
|
||||
<CustomModal onRef={this.onModalRef}>
|
||||
{this.getBugReportModal()}
|
||||
</CustomModal>
|
||||
<Container>
|
||||
{this.getBugReportModal()}
|
||||
<CustomHeader navigation={nav} title={i18n.t('screens.about')} hasBackButton={true}/>
|
||||
<FlatList
|
||||
style={{padding: 5}}
|
||||
data={this.dataOrder}
|
||||
|
|
@ -411,9 +397,7 @@ class AboutScreen extends React.Component<Props, State> {
|
|||
keyExtractor={(item) => item.id}
|
||||
renderItem={this.getMainCard}
|
||||
/>
|
||||
</View>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTheme(AboutScreen);
|
||||
|
|
|
|||
|
|
@ -1,172 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {Alert, Clipboard, ScrollView, View} from "react-native";
|
||||
import AsyncStorageManager from "../../utils/AsyncStorageManager";
|
||||
import NotificationsManager from "../../utils/NotificationsManager";
|
||||
import CustomModal from "../../components/CustomModal";
|
||||
import {Button, Card, List, Subheading, TextInput, Title, withTheme} from 'react-native-paper';
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
};
|
||||
|
||||
type State = {
|
||||
modalCurrentDisplayItem: Object,
|
||||
currentPreferences: Object,
|
||||
}
|
||||
|
||||
/**
|
||||
* Class defining the Debug screen. This screen allows the user to get detailed information on the app/device.
|
||||
*/
|
||||
class DebugScreen extends React.Component<Props, State> {
|
||||
|
||||
modalRef: Object;
|
||||
modalInputValue = '';
|
||||
state = {
|
||||
modalCurrentDisplayItem: {},
|
||||
currentPreferences: JSON.parse(JSON.stringify(AsyncStorageManager.getInstance().preferences))
|
||||
};
|
||||
|
||||
onModalRef: Function;
|
||||
|
||||
colors: Object;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onModalRef = this.onModalRef.bind(this);
|
||||
this.colors = props.theme.colors;
|
||||
}
|
||||
|
||||
static getGeneralItem(onPressCallback: Function, icon: ?string, title: string, subtitle: string) {
|
||||
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() {
|
||||
let token = AsyncStorageManager.getInstance().preferences.expoToken.current;
|
||||
Alert.alert(
|
||||
'Expo Token',
|
||||
token,
|
||||
[
|
||||
{text: 'Copy', onPress: () => Clipboard.setString(token)},
|
||||
{text: 'OK'}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
async forceExpoTokenUpdate() {
|
||||
await NotificationsManager.forceExpoTokenUpdate();
|
||||
this.alertCurrentExpoToken();
|
||||
}
|
||||
|
||||
showEditModal(item: Object) {
|
||||
this.setState({
|
||||
modalCurrentDisplayItem: item
|
||||
});
|
||||
if (this.modalRef) {
|
||||
this.modalRef.open();
|
||||
}
|
||||
}
|
||||
|
||||
getModalContent() {
|
||||
return (
|
||||
<View style={{
|
||||
flex: 1,
|
||||
padding: 20
|
||||
}}>
|
||||
<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
|
||||
mode="contained"
|
||||
dark={true}
|
||||
color={this.colors.success}
|
||||
onPress={() => this.saveNewPrefs(this.state.modalCurrentDisplayItem.key, this.modalInputValue)}>
|
||||
Save new value
|
||||
</Button>
|
||||
<Button
|
||||
mode="contained"
|
||||
dark={true}
|
||||
color={this.colors.danger}
|
||||
onPress={() => this.saveNewPrefs(this.state.modalCurrentDisplayItem.key, this.state.modalCurrentDisplayItem.default)}>
|
||||
Reset to default
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
saveNewPrefs(key: string, value: string) {
|
||||
this.setState((prevState) => {
|
||||
let currentPreferences = {...prevState.currentPreferences};
|
||||
currentPreferences[key].current = value;
|
||||
return {currentPreferences};
|
||||
});
|
||||
AsyncStorageManager.getInstance().savePref(key, value);
|
||||
}
|
||||
|
||||
onModalRef(ref: Object) {
|
||||
this.modalRef = ref;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<CustomModal onRef={this.onModalRef}>
|
||||
{this.getModalContent()}
|
||||
</CustomModal>
|
||||
<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', '')}
|
||||
</Card.Content>
|
||||
</Card>
|
||||
<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>
|
||||
)}
|
||||
</Card.Content>
|
||||
</Card>
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTheme(DebugScreen);
|
||||
194
screens/DebugScreen.js
Normal file
194
screens/DebugScreen.js
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
// @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 AsyncStorageManager from "../utils/AsyncStorageManager";
|
||||
import NotificationsManager from "../utils/NotificationsManager";
|
||||
import {Modalize} from "react-native-modalize";
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
};
|
||||
|
||||
type State = {
|
||||
modalCurrentDisplayItem: Object,
|
||||
currentPreferences: Object,
|
||||
}
|
||||
|
||||
/**
|
||||
* Class defining the Debug screen. This screen allows the user to get detailed information on the app/device.
|
||||
*/
|
||||
export default class DebugScreen extends React.Component<Props, State> {
|
||||
|
||||
modalRef: { current: null | Modalize };
|
||||
modalInputValue = '';
|
||||
state = {
|
||||
modalCurrentDisplayItem: {},
|
||||
currentPreferences: JSON.parse(JSON.stringify(AsyncStorageManager.getInstance().preferences))
|
||||
};
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.modalRef = React.createRef();
|
||||
}
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
alertCurrentExpoToken() {
|
||||
let token = AsyncStorageManager.getInstance().preferences.expoToken.current;
|
||||
Alert.alert(
|
||||
'Expo Token',
|
||||
token,
|
||||
[
|
||||
{text: 'Copy', onPress: () => Clipboard.setString(token)},
|
||||
{text: 'OK'}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
async forceExpoTokenUpdate() {
|
||||
await NotificationsManager.forceExpoTokenUpdate();
|
||||
this.alertCurrentExpoToken();
|
||||
}
|
||||
|
||||
showEditModal(item: Object) {
|
||||
this.setState({
|
||||
modalCurrentDisplayItem: item
|
||||
});
|
||||
if (this.modalRef.current) {
|
||||
this.modalRef.current.open();
|
||||
}
|
||||
}
|
||||
|
||||
getModalContent() {
|
||||
return (
|
||||
<View style={{
|
||||
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>
|
||||
<View style={{
|
||||
flexDirection: 'row',
|
||||
marginTop: 10,
|
||||
}}>
|
||||
<Button success
|
||||
onPress={() => this.saveNewPrefs(this.state.modalCurrentDisplayItem.key, this.modalInputValue)}>
|
||||
<Text>Save new value</Text>
|
||||
</Button>
|
||||
<Button
|
||||
onPress={() => this.saveNewPrefs(this.state.modalCurrentDisplayItem.key, this.state.modalCurrentDisplayItem.default)}>
|
||||
<Text>Reset to default</Text>
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
saveNewPrefs(key: string, value: string) {
|
||||
this.setState((prevState) => {
|
||||
let currentPreferences = {...prevState.currentPreferences};
|
||||
currentPreferences[key].current = value;
|
||||
return {currentPreferences};
|
||||
});
|
||||
AsyncStorageManager.getInstance().savePref(key, value);
|
||||
}
|
||||
|
||||
render() {
|
||||
const nav = this.props.navigation;
|
||||
return (
|
||||
<Container>
|
||||
<Modalize
|
||||
ref={this.modalRef}
|
||||
adjustToContentHeight
|
||||
modalStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
|
||||
{this.getModalContent()}
|
||||
</Modalize>
|
||||
<CustomHeader navigation={nav} title={i18n.t('screens.debug')} hasBackButton={true}/>
|
||||
<Content padder>
|
||||
<Card>
|
||||
<CardItem header>
|
||||
<Text>
|
||||
Notifications
|
||||
</Text>
|
||||
</CardItem>
|
||||
<List>
|
||||
{DebugScreen.getGeneralItem(() => this.alertCurrentExpoToken(), 'bell', 'Get current Expo Token', '')}
|
||||
{DebugScreen.getGeneralItem(() => this.forceExpoTokenUpdate(), 'bell-ring', 'Force Expo token update', '')}
|
||||
</List>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardItem header>
|
||||
<Text>
|
||||
Preferences
|
||||
</Text>
|
||||
</CardItem>
|
||||
<List>
|
||||
{Object.values(this.state.currentPreferences).map((object) =>
|
||||
<View>
|
||||
{DebugScreen.getGeneralItem(() => this.showEditModal(object), undefined, object.key, 'Click to edit')}
|
||||
</View>
|
||||
)}
|
||||
</List>
|
||||
</Card>
|
||||
</Content>
|
||||
</Container>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,18 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {View} from 'react-native';
|
||||
import {Image, Linking, TouchableOpacity, View} from 'react-native';
|
||||
import {Body, Button, Card, CardItem, H1, Left, Text, Thumbnail} from 'native-base';
|
||||
import i18n from "i18n-js";
|
||||
import DashboardItem from "../components/EventDashboardItem";
|
||||
import * as WebBrowser from 'expo-web-browser';
|
||||
import WebSectionList from "../components/WebSectionList";
|
||||
import {Text, withTheme} from 'react-native-paper';
|
||||
import FeedItem from "../components/FeedItem";
|
||||
import SquareDashboardItem from "../components/SquareDashboardItem";
|
||||
import PreviewEventDashboardItem from "../components/PreviewEventDashboardItem";
|
||||
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 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";
|
||||
|
||||
|
|
@ -23,34 +23,48 @@ const SECTIONS_ID = [
|
|||
|
||||
const REFRESH_TIME = 1000 * 20; // Refresh every 20 seconds
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
theme: Object,
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* Class defining the app's home screen
|
||||
*/
|
||||
class HomeScreen extends React.Component<Props> {
|
||||
export default class HomeScreen extends FetchedDataSectionList {
|
||||
|
||||
onProxiwashClick: Function;
|
||||
onTutorInsaClick: Function;
|
||||
onMenuClick: Function;
|
||||
onProximoClick: Function;
|
||||
getRenderItem: Function;
|
||||
createDataset: Function;
|
||||
|
||||
colors : Object;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
constructor() {
|
||||
super(DATA_URL, REFRESH_TIME);
|
||||
this.onProxiwashClick = this.onProxiwashClick.bind(this);
|
||||
this.onTutorInsaClick = this.onTutorInsaClick.bind(this);
|
||||
this.onMenuClick = this.onMenuClick.bind(this);
|
||||
this.onProximoClick = this.onProximoClick.bind(this);
|
||||
this.getRenderItem = this.getRenderItem.bind(this);
|
||||
this.createDataset = this.createDataset.bind(this);
|
||||
this.colors = props.theme.colors;
|
||||
}
|
||||
|
||||
onProxiwashClick() {
|
||||
this.props.navigation.navigate('Proxiwash');
|
||||
}
|
||||
|
||||
onTutorInsaClick() {
|
||||
this.props.navigation.navigate('TutorInsaScreen');
|
||||
}
|
||||
|
||||
onProximoClick() {
|
||||
this.props.navigation.navigate('Proximo');
|
||||
}
|
||||
|
||||
onMenuClick() {
|
||||
this.props.navigation.navigate('SelfMenuScreen');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -63,20 +77,12 @@ class HomeScreen extends React.Component<Props> {
|
|||
return date.toLocaleString();
|
||||
}
|
||||
|
||||
onProxiwashClick() {
|
||||
this.props.navigation.navigate('Proxiwash');
|
||||
getHeaderTranslation() {
|
||||
return i18n.t("screens.home");
|
||||
}
|
||||
|
||||
onTutorInsaClick() {
|
||||
WebBrowser.openBrowserAsync("https://www.etud.insa-toulouse.fr/~tutorinsa/");
|
||||
}
|
||||
|
||||
onProximoClick() {
|
||||
this.props.navigation.navigate('Proximo');
|
||||
}
|
||||
|
||||
onMenuClick() {
|
||||
this.props.navigation.navigate('SelfMenuScreen');
|
||||
getUpdateToastTranslations() {
|
||||
return [i18n.t("homeScreen.listUpdated"), i18n.t("homeScreen.listUpdateFail")];
|
||||
}
|
||||
|
||||
getKeyExtractor(item: Object) {
|
||||
|
|
@ -111,32 +117,36 @@ class HomeScreen extends React.Component<Props> {
|
|||
|
||||
generateDashboardDataset(dashboardData: Object) {
|
||||
let dataset = [
|
||||
|
||||
{
|
||||
id: 'middle',
|
||||
content: []
|
||||
},
|
||||
{
|
||||
id: 'event',
|
||||
content: undefined
|
||||
},
|
||||
{
|
||||
id: 'middle',
|
||||
content: [{}, {}]
|
||||
},
|
||||
{
|
||||
id: 'bottom',
|
||||
content: [{}, {}]
|
||||
},
|
||||
|
||||
];
|
||||
for (let [key, value] of Object.entries(dashboardData)) {
|
||||
switch (key) {
|
||||
case 'today_events':
|
||||
dataset[1]['content'] = value;
|
||||
dataset[0]['content'] = value;
|
||||
break;
|
||||
case 'available_machines':
|
||||
dataset[0]['content'][0] = {id: key, data: value};
|
||||
dataset[1]['content'][0] = {id: key, data: value};
|
||||
break;
|
||||
case 'available_tutorials':
|
||||
dataset[0]['content'][1] = {id: key, data: value};
|
||||
dataset[1]['content'][1] = {id: key, data: value};
|
||||
break;
|
||||
case 'proximo_articles':
|
||||
dataset[0]['content'][2] = {id: key, data: value};
|
||||
dataset[2]['content'][0] = {id: key, data: value};
|
||||
break;
|
||||
case 'today_menu':
|
||||
dataset[0]['content'][3] = {id: key, data: value};
|
||||
dataset[2]['content'][1] = {id: key, data: value};
|
||||
break;
|
||||
|
||||
}
|
||||
|
|
@ -144,12 +154,33 @@ class HomeScreen extends React.Component<Props> {
|
|||
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')
|
||||
return this.getDashboardEventItem(content);
|
||||
else if (item['id'] === 'middle')
|
||||
return this.getDashboardMiddleItem(content);
|
||||
else
|
||||
return this.getDashboardBottomItem(content);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -283,8 +314,17 @@ class HomeScreen extends React.Component<Props> {
|
|||
}
|
||||
|
||||
|
||||
clickAction(isAvailable: boolean, displayEvent: Object) {
|
||||
if (isAvailable)
|
||||
this.props.navigation.navigate('PlanningDisplayScreen', {data: displayEvent});
|
||||
else
|
||||
this.props.navigation.navigate('PlanningScreen');
|
||||
};
|
||||
|
||||
|
||||
getDashboardEventItem(content: Array<Object>) {
|
||||
let icon = 'calendar-range';
|
||||
let color = ThemeManager.getCurrentThemeVariables().planningColor;
|
||||
let title = i18n.t('homeScreen.dashboard.todayEventsTitle');
|
||||
let subtitle;
|
||||
let futureEvents = this.getFutureEvents(content);
|
||||
|
|
@ -305,24 +345,78 @@ class HomeScreen extends React.Component<Props> {
|
|||
subtitle = i18n.t('homeScreen.dashboard.todayEventsSubtitleNA');
|
||||
|
||||
let displayEvent = this.getDisplayEvent(futureEvents);
|
||||
const clickContainerAction = () => this.props.navigation.navigate('Planning');
|
||||
const clickPreviewAction = () => this.props.navigation.navigate('PlanningDisplayScreen', {data: displayEvent});
|
||||
|
||||
return (
|
||||
<DashboardItem
|
||||
{...this.props}
|
||||
subtitle={subtitle}
|
||||
color={color}
|
||||
icon={icon}
|
||||
clickAction={clickContainerAction}
|
||||
clickAction={this.clickAction.bind(this, isAvailable, displayEvent)}
|
||||
title={title}
|
||||
isAvailable={isAvailable}
|
||||
>
|
||||
<PreviewEventDashboardItem
|
||||
{...this.props}
|
||||
event={displayEvent}
|
||||
clickAction={clickPreviewAction}
|
||||
/>
|
||||
</DashboardItem>
|
||||
displayEvent={displayEvent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
getDashboardBottomItem(content: Array<Object>) {
|
||||
let proximoData = content[0]['data'];
|
||||
let menuData = content[1]['data'];
|
||||
let proximoIcon = 'shopping';
|
||||
let proximoColor = ThemeManager.getCurrentThemeVariables().proximoColor;
|
||||
let proximoTitle = i18n.t('homeScreen.dashboard.proximoTitle');
|
||||
let isProximoAvailable = parseInt(proximoData) > 0;
|
||||
let proximoSubtitle;
|
||||
if (isProximoAvailable) {
|
||||
proximoSubtitle =
|
||||
<Text>
|
||||
<Text style={{fontWeight: "bold"}}>{proximoData}</Text>
|
||||
<Text>
|
||||
{
|
||||
proximoData > 1 ?
|
||||
i18n.t('homeScreen.dashboard.proximoSubtitlePlural') :
|
||||
i18n.t('homeScreen.dashboard.proximoSubtitle')
|
||||
}
|
||||
</Text>
|
||||
</Text>;
|
||||
} else
|
||||
proximoSubtitle = i18n.t('homeScreen.dashboard.proximoSubtitleNA');
|
||||
|
||||
|
||||
let menuIcon = 'silverware-fork-knife';
|
||||
let menuColor = ThemeManager.getCurrentThemeVariables().menuColor;
|
||||
let menuTitle = i18n.t('homeScreen.dashboard.menuTitle');
|
||||
let isMenuAvailable = menuData.length > 0;
|
||||
let menuSubtitle;
|
||||
if (isMenuAvailable) {
|
||||
menuSubtitle = i18n.t('homeScreen.dashboard.menuSubtitle');
|
||||
} else
|
||||
menuSubtitle = i18n.t('homeScreen.dashboard.menuSubtitleNA');
|
||||
return (
|
||||
<View style={{
|
||||
flexDirection: 'row',
|
||||
marginLeft: 10,
|
||||
marginRight: 10,
|
||||
}}>
|
||||
<DashboardItem
|
||||
isSquare={true}
|
||||
subtitle={menuSubtitle}
|
||||
color={menuColor}
|
||||
icon={menuIcon}
|
||||
clickAction={this.onMenuClick}
|
||||
title={menuTitle}
|
||||
isAvailable={isMenuAvailable}
|
||||
isSquareLeft={true}/>
|
||||
<DashboardItem
|
||||
isSquare={true}
|
||||
subtitle={proximoSubtitle}
|
||||
color={proximoColor}
|
||||
icon={proximoIcon}
|
||||
clickAction={this.onProximoClick}
|
||||
title={proximoTitle}
|
||||
isAvailable={isProximoAvailable}/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -330,91 +424,163 @@ class HomeScreen extends React.Component<Props> {
|
|||
getDashboardMiddleItem(content: Array<Object>) {
|
||||
let proxiwashData = content[0]['data'];
|
||||
let tutorinsaData = content[1]['data'];
|
||||
let proximoData = content[2]['data'];
|
||||
let menuData = content[3]['data'];
|
||||
|
||||
let proxiwashIcon = 'washing-machine';
|
||||
let proxiwashColor = ThemeManager.getCurrentThemeVariables().proxiwashColor;
|
||||
let proxiwashTitle = i18n.t('homeScreen.dashboard.proxiwashTitle');
|
||||
let proxiwashIsAvailable = parseInt(proxiwashData['dryers']) > 0 || parseInt(proxiwashData['washers']) > 0;
|
||||
let proxiwashSubtitle;
|
||||
let dryerColor = parseInt(proxiwashData['dryers']) > 0 ?
|
||||
ThemeManager.getCurrentThemeVariables().textColor :
|
||||
ThemeManager.getCurrentThemeVariables().listNoteColor;
|
||||
let washerColor = parseInt(proxiwashData['washers']) > 0 ?
|
||||
ThemeManager.getCurrentThemeVariables().textColor :
|
||||
ThemeManager.getCurrentThemeVariables().listNoteColor;
|
||||
let availableDryers = proxiwashData['dryers'];
|
||||
let availableWashers = proxiwashData['washers'];
|
||||
if (proxiwashIsAvailable) {
|
||||
proxiwashSubtitle =
|
||||
<Text>
|
||||
<Text style={{
|
||||
fontWeight: parseInt(proxiwashData['dryers']) > 0 ?
|
||||
'bold' :
|
||||
'normal',
|
||||
color: dryerColor
|
||||
}}>
|
||||
{availableDryers}
|
||||
</Text>
|
||||
<Text>
|
||||
{
|
||||
availableDryers > 1 ?
|
||||
i18n.t('homeScreen.dashboard.proxiwashSubtitle1Plural') :
|
||||
i18n.t('homeScreen.dashboard.proxiwashSubtitle1')
|
||||
}
|
||||
</Text>
|
||||
{"\n"}
|
||||
<Text style={{
|
||||
fontWeight: parseInt(proxiwashData['washers']) > 0 ?
|
||||
'bold' :
|
||||
'normal',
|
||||
color: washerColor
|
||||
}}>
|
||||
{availableWashers}
|
||||
</Text>
|
||||
<Text>
|
||||
{
|
||||
availableWashers > 1 ?
|
||||
i18n.t('homeScreen.dashboard.proxiwashSubtitle2Plural') :
|
||||
i18n.t('homeScreen.dashboard.proxiwashSubtitle2')
|
||||
}
|
||||
</Text>
|
||||
</Text>;
|
||||
} else
|
||||
proxiwashSubtitle = i18n.t('homeScreen.dashboard.proxiwashSubtitleNA');
|
||||
|
||||
let tutorinsaIcon = 'school';
|
||||
let tutorinsaColor = ThemeManager.getCurrentThemeVariables().tutorinsaColor;
|
||||
let tutorinsaTitle = 'Tutor\'INSA';
|
||||
let tutorinsaIsAvailable = tutorinsaData > 0;
|
||||
let tutorinsaSubtitle;
|
||||
if (tutorinsaIsAvailable) {
|
||||
tutorinsaSubtitle =
|
||||
<Text>
|
||||
<Text style={{fontWeight: "bold"}}>{tutorinsaData}</Text>
|
||||
<Text>
|
||||
{
|
||||
tutorinsaData > 1 ?
|
||||
i18n.t('homeScreen.dashboard.tutorinsaSubtitlePlural') :
|
||||
i18n.t('homeScreen.dashboard.tutorinsaSubtitle')
|
||||
}
|
||||
</Text>
|
||||
</Text>;
|
||||
} else
|
||||
tutorinsaSubtitle = i18n.t('homeScreen.dashboard.tutorinsaSubtitleNA');
|
||||
|
||||
return (
|
||||
<View style={{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
flexWrap: 'wrap',
|
||||
margin: 10,
|
||||
marginLeft: 10,
|
||||
marginRight: 10,
|
||||
}}>
|
||||
<SquareDashboardItem
|
||||
color={this.colors.proxiwashColor}
|
||||
icon={'washing-machine'}
|
||||
<DashboardItem
|
||||
isSquare={true}
|
||||
subtitle={proxiwashSubtitle}
|
||||
color={proxiwashColor}
|
||||
icon={proxiwashIcon}
|
||||
clickAction={this.onProxiwashClick}
|
||||
isAvailable={parseInt(proxiwashData['washers']) > 0}
|
||||
badgeNumber={proxiwashData['washers']}
|
||||
/>
|
||||
<SquareDashboardItem
|
||||
color={this.colors.proxiwashColor}
|
||||
icon={'tumble-dryer'}
|
||||
clickAction={this.onProxiwashClick}
|
||||
isAvailable={parseInt(proxiwashData['dryers']) > 0}
|
||||
badgeNumber={proxiwashData['dryers']}
|
||||
/>
|
||||
<SquareDashboardItem
|
||||
color={this.colors.tutorinsaColor}
|
||||
icon={'school'}
|
||||
title={proxiwashTitle}
|
||||
isAvailable={proxiwashIsAvailable}
|
||||
isSquareLeft={true}/>
|
||||
<DashboardItem
|
||||
isSquare={true}
|
||||
subtitle={tutorinsaSubtitle}
|
||||
color={tutorinsaColor}
|
||||
icon={tutorinsaIcon}
|
||||
clickAction={this.onTutorInsaClick}
|
||||
isAvailable={tutorinsaData > 0}
|
||||
badgeNumber={tutorinsaData}
|
||||
/>
|
||||
<SquareDashboardItem
|
||||
color={this.colors.proximoColor}
|
||||
icon={'shopping'}
|
||||
clickAction={this.onProximoClick}
|
||||
isAvailable={parseInt(proximoData) > 0}
|
||||
badgeNumber={parseInt(proximoData)}
|
||||
/>
|
||||
<SquareDashboardItem
|
||||
color={this.colors.menuColor}
|
||||
icon={'silverware-fork-knife'}
|
||||
clickAction={this.onMenuClick}
|
||||
isAvailable={menuData.length > 0}
|
||||
badgeNumber={0}
|
||||
/>
|
||||
title={tutorinsaTitle}
|
||||
isAvailable={tutorinsaIsAvailable}/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
openLink(link: string) {
|
||||
WebBrowser.openBrowserAsync(link);
|
||||
}
|
||||
|
||||
getFeedItem(item: Object) {
|
||||
const onImagePress = this.openLink.bind(this, item.full_picture);
|
||||
const onOutLinkPress = this.openLink.bind(this, item.permalink_url);
|
||||
getRenderItem(item: Object, section: Object) {
|
||||
return (
|
||||
<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}
|
||||
autoRefreshTime={REFRESH_TIME}
|
||||
refreshOnFocus={true}
|
||||
fetchUrl={DATA_URL}
|
||||
renderItem={this.getRenderItem}/>
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTheme(HomeScreen);
|
||||
|
|
|
|||
|
|
@ -1,65 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
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, withTheme} from 'react-native-paper';
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
route: Object
|
||||
};
|
||||
|
||||
function openWebLink(event, link) {
|
||||
Linking.openURL(link).catch((err) => console.error('Error opening link', err));
|
||||
}
|
||||
|
||||
/**
|
||||
* Class defining an about screen. This screen shows the user information about the app and it's author.
|
||||
*/
|
||||
class PlanningDisplayScreen extends React.Component<Props> {
|
||||
|
||||
displayData = this.props.route.params['data'];
|
||||
|
||||
colors: Object;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.colors = props.theme.colors;
|
||||
}
|
||||
|
||||
render() {
|
||||
// console.log("rendering planningDisplayScreen");
|
||||
return (
|
||||
<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/>}
|
||||
|
||||
{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: this.colors.text,},
|
||||
div: {color: this.colors.text}
|
||||
}}
|
||||
onLinkPress={openWebLink}/>
|
||||
</Card.Content>
|
||||
: <View/>}
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTheme(PlanningDisplayScreen);
|
||||
|
|
@ -1,271 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {BackHandler, View} from 'react-native';
|
||||
import i18n from "i18n-js";
|
||||
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'],
|
||||
monthNamesShort: ['Janv.', 'Févr.', 'Mars', 'Avril', 'Mai', 'Juin', 'Juil.', 'Août', 'Sept.', 'Oct.', 'Nov.', 'Déc.'],
|
||||
dayNames: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'],
|
||||
dayNamesShort: ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'],
|
||||
today: 'Aujourd\'hui'
|
||||
};
|
||||
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
}
|
||||
|
||||
type State = {
|
||||
refreshing: boolean,
|
||||
agendaItems: Object,
|
||||
calendarShowing: boolean,
|
||||
};
|
||||
|
||||
const FETCH_URL = "https://amicale-insat.fr/event/json/list";
|
||||
|
||||
const AGENDA_MONTH_SPAN = 3;
|
||||
|
||||
/**
|
||||
* Class defining the app's planning screen
|
||||
*/
|
||||
export default class PlanningScreen extends React.Component<Props, State> {
|
||||
|
||||
agendaRef: Agenda;
|
||||
webDataManager: WebDataManager;
|
||||
|
||||
lastRefresh: Date;
|
||||
minTimeBetweenRefresh = 60;
|
||||
|
||||
didFocusSubscription: Function;
|
||||
willBlurSubscription: Function;
|
||||
|
||||
state = {
|
||||
refreshing: false,
|
||||
agendaItems: {},
|
||||
calendarShowing: false,
|
||||
};
|
||||
|
||||
onRefresh: Function;
|
||||
onCalendarToggled: Function;
|
||||
getRenderItem: Function;
|
||||
getRenderEmptyDate: Function;
|
||||
onAgendaRef: Function;
|
||||
onCalendarToggled: Function;
|
||||
onBackButtonPressAndroid: Function;
|
||||
currentDate = this.getCurrentDate();
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.webDataManager = new WebDataManager(FETCH_URL);
|
||||
if (i18n.currentLocale().startsWith("fr")) {
|
||||
LocaleConfig.defaultLocale = 'fr';
|
||||
}
|
||||
|
||||
// Create references for functions required in the render function
|
||||
this.onRefresh = this.onRefresh.bind(this);
|
||||
this.onCalendarToggled = this.onCalendarToggled.bind(this);
|
||||
this.getRenderItem = this.getRenderItem.bind(this);
|
||||
this.getRenderEmptyDate = this.getRenderEmptyDate.bind(this);
|
||||
this.onAgendaRef = this.onAgendaRef.bind(this);
|
||||
this.onCalendarToggled = this.onCalendarToggled.bind(this);
|
||||
this.onBackButtonPressAndroid = this.onBackButtonPressAndroid.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.onRefresh();
|
||||
this.didFocusSubscription = this.props.navigation.addListener(
|
||||
'focus',
|
||||
() =>
|
||||
BackHandler.addEventListener(
|
||||
'hardwareBackPress',
|
||||
this.onBackButtonPressAndroid
|
||||
)
|
||||
);
|
||||
this.willBlurSubscription = this.props.navigation.addListener(
|
||||
'blur',
|
||||
() =>
|
||||
BackHandler.removeEventListener(
|
||||
'hardwareBackPress',
|
||||
this.onBackButtonPressAndroid
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onBackButtonPressAndroid() {
|
||||
if (this.state.calendarShowing) {
|
||||
this.agendaRef.chooseDay(this.agendaRef.state.selectedDay);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
getCurrentDate() {
|
||||
let today = new Date();
|
||||
return this.getFormattedDate(today);
|
||||
}
|
||||
|
||||
getFormattedDate(date: Date) {
|
||||
let dd = String(date.getDate()).padStart(2, '0');
|
||||
let mm = String(date.getMonth() + 1).padStart(2, '0'); //January is 0!
|
||||
let yyyy = date.getFullYear();
|
||||
return yyyy + '-' + mm + '-' + dd;
|
||||
}
|
||||
|
||||
generateEmptyCalendar() {
|
||||
let end = new Date(new Date().setMonth(new Date().getMonth() + AGENDA_MONTH_SPAN + 1));
|
||||
let daysOfYear = {};
|
||||
for (let d = new Date(2019, 8, 1); d <= end; d.setDate(d.getDate() + 1)) {
|
||||
daysOfYear[this.getFormattedDate(new Date(d))] = []
|
||||
}
|
||||
return daysOfYear;
|
||||
}
|
||||
|
||||
getRenderItem(item: Object) {
|
||||
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>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<View>
|
||||
<Divider/>
|
||||
<List.Item
|
||||
title={item.title}
|
||||
description={PlanningEventManager.getFormattedTime(item)}
|
||||
onPress={onPress}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getRenderEmptyDate() {
|
||||
return (
|
||||
<Divider/>
|
||||
);
|
||||
}
|
||||
|
||||
rowHasChanged(r1: Object, r2: Object) {
|
||||
return false;
|
||||
// if (r1 !== undefined && r2 !== undefined)
|
||||
// return r1.title !== r2.title;
|
||||
// else return !(r1 === undefined && r2 === undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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((fetchedData) => {
|
||||
this.setState({
|
||||
refreshing: false,
|
||||
});
|
||||
this.generateEventAgenda(fetchedData);
|
||||
this.lastRefresh = new Date();
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
refreshing: false,
|
||||
});
|
||||
// console.log(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
generateEventAgenda(eventList: Array<Object>) {
|
||||
let agendaItems = this.generateEmptyCalendar();
|
||||
for (let i = 0; i < eventList.length; i++) {
|
||||
if (agendaItems[PlanningEventManager.getEventStartDate(eventList[i])] !== undefined) {
|
||||
this.pushEventInOrder(agendaItems, eventList[i], PlanningEventManager.getEventStartDate(eventList[i]));
|
||||
}
|
||||
}
|
||||
this.setState({agendaItems: agendaItems})
|
||||
}
|
||||
|
||||
pushEventInOrder(agendaItems: Object, event: Object, startDate: string) {
|
||||
if (agendaItems[startDate].length === 0)
|
||||
agendaItems[startDate].push(event);
|
||||
else {
|
||||
for (let i = 0; i < agendaItems[startDate].length; i++) {
|
||||
if (PlanningEventManager.isEventBefore(event, agendaItems[startDate][i])) {
|
||||
agendaItems[startDate].splice(i, 0, event);
|
||||
break;
|
||||
} else if (i === agendaItems[startDate].length - 1) {
|
||||
agendaItems[startDate].push(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onAgendaRef(ref: Agenda) {
|
||||
this.agendaRef = ref;
|
||||
}
|
||||
|
||||
onCalendarToggled(isCalendarOpened: boolean) {
|
||||
this.setState({calendarShowing: isCalendarOpened});
|
||||
}
|
||||
|
||||
render() {
|
||||
// console.log("rendering PlanningScreen");
|
||||
return (
|
||||
<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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
68
screens/PlanningDisplayScreen.js
Normal file
68
screens/PlanningDisplayScreen.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// @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 ThemeManager from "../utils/ThemeManager";
|
||||
import HTML from "react-native-render-html";
|
||||
import {Linking} from "expo";
|
||||
import PlanningEventManager from '../utils/PlanningEventManager';
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
};
|
||||
|
||||
function openWebLink(event, link) {
|
||||
Linking.openURL(link).catch((err) => console.error('Error opening link', err));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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> {
|
||||
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/>}
|
||||
|
||||
{displayData.description !== null ?
|
||||
// Surround description with div to allow text styling if the description is not html
|
||||
<HTML html={"<div>" + displayData.description + "</div>"}
|
||||
tagsStyles={{
|
||||
p: {
|
||||
color: ThemeManager.getCurrentThemeVariables().textColor,
|
||||
fontSize: ThemeManager.getCurrentThemeVariables().fontSizeBase
|
||||
},
|
||||
div: {color: ThemeManager.getCurrentThemeVariables().textColor}
|
||||
}}
|
||||
onLinkPress={openWebLink}/>
|
||||
: <View/>}
|
||||
</Content>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
336
screens/PlanningScreen.js
Normal file
336
screens/PlanningScreen.js
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {BackHandler, Image} from 'react-native';
|
||||
import {H3, Text, View} from 'native-base';
|
||||
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 WebDataManager from "../utils/WebDataManager";
|
||||
import PlanningEventManager from '../utils/PlanningEventManager';
|
||||
|
||||
LocaleConfig.locales['fr'] = {
|
||||
monthNames: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
|
||||
monthNamesShort: ['Janv.', 'Févr.', 'Mars', 'Avril', 'Mai', 'Juin', 'Juil.', 'Août', 'Sept.', 'Oct.', 'Nov.', 'Déc.'],
|
||||
dayNames: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'],
|
||||
dayNamesShort: ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'],
|
||||
today: 'Aujourd\'hui'
|
||||
};
|
||||
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
}
|
||||
|
||||
type State = {
|
||||
refreshing: boolean,
|
||||
agendaItems: Object,
|
||||
calendarShowing: boolean,
|
||||
};
|
||||
|
||||
const FETCH_URL = "https://amicale-insat.fr/event/json/list";
|
||||
|
||||
const AGENDA_MONTH_SPAN = 6;
|
||||
|
||||
/**
|
||||
* Class defining the app's planning screen
|
||||
*/
|
||||
export default class PlanningScreen extends React.Component<Props, State> {
|
||||
|
||||
agendaRef: Agenda;
|
||||
webDataManager: WebDataManager;
|
||||
|
||||
lastRefresh: Date;
|
||||
minTimeBetweenRefresh = 60;
|
||||
|
||||
didFocusSubscription: Function;
|
||||
willBlurSubscription: Function;
|
||||
|
||||
state = {
|
||||
refreshing: false,
|
||||
agendaItems: {},
|
||||
calendarShowing: false,
|
||||
};
|
||||
|
||||
onRefresh: Function;
|
||||
onCalendarToggled: Function;
|
||||
getRenderItem: Function;
|
||||
getRenderEmptyDate: Function;
|
||||
onAgendaRef: Function;
|
||||
onCalendarToggled: Function;
|
||||
onBackButtonPressAndroid: Function;
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
// Create references for functions required in the render function
|
||||
this.onRefresh = this.onRefresh.bind(this);
|
||||
this.onCalendarToggled = this.onCalendarToggled.bind(this);
|
||||
this.getRenderItem = this.getRenderItem.bind(this);
|
||||
this.getRenderEmptyDate = this.getRenderEmptyDate.bind(this);
|
||||
this.onAgendaRef = this.onAgendaRef.bind(this);
|
||||
this.onCalendarToggled = this.onCalendarToggled.bind(this);
|
||||
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.willBlurSubscription = this.props.navigation.addListener(
|
||||
'willBlur',
|
||||
() =>
|
||||
BackHandler.removeEventListener(
|
||||
'hardwareBackPress',
|
||||
this.onBackButtonPressAndroid
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onBackButtonPressAndroid() {
|
||||
if (this.state.calendarShowing) {
|
||||
this.agendaRef.chooseDay(this.agendaRef.state.selectedDay);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
componentWillUnmount() {
|
||||
this.didFocusSubscription && this.didFocusSubscription.remove();
|
||||
this.willBlurSubscription && this.willBlurSubscription.remove();
|
||||
}
|
||||
|
||||
getCurrentDate() {
|
||||
let today = new Date();
|
||||
return this.getFormattedDate(today);
|
||||
}
|
||||
|
||||
getFormattedDate(date: Date) {
|
||||
let dd = String(date.getDate()).padStart(2, '0');
|
||||
let mm = String(date.getMonth() + 1).padStart(2, '0'); //January is 0!
|
||||
let yyyy = date.getFullYear();
|
||||
return yyyy + '-' + mm + '-' + dd;
|
||||
}
|
||||
|
||||
generateEmptyCalendar() {
|
||||
let end = new Date(new Date().setMonth(new Date().getMonth() + AGENDA_MONTH_SPAN + 1));
|
||||
let daysOfYear = {};
|
||||
for (let d = new Date(2019, 8, 1); d <= end; d.setDate(d.getDate() + 1)) {
|
||||
daysOfYear[this.getFormattedDate(new Date(d))] = []
|
||||
}
|
||||
return daysOfYear;
|
||||
}
|
||||
|
||||
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>
|
||||
</View>
|
||||
</Touchable>
|
||||
);
|
||||
}
|
||||
|
||||
getRenderEmptyDate() {
|
||||
return (
|
||||
<View style={{
|
||||
padding: 10,
|
||||
flex: 1,
|
||||
}}>
|
||||
<View style={{
|
||||
width: '100%',
|
||||
height: 1,
|
||||
backgroundColor: ThemeManager.getCurrentThemeVariables().agendaEmptyLine,
|
||||
marginTop: 'auto',
|
||||
marginBottom: 'auto',
|
||||
}}/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
rowHasChanged(r1: Object, r2: Object) {
|
||||
if (r1 !== undefined && r2 !== undefined)
|
||||
return r1.title !== r2.title;
|
||||
else return !(r1 === undefined && r2 === undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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((fetchedData) => {
|
||||
this.setState({
|
||||
refreshing: false,
|
||||
});
|
||||
this.generateEventAgenda(fetchedData);
|
||||
this.lastRefresh = new Date();
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
refreshing: false,
|
||||
});
|
||||
// console.log(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
generateEventAgenda(eventList: Array<Object>) {
|
||||
let agendaItems = this.generateEmptyCalendar();
|
||||
for (let i = 0; i < eventList.length; i++) {
|
||||
if (agendaItems[PlanningEventManager.getEventStartDate(eventList[i])] !== undefined) {
|
||||
this.pushEventInOrder(agendaItems, eventList[i], PlanningEventManager.getEventStartDate(eventList[i]));
|
||||
}
|
||||
}
|
||||
this.setState({agendaItems: agendaItems})
|
||||
}
|
||||
|
||||
pushEventInOrder(agendaItems: Object, event: Object, startDate: string) {
|
||||
if (agendaItems[startDate].length === 0)
|
||||
agendaItems[startDate].push(event);
|
||||
else {
|
||||
for (let i = 0; i < agendaItems[startDate].length; i++) {
|
||||
if (PlanningEventManager.isEventBefore(event, agendaItems[startDate][i])) {
|
||||
agendaItems[startDate].splice(i, 0, event);
|
||||
break;
|
||||
} else if (i === agendaItems[startDate].length - 1) {
|
||||
agendaItems[startDate].push(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onAgendaRef(ref: Agenda) {
|
||||
this.agendaRef = ref;
|
||||
}
|
||||
|
||||
onCalendarToggled(isCalendarOpened: boolean) {
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {Image, ScrollView, View} from 'react-native';
|
||||
import {Image, View} from 'react-native';
|
||||
import {Card, CardItem, Container, Content, H2, Left, Text} from 'native-base';
|
||||
import CustomHeader from "../../components/CustomHeader";
|
||||
import i18n from "i18n-js";
|
||||
import {Card, List, Paragraph, Text} from 'react-native-paper';
|
||||
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
|
|
@ -15,41 +17,49 @@ type Props = {
|
|||
export default class ProximoAboutScreen extends React.Component<Props> {
|
||||
|
||||
render() {
|
||||
const nav = this.props.navigation;
|
||||
return (
|
||||
<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>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,20 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {Platform, Image, ScrollView, View} from "react-native";
|
||||
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 i18n from "i18n-js";
|
||||
import CustomModal from "../../components/CustomModal";
|
||||
import {Avatar, IconButton, List, RadioButton, Searchbar, Subheading, Text, Title, withTheme} from "react-native-paper";
|
||||
import PureFlatList from "../../components/PureFlatList";
|
||||
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
|
||||
import ThemeManager from "../../utils/ThemeManager";
|
||||
import {Modalize} from 'react-native-modalize';
|
||||
|
||||
const sortMode = {
|
||||
price: "0",
|
||||
name: '1',
|
||||
};
|
||||
|
||||
function sortPrice(a, b) {
|
||||
return a.price - b.price;
|
||||
|
|
@ -16,118 +25,136 @@ function sortPriceReverse(a, b) {
|
|||
}
|
||||
|
||||
function sortName(a, b) {
|
||||
if (a.name.toLowerCase() < b.name.toLowerCase())
|
||||
if (a.name < b.name)
|
||||
return -1;
|
||||
if (a.name.toLowerCase() > b.name.toLowerCase())
|
||||
if (a.name > b.name)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function sortNameReverse(a, b) {
|
||||
if (a.name.toLowerCase() < b.name.toLowerCase())
|
||||
if (a.name < b.name)
|
||||
return 1;
|
||||
if (a.name.toLowerCase() > b.name.toLowerCase())
|
||||
if (a.name > b.name)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
route: Object,
|
||||
navigation: Object
|
||||
}
|
||||
|
||||
type State = {
|
||||
currentSortMode: number,
|
||||
modalCurrentDisplayItem: React.Node,
|
||||
currentSortMode: string,
|
||||
isSortReversed: boolean,
|
||||
sortPriceIcon: React.Node,
|
||||
sortNameIcon: React.Node,
|
||||
modalCurrentDisplayItem: Object,
|
||||
currentlyDisplayedData: Array<Object>,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class defining proximo's article list of a certain category.
|
||||
*/
|
||||
class ProximoListScreen extends React.Component<Props, State> {
|
||||
export default class ProximoListScreen extends React.Component<Props, State> {
|
||||
|
||||
modalRef: Object;
|
||||
modalRef: { current: null | Modalize };
|
||||
originalData: Array<Object>;
|
||||
shouldFocusSearchBar: boolean;
|
||||
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;
|
||||
|
||||
onMenuRef: Function;
|
||||
onSearchStringChange: Function;
|
||||
onSelectSortModeName: Function;
|
||||
onSelectSortModePrice: Function;
|
||||
onSortMenuPress: Function;
|
||||
renderItem: Function;
|
||||
onModalRef: Function;
|
||||
onListItemPress: Function;
|
||||
|
||||
colors: Object;
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.originalData = this.props.route.params['data']['data'];
|
||||
this.shouldFocusSearchBar = this.props.route.params['shouldFocusSearchBar'];
|
||||
this.state = {
|
||||
currentlyDisplayedData: this.originalData.sort(sortName),
|
||||
currentSortMode: 3,
|
||||
modalCurrentDisplayItem: null,
|
||||
};
|
||||
this.modalRef = React.createRef();
|
||||
this.originalData = this.navData['data'];
|
||||
|
||||
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);
|
||||
this.onModalRef = this.onModalRef.bind(this);
|
||||
this.colors = props.theme.colors;
|
||||
this.onListItemPress = this.onListItemPress.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the reference to the sort menu for later use
|
||||
*
|
||||
* @param ref The menu reference
|
||||
*/
|
||||
onMenuRef(ref: Menu) {
|
||||
this.sortMenuRef = ref;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the sort mode from state when components are ready
|
||||
* 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
|
||||
*/
|
||||
componentDidMount() {
|
||||
const button = this.getSortMenu.bind(this);
|
||||
const title = this.getSearchBar.bind(this);
|
||||
this.props.navigation.setOptions({
|
||||
headerRight: button,
|
||||
headerTitle: title,
|
||||
headerBackTitleVisible: false,
|
||||
headerTitleContainerStyle: Platform.OS === 'ios' ?
|
||||
{marginHorizontal: 0, width: '70%'} :
|
||||
{marginHorizontal: 0, right: 50, left: 50},
|
||||
});
|
||||
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 number representing the mode
|
||||
* @param mode The string representing the mode
|
||||
* @param isReverse Whether to use a reverse sort
|
||||
*/
|
||||
setSortMode(mode: number) {
|
||||
setSortMode(mode: string, isReverse: boolean) {
|
||||
this.setState({
|
||||
currentSortMode: mode,
|
||||
isSortReversed: isReverse
|
||||
});
|
||||
let data = this.state.currentlyDisplayedData;
|
||||
switch (mode) {
|
||||
case 1:
|
||||
data.sort(sortPrice);
|
||||
case sortMode.price:
|
||||
if (isReverse) {
|
||||
data.sort(sortPriceReverse);
|
||||
} else {
|
||||
data.sort(sortPrice);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
data.sort(sortPriceReverse);
|
||||
break;
|
||||
case 3:
|
||||
data.sort(sortName);
|
||||
break;
|
||||
case 4:
|
||||
data.sort(sortNameReverse);
|
||||
case sortMode.name:
|
||||
if (isReverse) {
|
||||
data.sort(sortNameReverse);
|
||||
} else {
|
||||
data.sort(sortName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this.modalRef && mode !== this.state.currentSortMode) {
|
||||
this.modalRef.close();
|
||||
}
|
||||
this.setupSortIcons(mode, isReverse);
|
||||
this.sortMenuRef.hide();
|
||||
}
|
||||
|
||||
getSearchBar() {
|
||||
return (
|
||||
<Searchbar
|
||||
placeholder={i18n.t('proximoScreen.search')}
|
||||
onChangeText={this.onSearchStringChange}
|
||||
/>
|
||||
);
|
||||
/**
|
||||
* Set the sort mode from state when components are ready
|
||||
*/
|
||||
componentDidMount() {
|
||||
this.setSortMode(this.state.currentSortMode, this.state.isSortReversed);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -139,14 +166,48 @@ class ProximoListScreen extends React.Component<Props, State> {
|
|||
getStockColor(availableStock: number) {
|
||||
let color: string;
|
||||
if (availableStock > 3)
|
||||
color = this.colors.success;
|
||||
color = ThemeManager.getCurrentThemeVariables().brandSuccess;
|
||||
else if (availableStock > 0)
|
||||
color = this.colors.warning;
|
||||
color = ThemeManager.getCurrentThemeVariables().brandWarning;
|
||||
else
|
||||
color = this.colors.danger;
|
||||
color = ThemeManager.getCurrentThemeVariables().brandDanger;
|
||||
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, "");
|
||||
}
|
||||
|
|
@ -175,157 +236,145 @@ class ProximoListScreen extends React.Component<Props, State> {
|
|||
})
|
||||
}
|
||||
|
||||
getModalItemContent(item: Object) {
|
||||
getModalContent() {
|
||||
return (
|
||||
<View style={{
|
||||
flex: 1,
|
||||
padding: 20
|
||||
}}>
|
||||
<Title>{item.name}</Title>
|
||||
<H1>{this.state.modalCurrentDisplayItem.name}</H1>
|
||||
<View style={{
|
||||
flexDirection: 'row',
|
||||
width: '100%',
|
||||
marginTop: 10,
|
||||
}}>
|
||||
<Subheading style={{
|
||||
color: this.getStockColor(parseInt(item.quantity)),
|
||||
<H3 style={{
|
||||
color: this.getStockColor(parseInt(this.state.modalCurrentDisplayItem.quantity)),
|
||||
}}>
|
||||
{item.quantity + ' ' + i18n.t('proximoScreen.inStock')}
|
||||
</Subheading>
|
||||
<Subheading style={{marginLeft: 'auto'}}>{item.price}€</Subheading>
|
||||
{this.state.modalCurrentDisplayItem.quantity + ' ' + i18n.t('proximoScreen.inStock')}
|
||||
</H3>
|
||||
<H3 style={{marginLeft: 'auto'}}>{this.state.modalCurrentDisplayItem.price}€</H3>
|
||||
</View>
|
||||
|
||||
<ScrollView>
|
||||
<Content>
|
||||
<View style={{width: '100%', height: 150, marginTop: 20, marginBottom: 20}}>
|
||||
<Image style={{flex: 1, resizeMode: "contain"}}
|
||||
source={{uri: item.image}}/>
|
||||
source={{uri: this.state.modalCurrentDisplayItem.image}}/>
|
||||
</View>
|
||||
<Text>{item.description}</Text>
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
getModalSortMenu() {
|
||||
return (
|
||||
<View style={{
|
||||
flex: 1,
|
||||
padding: 20
|
||||
}}>
|
||||
<Title style={{marginBottom: 10}}>{i18n.t('proximoScreen.sortOrder')}</Title>
|
||||
<RadioButton.Group
|
||||
onValueChange={value => this.setSortMode(value)}
|
||||
value={this.state.currentSortMode}
|
||||
>
|
||||
<View style={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
<RadioButton value={1}/>
|
||||
<Text>{i18n.t('proximoScreen.sortPrice')}</Text>
|
||||
</View>
|
||||
<View style={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
<RadioButton value={2}/>
|
||||
<Text>{i18n.t('proximoScreen.sortPriceReverse')}</Text>
|
||||
</View>
|
||||
<View style={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
<RadioButton value={3}/>
|
||||
<Text>{i18n.t('proximoScreen.sortName')}</Text>
|
||||
</View>
|
||||
<View style={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
<RadioButton value={4}/>
|
||||
<Text>{i18n.t('proximoScreen.sortNameReverse')}</Text>
|
||||
</View>
|
||||
</RadioButton.Group>
|
||||
<Text>{this.state.modalCurrentDisplayItem.description}</Text>
|
||||
</Content>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
onListItemPress(item: Object) {
|
||||
this.setState({
|
||||
modalCurrentDisplayItem: this.getModalItemContent(item)
|
||||
modalCurrentDisplayItem: item
|
||||
});
|
||||
if (this.modalRef) {
|
||||
this.modalRef.open();
|
||||
if (this.modalRef.current) {
|
||||
this.modalRef.current.open();
|
||||
}
|
||||
}
|
||||
|
||||
onSelectSortModeName() {
|
||||
this.sortModeSelected(sortMode.name);
|
||||
}
|
||||
|
||||
onSelectSortModePrice() {
|
||||
this.sortModeSelected(sortMode.price);
|
||||
}
|
||||
|
||||
onSortMenuPress() {
|
||||
this.setState({
|
||||
modalCurrentDisplayItem: this.getModalSortMenu()
|
||||
});
|
||||
if (this.modalRef) {
|
||||
this.modalRef.open();
|
||||
}
|
||||
this.sortMenuRef.show();
|
||||
}
|
||||
|
||||
|
||||
getSortMenu() {
|
||||
return (
|
||||
<IconButton
|
||||
icon="sort"
|
||||
color={this.colors.text}
|
||||
size={26}
|
||||
onPress={this.onSortMenuPress}
|
||||
/>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
renderItem({item}: Object) {
|
||||
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={() => <Avatar.Image style={{backgroundColor: 'transparent'}} size={64}
|
||||
source={{uri: item.image}}/>}
|
||||
right={() =>
|
||||
<Text style={{fontWeight: "bold"}}>
|
||||
{item.price}€
|
||||
</Text>}
|
||||
/>
|
||||
);
|
||||
return (<ListItem
|
||||
thumbnail
|
||||
onPress={this.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>);
|
||||
}
|
||||
|
||||
keyExtractor(item: Object) {
|
||||
return item.name + item.code;
|
||||
}
|
||||
|
||||
onModalRef(ref: Object) {
|
||||
this.modalRef = ref;
|
||||
}
|
||||
|
||||
render() {
|
||||
// console.log("rendering ProximoListScreen");
|
||||
const nav = this.props.navigation;
|
||||
return (
|
||||
<View style={{
|
||||
height: '100%'
|
||||
}}>
|
||||
<CustomModal onRef={this.onModalRef}>
|
||||
{this.state.modalCurrentDisplayItem}
|
||||
</CustomModal>
|
||||
<PureFlatList
|
||||
data={this.state.currentlyDisplayedData}
|
||||
keyExtractor={this.keyExtractor}
|
||||
renderItem={this.renderItem}
|
||||
updateData={this.state.currentSortMode}
|
||||
<Container>
|
||||
<Modalize ref={this.modalRef}
|
||||
adjustToContentHeight
|
||||
modalStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
|
||||
{this.getModalContent()}
|
||||
</Modalize>
|
||||
<CustomHeader
|
||||
hasBackButton={true}
|
||||
navigation={nav}
|
||||
hasSearchField={true}
|
||||
searchCallback={this.onSearchStringChange}
|
||||
shouldFocusSearchBar={this.shouldFocusSearchBar}
|
||||
rightButton={this.getSortMenu()}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<FlatList
|
||||
data={this.state.currentlyDisplayedData}
|
||||
extraData={this.state.currentlyDisplayedData}
|
||||
keyExtractor={this.keyExtractor}
|
||||
style={{minHeight: 300, width: '100%'}}
|
||||
renderItem={this.renderItem}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTheme(ProximoListScreen);
|
||||
|
|
|
|||
|
|
@ -1,44 +1,30 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {View} from 'react-native'
|
||||
import {Platform, View} from 'react-native'
|
||||
import {Body, Left, ListItem, Right, Text} from 'native-base';
|
||||
import i18n from "i18n-js";
|
||||
import WebSectionList from "../../components/WebSectionList";
|
||||
import {List, withTheme} from 'react-native-paper';
|
||||
import HeaderButton from "../../components/HeaderButton";
|
||||
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
|
||||
import FetchedDataSectionList from "../../components/FetchedDataSectionList";
|
||||
import ThemeManager from "../../utils/ThemeManager";
|
||||
import Touchable from "react-native-platform-touchable";
|
||||
|
||||
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.
|
||||
*/
|
||||
class ProximoMainScreen extends React.Component<Props, State> {
|
||||
|
||||
articles: Object;
|
||||
export default class ProximoMainScreen extends FetchedDataSectionList {
|
||||
|
||||
onPressSearchBtn: Function;
|
||||
onPressAboutBtn: Function;
|
||||
getRenderItem: Function;
|
||||
createDataset: Function;
|
||||
|
||||
colors: Object;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
constructor() {
|
||||
super(DATA_URL, 0);
|
||||
this.onPressSearchBtn = this.onPressSearchBtn.bind(this);
|
||||
this.onPressAboutBtn = this.onPressAboutBtn.bind(this);
|
||||
this.getRenderItem = this.getRenderItem.bind(this);
|
||||
this.createDataset = this.createDataset.bind(this);
|
||||
this.colors = props.theme.colors;
|
||||
}
|
||||
|
||||
static sortFinalData(a: Object, b: Object) {
|
||||
|
|
@ -59,11 +45,12 @@ class ProximoMainScreen extends React.Component<Props, State> {
|
|||
return 0;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const rightButton = this.getRightButton.bind(this);
|
||||
this.props.navigation.setOptions({
|
||||
headerRight: rightButton,
|
||||
});
|
||||
getHeaderTranslation() {
|
||||
return i18n.t("screens.proximo");
|
||||
}
|
||||
|
||||
getUpdateToastTranslations() {
|
||||
return [i18n.t("proximoScreen.listUpdated"), i18n.t("proximoScreen.listUpdateFail")];
|
||||
}
|
||||
|
||||
getKeyExtractor(item: Object) {
|
||||
|
|
@ -75,7 +62,7 @@ class ProximoMainScreen extends React.Component<Props, State> {
|
|||
{
|
||||
title: '',
|
||||
data: this.generateData(fetchedData),
|
||||
extraData: this.state,
|
||||
extraData: super.state,
|
||||
keyExtractor: this.getKeyExtractor
|
||||
}
|
||||
];
|
||||
|
|
@ -90,22 +77,21 @@ class ProximoMainScreen extends React.Component<Props, State> {
|
|||
*/
|
||||
generateData(fetchedData: Object) {
|
||||
let finalData = [];
|
||||
this.articles = undefined;
|
||||
if (fetchedData.types !== undefined && fetchedData.articles !== undefined) {
|
||||
let types = fetchedData.types;
|
||||
this.articles = fetchedData.articles;
|
||||
let articles = fetchedData.articles;
|
||||
finalData.push({
|
||||
type: {
|
||||
id: -1,
|
||||
name: i18n.t('proximoScreen.all'),
|
||||
icon: 'star'
|
||||
},
|
||||
data: this.getAvailableArticles(this.articles, undefined)
|
||||
data: this.getAvailableArticles(articles, undefined)
|
||||
});
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
finalData.push({
|
||||
type: types[i],
|
||||
data: this.getAvailableArticles(this.articles, types[i])
|
||||
data: this.getAvailableArticles(articles, types[i])
|
||||
});
|
||||
|
||||
}
|
||||
|
|
@ -142,8 +128,8 @@ class ProximoMainScreen extends React.Component<Props, State> {
|
|||
name: i18n.t('proximoScreen.all'),
|
||||
icon: 'star'
|
||||
},
|
||||
data: this.articles !== undefined ?
|
||||
this.getAvailableArticles(this.articles, undefined) : []
|
||||
data: this.state.fetchedData.articles !== undefined ?
|
||||
this.getAvailableArticles(this.state.fetchedData.articles, undefined) : []
|
||||
},
|
||||
};
|
||||
this.props.navigation.navigate('ProximoListScreen', searchScreenData);
|
||||
|
|
@ -157,51 +143,63 @@ class ProximoMainScreen extends React.Component<Props, State> {
|
|||
return (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
flexDirection: 'row'
|
||||
}}>
|
||||
<HeaderButton icon={'magnify'} onPress={this.onPressSearchBtn}/>
|
||||
<HeaderButton icon={'information'} onPress={this.onPressAboutBtn}/>
|
||||
<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>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
getRenderItem({item}: Object) {
|
||||
getRenderItem(item: Object, section: 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 (
|
||||
<List.Item
|
||||
title={item.type.name}
|
||||
description={subtitle}
|
||||
<ListItem
|
||||
button
|
||||
thumbnail
|
||||
onPress={onPress}
|
||||
left={props => <List.Icon
|
||||
{...props}
|
||||
icon={item.type.icon}
|
||||
color={this.colors.primary}/>}
|
||||
right={props => <List.Icon {...props} icon={'chevron-right'}/>}
|
||||
/>
|
||||
>
|
||||
<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>
|
||||
);
|
||||
} else
|
||||
} else {
|
||||
return <View/>;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const nav = this.props.navigation;
|
||||
return (
|
||||
<WebSectionList
|
||||
createDataset={this.createDataset}
|
||||
navigation={nav}
|
||||
autoRefreshTime={0}
|
||||
refreshOnFocus={false}
|
||||
fetchUrl={DATA_URL}
|
||||
renderItem={this.getRenderItem}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTheme(ProximoMainScreen);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {Image, ScrollView, View} from 'react-native';
|
||||
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 i18n from "i18n-js";
|
||||
import {Card, List, Paragraph, Text, Title} from 'react-native-paper';
|
||||
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
|
||||
import ThemeManager from "../../utils/ThemeManager";
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
|
|
@ -15,68 +18,132 @@ type Props = {
|
|||
export default class ProxiwashAboutScreen extends React.Component<Props> {
|
||||
|
||||
render() {
|
||||
const nav = this.props.navigation;
|
||||
return (
|
||||
<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>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,117 +2,90 @@
|
|||
|
||||
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 WebSectionList from "../../components/WebSectionList";
|
||||
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
|
||||
import FetchedDataSectionList from "../../components/FetchedDataSectionList";
|
||||
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, withTheme} from 'react-native-paper';
|
||||
import HeaderButton from "../../components/HeaderButton";
|
||||
import ProxiwashListItem from "../../components/ProxiwashListItem";
|
||||
import ProxiwashConstants from "../../constants/ProxiwashConstants";
|
||||
import CustomModal from "../../components/CustomModal";
|
||||
import AprilFoolsManager from "../../utils/AprilFoolsManager";
|
||||
|
||||
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,
|
||||
theme: 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
|
||||
*/
|
||||
class ProxiwashScreen extends React.Component<Props, State> {
|
||||
|
||||
modalRef: Object;
|
||||
export default class ProxiwashScreen extends FetchedDataSectionList {
|
||||
|
||||
onAboutPress: Function;
|
||||
getRenderItem: Function;
|
||||
getRenderSectionHeader: Function;
|
||||
createDataset: Function;
|
||||
onHideBanner: Function;
|
||||
onModalRef: Function;
|
||||
|
||||
fetchedData: Object;
|
||||
colors: 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(props) {
|
||||
super(props);
|
||||
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');
|
||||
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;
|
||||
|
||||
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');
|
||||
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');
|
||||
|
||||
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';
|
||||
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';
|
||||
|
||||
// let dataString = AsyncStorageManager.getInstance().preferences.proxiwashWatchedMachines.current;
|
||||
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);
|
||||
this.onModalRef = this.onModalRef.bind(this);
|
||||
this.colors = props.theme.colors;
|
||||
}
|
||||
this.state = {
|
||||
refreshing: false,
|
||||
firstLoading: true,
|
||||
fetchedData: {},
|
||||
// machinesWatched: JSON.parse(dataString),
|
||||
machinesWatched: [],
|
||||
};
|
||||
this.setMinTimeRefresh(30);
|
||||
|
||||
onHideBanner() {
|
||||
this.setState({bannerVisible: false});
|
||||
AsyncStorageManager.getInstance().savePref(
|
||||
AsyncStorageManager.getInstance().preferences.proxiwashShowBanner.key,
|
||||
'0'
|
||||
);
|
||||
this.onAboutPress = this.onAboutPress.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup notification channel for android and add listeners to detect notifications fired
|
||||
*/
|
||||
componentDidMount() {
|
||||
const rightButton = this.getRightButton.bind(this);
|
||||
this.props.navigation.setOptions({
|
||||
headerRight: rightButton,
|
||||
});
|
||||
super.componentDidMount();
|
||||
if (AsyncStorageManager.getInstance().preferences.expoToken.current !== '') {
|
||||
// Get latest watchlist from server
|
||||
NotificationsManager.getMachineNotificationWatchlist((fetchedList) => {
|
||||
|
|
@ -134,6 +107,14 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -230,107 +211,68 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
createDataset(fetchedData: Object) {
|
||||
let data = fetchedData;
|
||||
if (AprilFoolsManager.getInstance().isAprilFoolsEnabled()) {
|
||||
data = JSON.parse(JSON.stringify(fetchedData)); // Deep copy
|
||||
AprilFoolsManager.getNewProxiwashDryerOrderedList(data.dryers);
|
||||
AprilFoolsManager.getNewProxiwashWasherOrderedList(data.washers);
|
||||
}
|
||||
this.fetchedData = fetchedData;
|
||||
|
||||
return [
|
||||
{
|
||||
title: i18n.t('proxiwashScreen.dryers'),
|
||||
icon: 'tumble-dryer',
|
||||
data: data.dryers === undefined ? [] : data.dryers,
|
||||
extraData: this.state,
|
||||
keyExtractor: this.getDryersKeyExtractor
|
||||
},
|
||||
{
|
||||
title: i18n.t('proxiwashScreen.washers'),
|
||||
icon: 'washing-machine',
|
||||
data: data.washers === undefined ? [] : data.washers,
|
||||
extraData: this.state,
|
||||
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,
|
||||
keyExtractor: this.getDryersKeyExtractor
|
||||
},
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
showModal(title: string, item: Object, isDryer: boolean) {
|
||||
this.setState({
|
||||
modalCurrentDisplayItem: this.getModalContent(title, item, isDryer)
|
||||
});
|
||||
if (this.modalRef) {
|
||||
this.modalRef.open();
|
||||
}
|
||||
hasTabs(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
onSetupNotificationsPress(machineId: string) {
|
||||
if (this.modalRef) {
|
||||
this.modalRef.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 =
|
||||
/**
|
||||
* 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 = [
|
||||
{
|
||||
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 (ProxiwashConstants.machineStates[item.state] === ProxiwashConstants.machineStates.DISPONIBLE) {
|
||||
} else if (MACHINE_STATES[item.state] === MACHINE_STATES.DISPONIBLE) {
|
||||
if (isDryer)
|
||||
message += '\n' + i18n.t('proxiwashScreen.dryersTariff');
|
||||
else
|
||||
message += '\n' + i18n.t('proxiwashScreen.washersTariff');
|
||||
}
|
||||
return (
|
||||
<View style={{
|
||||
flex: 1,
|
||||
padding: 20
|
||||
}}>
|
||||
<Card.Title
|
||||
title={title}
|
||||
left={() => <Avatar.Icon
|
||||
icon={isDryer ? 'tumble-dryer' : 'washing-machine'}
|
||||
color={this.colors.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>
|
||||
Alert.alert(
|
||||
title,
|
||||
message,
|
||||
buttons
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -338,65 +280,15 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
|||
this.props.navigation.navigate('ProxiwashAboutScreen');
|
||||
}
|
||||
|
||||
getRightButton() {
|
||||
getRightButton(): * {
|
||||
return (
|
||||
<HeaderButton icon={'information'} onPress={this.onAboutPress}/>
|
||||
);
|
||||
}
|
||||
|
||||
onModalRef(ref: Object) {
|
||||
this.modalRef = ref;
|
||||
}
|
||||
|
||||
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 isDryer = section.title === i18n.t('proxiwashScreen.dryers');
|
||||
const nbAvailable = this.getMachineAvailableNumber(isDryer);
|
||||
const subtitle = nbAvailable + ' ' + ((nbAvailable <= 1) ? i18n.t('proxiwashScreen.numAvailable')
|
||||
: i18n.t('proxiwashScreen.numAvailablePlural'));
|
||||
return (
|
||||
<View style={{
|
||||
flexDirection: 'row',
|
||||
marginLeft: 5,
|
||||
marginRight: 5,
|
||||
marginBottom: 10,
|
||||
marginTop: 20,
|
||||
}}>
|
||||
<Avatar.Icon
|
||||
icon={isDryer ? 'tumble-dryer' : 'washing-machine'}
|
||||
color={this.colors.primary}
|
||||
style={{backgroundColor: 'transparent'}}
|
||||
/>
|
||||
<View style={{
|
||||
justifyContent: 'center',
|
||||
}}>
|
||||
<Text style={{
|
||||
fontSize: 20,
|
||||
fontWeight: 'bold',
|
||||
}}>
|
||||
{section.title}
|
||||
</Text>
|
||||
|
||||
<Text style={{
|
||||
color: this.colors.subtitle,
|
||||
}}>
|
||||
{subtitle}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<Touchable
|
||||
style={{padding: 6}}
|
||||
onPress={this.onAboutPress}>
|
||||
<CustomMaterialIcon
|
||||
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
|
||||
icon="information"/>
|
||||
</Touchable>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -407,69 +299,77 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
|||
* @param section The object describing the current SectionList section
|
||||
* @returns {React.Node}
|
||||
*/
|
||||
getRenderItem({item, section}: Object) {
|
||||
const isMachineRunning = ProxiwashConstants.machineStates[item.state] === ProxiwashConstants.machineStates["EN COURS"];
|
||||
let displayNumber = item.number;
|
||||
if (AprilFoolsManager.getInstance().isAprilFoolsEnabled())
|
||||
displayNumber = AprilFoolsManager.getProxiwashMachineDisplayNumber(parseInt(item.number));
|
||||
const machineName = (section.title === i18n.t('proxiwashScreen.dryers') ?
|
||||
i18n.t('proxiwashScreen.dryer') :
|
||||
i18n.t('proxiwashScreen.washer')) + ' n°' + displayNumber;
|
||||
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%';
|
||||
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);
|
||||
return (
|
||||
<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]]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
<Card style={{
|
||||
flex: 0,
|
||||
height: 64,
|
||||
marginLeft: 10,
|
||||
marginRight: 10
|
||||
}}>
|
||||
|
||||
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}
|
||||
/>}
|
||||
<CardItem
|
||||
style={{
|
||||
backgroundColor: stateColors[MACHINE_STATES[item.state]],
|
||||
paddingRight: 0,
|
||||
paddingLeft: 0,
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
{i18n.t('proxiwashScreen.enableNotificationsTip')}
|
||||
</Banner>
|
||||
<CustomModal onRef={this.onModalRef}>
|
||||
{this.state.modalCurrentDisplayItem}
|
||||
</CustomModal>
|
||||
<WebSectionList
|
||||
createDataset={this.createDataset}
|
||||
navigation={nav}
|
||||
fetchUrl={DATA_URL}
|
||||
renderItem={this.getRenderItem}
|
||||
renderSectionHeader={this.getRenderSectionHeader}
|
||||
autoRefreshTime={REFRESH_TIME}
|
||||
refreshOnFocus={true}
|
||||
updateData={this.state.machinesWatched.length}/>
|
||||
</View>
|
||||
|
||||
);
|
||||
<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>);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTheme(ProxiwashScreen);
|
||||
|
|
|
|||
|
|
@ -2,34 +2,25 @@
|
|||
|
||||
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 WebSectionList from "../components/WebSectionList";
|
||||
import {Card, Text, withTheme} from 'react-native-paper';
|
||||
import AprilFoolsManager from "../utils/AprilFoolsManager";
|
||||
import FetchedDataSectionList from "../components/FetchedDataSectionList";
|
||||
|
||||
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
|
||||
*/
|
||||
class SelfMenuScreen extends React.Component<Props> {
|
||||
export default class SelfMenuScreen extends FetchedDataSectionList {
|
||||
|
||||
// Hard code strings as toLocaleDateString does not work on current android JS engine
|
||||
daysOfWeek = [];
|
||||
monthsOfYear = [];
|
||||
|
||||
getRenderItem: Function;
|
||||
getRenderSectionHeader: Function;
|
||||
createDataset: Function;
|
||||
colors: Object;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
constructor() {
|
||||
super(DATA_URL, 0);
|
||||
this.daysOfWeek.push(i18n.t("date.daysOfWeek.monday"));
|
||||
this.daysOfWeek.push(i18n.t("date.daysOfWeek.tuesday"));
|
||||
this.daysOfWeek.push(i18n.t("date.daysOfWeek.wednesday"));
|
||||
|
|
@ -50,17 +41,32 @@ class SelfMenuScreen extends React.Component<Props> {
|
|||
this.monthsOfYear.push(i18n.t("date.monthsOfYear.october"));
|
||||
this.monthsOfYear.push(i18n.t("date.monthsOfYear.november"));
|
||||
this.monthsOfYear.push(i18n.t("date.monthsOfYear.december"));
|
||||
}
|
||||
|
||||
this.getRenderItem = this.getRenderItem.bind(this);
|
||||
this.getRenderSectionHeader = this.getRenderSectionHeader.bind(this);
|
||||
this.createDataset = this.createDataset.bind(this);
|
||||
this.colors = props.theme.colors;
|
||||
getHeaderTranslation() {
|
||||
return i18n.t("screens.menuSelf");
|
||||
}
|
||||
|
||||
getUpdateToastTranslations() {
|
||||
return [i18n.t("homeScreen.listUpdated"), i18n.t("homeScreen.listUpdateFail")];
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
@ -74,8 +80,6 @@ class SelfMenuScreen extends React.Component<Props> {
|
|||
}
|
||||
];
|
||||
}
|
||||
if (AprilFoolsManager.getInstance().isAprilFoolsEnabled() && fetchedData.length > 0)
|
||||
fetchedData[0].meal[0].foodcategory = AprilFoolsManager.getFakeMenuItem(fetchedData[0].meal[0].foodcategory);
|
||||
// fetched data is an array here
|
||||
for (let i = 0; i < fetchedData.length; i++) {
|
||||
result.push(
|
||||
|
|
@ -97,64 +101,64 @@ class SelfMenuScreen extends React.Component<Props> {
|
|||
return this.daysOfWeek[date.getDay() - 1] + " " + date.getDate() + " " + this.monthsOfYear[date.getMonth()] + " " + date.getFullYear();
|
||||
}
|
||||
|
||||
getRenderSectionHeader({section}: Object) {
|
||||
getRenderSectionHeader(title: string) {
|
||||
return (
|
||||
<Card style={{
|
||||
width: '95%',
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
marginTop: 5,
|
||||
marginBottom: 5,
|
||||
elevation: 4,
|
||||
marginLeft: 10,
|
||||
marginRight: 10,
|
||||
marginTop: 10,
|
||||
marginBottom: 10,
|
||||
borderRadius: 50
|
||||
}}>
|
||||
<Card.Title
|
||||
title={section.title}
|
||||
titleStyle={{
|
||||
textAlign: 'center'
|
||||
}}
|
||||
subtitleStyle={{
|
||||
textAlign: 'center'
|
||||
}}
|
||||
style={{
|
||||
paddingLeft: 0,
|
||||
}}
|
||||
/>
|
||||
<H2 style={{
|
||||
textAlign: 'center',
|
||||
marginTop: 10,
|
||||
marginBottom: 10
|
||||
}}>{title}</H2>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
getRenderItem({item}: Object) {
|
||||
getRenderItem(item: Object, section: Object) {
|
||||
return (
|
||||
<Card style={{
|
||||
flex: 0,
|
||||
marginHorizontal: 10,
|
||||
marginVertical: 5,
|
||||
marginLeft: 20,
|
||||
marginRight: 20
|
||||
}}>
|
||||
<Card.Title
|
||||
style={{marginTop: 5}}
|
||||
title={item.name}
|
||||
/>
|
||||
<View style={{
|
||||
width: '80%',
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: this.colors.primary,
|
||||
marginTop: 5,
|
||||
marginBottom: 5,
|
||||
}}/>
|
||||
<Card.Content>
|
||||
<CardItem style={{
|
||||
paddingBottom: 0,
|
||||
flexDirection: 'column'
|
||||
}}>
|
||||
<H3 style={{
|
||||
marginTop: 10,
|
||||
marginBottom: 0,
|
||||
color: ThemeManager.getCurrentThemeVariables().listNoteColor
|
||||
}}>{item.name}</H3>
|
||||
<View style={{
|
||||
width: '80%',
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: ThemeManager.getCurrentThemeVariables().listBorderColor,
|
||||
marginTop: 10,
|
||||
marginBottom: 5,
|
||||
}}/>
|
||||
</CardItem>
|
||||
<CardItem style={{
|
||||
flexDirection: 'column',
|
||||
paddingTop: 0,
|
||||
}}>
|
||||
{item.dishes.map((object) =>
|
||||
<View>
|
||||
{object.name !== "" ?
|
||||
<Text style={{
|
||||
marginTop: 5,
|
||||
marginBottom: 5,
|
||||
textAlign: 'center'
|
||||
marginBottom: 5
|
||||
}}>{this.formatName(object.name)}</Text>
|
||||
: <View/>}
|
||||
</View>)}
|
||||
</Card.Content>
|
||||
</CardItem>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
|
@ -163,20 +167,5 @@ class SelfMenuScreen extends React.Component<Props> {
|
|||
return name.charAt(0) + name.substr(1).toLowerCase();
|
||||
}
|
||||
|
||||
render() {
|
||||
const nav = this.props.navigation;
|
||||
return (
|
||||
<WebSectionList
|
||||
createDataset={this.createDataset}
|
||||
navigation={nav}
|
||||
autoRefreshTime={0}
|
||||
refreshOnFocus={false}
|
||||
fetchUrl={DATA_URL}
|
||||
renderItem={this.getRenderItem}
|
||||
renderSectionHeader={this.getRenderSectionHeader}
|
||||
stickyHeader={true}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTheme(SelfMenuScreen);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,27 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {ScrollView} from "react-native";
|
||||
import {
|
||||
Body,
|
||||
Card,
|
||||
CardItem,
|
||||
CheckBox,
|
||||
Container,
|
||||
Content,
|
||||
Left,
|
||||
List,
|
||||
ListItem,
|
||||
Picker,
|
||||
Right,
|
||||
Text,
|
||||
} from "native-base";
|
||||
import CustomHeader from "../components/CustomHeader";
|
||||
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';
|
||||
import {Appearance} from "react-native-appearance";
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
|
|
@ -15,7 +29,6 @@ type Props = {
|
|||
|
||||
type State = {
|
||||
nightMode: boolean,
|
||||
nightModeFollowSystem: boolean,
|
||||
proxiwashNotifPickerSelected: string,
|
||||
startScreenPickerSelected: string,
|
||||
};
|
||||
|
|
@ -26,8 +39,6 @@ type State = {
|
|||
export default class SettingsScreen extends React.Component<Props, State> {
|
||||
state = {
|
||||
nightMode: ThemeManager.getNightMode(),
|
||||
nightModeFollowSystem: AsyncStorageManager.getInstance().preferences.nightModeFollowSystem.current === '1' &&
|
||||
Appearance.getColorScheme() !== 'no-preference',
|
||||
proxiwashNotifPickerSelected: AsyncStorageManager.getInstance().preferences.proxiwashNotifications.current,
|
||||
startScreenPickerSelected: AsyncStorageManager.getInstance().preferences.defaultStartScreen.current,
|
||||
};
|
||||
|
|
@ -35,14 +46,45 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
|||
onProxiwashNotifPickerValueChange: Function;
|
||||
onStartScreenPickerValueChange: Function;
|
||||
onToggleNightMode: Function;
|
||||
onToggleNightModeFollowSystem: Function;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.onProxiwashNotifPickerValueChange = this.onProxiwashNotifPickerValueChange.bind(this);
|
||||
this.onStartScreenPickerValueChange = this.onStartScreenPickerValueChange.bind(this);
|
||||
this.onToggleNightMode = this.onToggleNightMode.bind(this);
|
||||
this.onToggleNightModeFollowSystem = this.onToggleNightModeFollowSystem.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>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -51,17 +93,15 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
|||
* @param value The value to store
|
||||
*/
|
||||
onProxiwashNotifPickerValueChange(value: string) {
|
||||
if (value != null) {
|
||||
let key = AsyncStorageManager.getInstance().preferences.proxiwashNotifications.key;
|
||||
AsyncStorageManager.getInstance().savePref(key, value);
|
||||
this.setState({
|
||||
proxiwashNotifPickerSelected: value
|
||||
});
|
||||
let intVal = 0;
|
||||
if (value !== 'never')
|
||||
intVal = parseInt(value);
|
||||
NotificationsManager.setMachineReminderNotificationTime(intVal);
|
||||
}
|
||||
let key = AsyncStorageManager.getInstance().preferences.proxiwashNotifications.key;
|
||||
AsyncStorageManager.getInstance().savePref(key, value);
|
||||
this.setState({
|
||||
proxiwashNotifPickerSelected: value
|
||||
});
|
||||
let intVal = 0;
|
||||
if (value !== 'never')
|
||||
intVal = parseInt(value);
|
||||
NotificationsManager.setMachineReminderNotificationTime(intVal);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -70,13 +110,11 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
|||
* @param value The value to store
|
||||
*/
|
||||
onStartScreenPickerValueChange(value: string) {
|
||||
if (value != null) {
|
||||
let key = AsyncStorageManager.getInstance().preferences.defaultStartScreen.key;
|
||||
AsyncStorageManager.getInstance().savePref(key, value);
|
||||
this.setState({
|
||||
startScreenPickerSelected: value
|
||||
});
|
||||
}
|
||||
let key = AsyncStorageManager.getInstance().preferences.defaultStartScreen.key;
|
||||
AsyncStorageManager.getInstance().savePref(key, value);
|
||||
this.setState({
|
||||
startScreenPickerSelected: value
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -86,14 +124,19 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
|||
*/
|
||||
getProxiwashNotifPicker() {
|
||||
return (
|
||||
<ToggleButton.Row
|
||||
<Picker
|
||||
note
|
||||
mode="dropdown"
|
||||
style={{width: 120}}
|
||||
selectedValue={this.state.proxiwashNotifPickerSelected}
|
||||
onValueChange={this.onProxiwashNotifPickerValueChange}
|
||||
value={this.state.proxiwashNotifPickerSelected}
|
||||
>
|
||||
<ToggleButton icon="close" value="never"/>
|
||||
<ToggleButton icon="numeric-2" value="2"/>
|
||||
<ToggleButton icon="numeric-5" value="5"/>
|
||||
</ToggleButton.Row>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -104,16 +147,19 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
|||
*/
|
||||
getStartScreenPicker() {
|
||||
return (
|
||||
<ToggleButton.Row
|
||||
<Picker
|
||||
note
|
||||
mode="dropdown"
|
||||
style={{width: 120}}
|
||||
selectedValue={this.state.startScreenPickerSelected}
|
||||
onValueChange={this.onStartScreenPickerValueChange}
|
||||
value={this.state.startScreenPickerSelected}
|
||||
>
|
||||
<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>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -123,18 +169,19 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
|||
onToggleNightMode() {
|
||||
ThemeManager.getInstance().setNightMode(!this.state.nightMode);
|
||||
this.setState({nightMode: !this.state.nightMode});
|
||||
this.resetStack();
|
||||
}
|
||||
|
||||
onToggleNightModeFollowSystem() {
|
||||
const value = !this.state.nightModeFollowSystem;
|
||||
this.setState({nightModeFollowSystem: value});
|
||||
let key = AsyncStorageManager.getInstance().preferences.nightModeFollowSystem.key;
|
||||
AsyncStorageManager.getInstance().savePref(key, value ? '1' : '0');
|
||||
if (value) {
|
||||
const nightMode = Appearance.getColorScheme() === 'dark';
|
||||
ThemeManager.getInstance().setNightMode(nightMode);
|
||||
this.setState({nightMode: nightMode});
|
||||
}
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -146,71 +193,60 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
|||
* @param subtitle The text to display as this list item subtitle
|
||||
* @returns {React.Node}
|
||||
*/
|
||||
getToggleItem(onPressCallback: Function, icon: string, title: string, subtitle: string, state: boolean) {
|
||||
getToggleItem(onPressCallback: Function, icon: string, title: string, subtitle: string) {
|
||||
return (
|
||||
<List.Item
|
||||
title={title}
|
||||
description={subtitle}
|
||||
left={props => <List.Icon {...props} icon={icon}/>}
|
||||
right={props =>
|
||||
<Switch
|
||||
value={state}
|
||||
onValueChange={onPressCallback}
|
||||
/>}
|
||||
/>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const nav = this.props.navigation;
|
||||
return (
|
||||
<ScrollView>
|
||||
<Card style={{margin: 5}}>
|
||||
<Card.Title title={i18n.t('settingsScreen.generalCard')}/>
|
||||
<List.Section>
|
||||
{Appearance.getColorScheme() !== 'no-preference' ? this.getToggleItem(
|
||||
this.onToggleNightModeFollowSystem,
|
||||
'theme-light-dark',
|
||||
i18n.t('settingsScreen.nightModeAuto'),
|
||||
this.state.nightMode ?
|
||||
i18n.t('settingsScreen.nightModeSubOn') :
|
||||
i18n.t('settingsScreen.nightModeSubOff'),
|
||||
this.state.nightModeFollowSystem
|
||||
) : null}
|
||||
{
|
||||
Appearance.getColorScheme() === 'no-preference' || !this.state.nightModeFollowSystem ?
|
||||
this.getToggleItem(
|
||||
this.onToggleNightMode,
|
||||
'theme-light-dark',
|
||||
i18n.t('settingsScreen.nightMode'),
|
||||
this.state.nightMode ?
|
||||
i18n.t('settingsScreen.nightModeSubOn') :
|
||||
i18n.t('settingsScreen.nightModeSubOff'),
|
||||
this.state.nightMode
|
||||
) : null
|
||||
}
|
||||
<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>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
38
screens/Websites/AmicaleScreen.js
Normal file
38
screens/Websites/AmicaleScreen.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// @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}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -11,7 +11,9 @@ 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.
|
||||
|
|
@ -30,6 +32,17 @@ 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() {
|
||||
|
|
@ -50,6 +63,12 @@ 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')}
|
||||
|
|
|
|||
|
|
@ -1,66 +0,0 @@
|
|||
// @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}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
52
screens/Websites/BlueMindScreen.js
Normal file
52
screens/Websites/BlueMindScreen.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// @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}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
38
screens/Websites/ElusEtudScreen.js
Normal file
38
screens/Websites/ElusEtudScreen.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// @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}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue