Update component overrides and intro slides to use TypeScript

This commit is contained in:
Arnaud Vergnet 2020-09-22 14:26:44 +02:00
parent 18f8c64302
commit acc4f8cdcc
14 changed files with 370 additions and 420 deletions

17
package-lock.json generated
View file

@ -2608,6 +2608,17 @@
"@types/react": "*"
}
},
"@types/react-native-calendars": {
"version": "1.20.10",
"resolved": "https://registry.npmjs.org/@types/react-native-calendars/-/react-native-calendars-1.20.10.tgz",
"integrity": "sha512-bmWlkFa/6SNF98aM9rjKMGUOSDb15VBsfxBW5oo/iJ5tm5THf+eAGlxH72hGZFqJpr93plBs+ctkRVHQA7fx1w==",
"dev": true,
"requires": {
"@types/react": "*",
"@types/react-native": "*",
"@types/xdate": "*"
}
},
"@types/react-native-vector-icons": {
"version": "6.4.6",
"resolved": "https://registry.npmjs.org/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.6.tgz",
@ -2632,6 +2643,12 @@
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
"integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw=="
},
"@types/xdate": {
"version": "0.8.31",
"resolved": "https://registry.npmjs.org/@types/xdate/-/xdate-0.8.31.tgz",
"integrity": "sha512-iZYRKKK8UZXoepNh2kwK6TPITMj/dwdv0NzNi9DFMt2foGkU7h+ncaCpGsdD2fp/CXMs9dxPAzV9uddFy7c4QA==",
"dev": true
},
"@types/yargs": {
"version": "15.0.5",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.5.tgz",

View file

@ -67,9 +67,10 @@
"@babel/runtime": "^7.11.0",
"@react-native-community/eslint-config": "^1.1.0",
"@types/i18n-js": "^3.0.3",
"@types/react-native-vector-icons": "^6.4.6",
"@types/jest": "^25.2.3",
"@types/react-native": "^0.63.2",
"@types/react-native-calendars": "^1.20.10",
"@types/react-native-vector-icons": "^6.4.6",
"@types/react-test-renderer": "^16.9.2",
"@typescript-eslint/eslint-plugin": "^2.27.0",
"@typescript-eslint/parser": "^2.27.0",

View file

@ -17,15 +17,13 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
// @flow
import * as React from 'react';
import {StyleSheet, View} from 'react-native';
import * as Animatable from 'react-native-animatable';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
type PropsType = {
icon: string,
icon: string;
};
const styles = StyleSheet.create({
@ -37,24 +35,14 @@ const styles = StyleSheet.create({
},
});
class IntroIcon extends React.Component<PropsType> {
shouldComponentUpdate(): boolean {
return false;
}
render(): React.Node {
const {icon} = this.props;
function IntroIcon(props: PropsType) {
return (
<View style={{flex: 1}}>
<Animatable.View
useNativeDriver
style={styles.center}
animation="fadeIn">
<MaterialCommunityIcons name={icon} color="#fff" size={200} />
<Animatable.View useNativeDriver style={styles.center} animation="fadeIn">
<MaterialCommunityIcons name={props.icon} color="#fff" size={200} />
</Animatable.View>
</View>
);
}
}
export default IntroIcon;

View file

@ -17,8 +17,6 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
// @flow
import * as React from 'react';
import {StyleSheet, View} from 'react-native';
import Mascot, {MASCOT_STYLE} from '../Mascot/Mascot';
@ -32,12 +30,7 @@ const styles = StyleSheet.create({
},
});
class MascotIntroEnd extends React.Component<null> {
shouldComponentUpdate(): boolean {
return false;
}
render(): React.Node {
function MascotIntroEnd() {
return (
<View style={{flex: 1}}>
<Mascot
@ -60,6 +53,5 @@ class MascotIntroEnd extends React.Component<null> {
</View>
);
}
}
export default MascotIntroEnd;

View file

@ -17,8 +17,6 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
// @flow
import * as React from 'react';
import {StyleSheet, View} from 'react-native';
import * as Animatable from 'react-native-animatable';
@ -34,12 +32,7 @@ const styles = StyleSheet.create({
},
});
class MascotIntroWelcome extends React.Component<null> {
shouldComponentUpdate(): boolean {
return false;
}
render(): React.Node {
function MascotIntroWelcome() {
return (
<View style={{flex: 1}}>
<Mascot
@ -90,6 +83,5 @@ class MascotIntroWelcome extends React.Component<null> {
</View>
);
}
}
export default MascotIntroWelcome;

View file

@ -1,82 +0,0 @@
/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
// @flow
import * as React from 'react';
import {View} from 'react-native';
import {withTheme} from 'react-native-paper';
import {Agenda} from 'react-native-calendars';
import type {CustomThemeType} from '../../managers/ThemeManager';
type PropsType = {
theme: CustomThemeType,
onRef: (ref: Agenda) => void,
};
/**
* Abstraction layer for Agenda component, using custom configuration
*/
class CustomAgenda extends React.Component<PropsType> {
getAgenda(): React.Node {
const {props} = this;
return (
<Agenda
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
ref={props.onRef}
theme={{
backgroundColor: props.theme.colors.agendaBackgroundColor,
calendarBackground: props.theme.colors.background,
textSectionTitleColor: props.theme.colors.agendaDayTextColor,
selectedDayBackgroundColor: props.theme.colors.primary,
selectedDayTextColor: '#ffffff',
todayTextColor: props.theme.colors.primary,
dayTextColor: props.theme.colors.text,
textDisabledColor: props.theme.colors.agendaDayTextColor,
dotColor: props.theme.colors.primary,
selectedDotColor: '#ffffff',
arrowColor: 'orange',
monthTextColor: props.theme.colors.primary,
indicatorColor: props.theme.colors.primary,
textDayFontWeight: '300',
textMonthFontWeight: 'bold',
textDayHeaderFontWeight: '300',
textDayFontSize: 16,
textMonthFontSize: 16,
textDayHeaderFontSize: 16,
agendaDayTextColor: props.theme.colors.agendaDayTextColor,
agendaDayNumColor: props.theme.colors.agendaDayTextColor,
agendaTodayColor: props.theme.colors.primary,
agendaKnobColor: props.theme.colors.primary,
}}
/>
);
}
render(): React.Node {
const {props} = this;
// Completely recreate the component on theme change to force theme reload
if (props.theme.dark)
return <View style={{flex: 1}}>{this.getAgenda()}</View>;
return this.getAgenda();
}
}
export default withTheme(CustomAgenda);

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
import * as React from 'react';
import {View} from 'react-native';
import {useTheme} from 'react-native-paper';
import {Agenda, AgendaProps} from 'react-native-calendars';
type PropsType = {
onRef: (ref: Agenda<any>) => void;
} & AgendaProps<any>;
/**
* Abstraction layer for Agenda component, using custom configuration
*/
function CustomAgenda(props: PropsType) {
const theme = useTheme();
function getAgenda() {
return (
<Agenda
{...props}
ref={props.onRef}
theme={{
backgroundColor: theme.colors.agendaBackgroundColor,
calendarBackground: theme.colors.background,
textSectionTitleColor: theme.colors.agendaDayTextColor,
selectedDayBackgroundColor: theme.colors.primary,
selectedDayTextColor: '#ffffff',
todayTextColor: theme.colors.primary,
dayTextColor: theme.colors.text,
textDisabledColor: theme.colors.agendaDayTextColor,
dotColor: theme.colors.primary,
selectedDotColor: '#ffffff',
arrowColor: 'orange',
monthTextColor: theme.colors.primary,
indicatorColor: theme.colors.primary,
textDayFontWeight: '300',
textMonthFontWeight: 'bold',
textDayHeaderFontWeight: '300',
textDayFontSize: 16,
textMonthFontSize: 16,
textDayHeaderFontSize: 16,
agendaDayTextColor: theme.colors.agendaDayTextColor,
agendaDayNumColor: theme.colors.agendaDayTextColor,
agendaTodayColor: theme.colors.primary,
agendaKnobColor: theme.colors.primary,
}}
/>
);
}
// Completely recreate the component on theme change to force theme reload
if (theme.dark) {
return <View style={{flex: 1}}>{getAgenda()}</View>;
}
return getAgenda();
}
export default CustomAgenda;

View file

@ -1,77 +0,0 @@
/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
/* eslint-disable flowtype/require-parameter-type */
// @flow
import * as React from 'react';
import {Text, withTheme} from 'react-native-paper';
import HTML from 'react-native-render-html';
import {Linking} from 'react-native';
import type {CustomThemeType} from '../../managers/ThemeManager';
type PropsType = {
theme: CustomThemeType,
html: string,
};
/**
* Abstraction layer for Agenda component, using custom configuration
*/
class CustomHTML extends React.Component<PropsType> {
openWebLink = (event: {...}, link: string) => {
Linking.openURL(link);
};
getBasicText = (
htmlAttribs,
children,
convertedCSSStyles,
passProps,
): React.Node => {
// eslint-disable-next-line react/jsx-props-no-spreading
return <Text {...passProps}>{children}</Text>;
};
getListBullet = (): React.Node => {
return <Text>- </Text>;
};
render(): React.Node {
const {props} = this;
// Surround description with p to allow text styling if the description is not html
return (
<HTML
html={`<p>${props.html}</p>`}
renderers={{
p: this.getBasicText,
li: this.getBasicText,
}}
listsPrefixesRenderers={{
ul: this.getListBullet,
}}
ignoredTags={['img']}
ignoredStyles={['color', 'background-color']}
onLinkPress={this.openWebLink}
/>
);
}
}
export default withTheme(CustomHTML);

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
import * as React from 'react';
import {Text} from 'react-native-paper';
import HTML from 'react-native-render-html';
import {GestureResponderEvent, Linking} from 'react-native';
type PropsType = {
html: string;
};
/**
* Abstraction layer for Agenda component, using custom configuration
*/
function CustomHTML(props: PropsType) {
const openWebLink = (event: GestureResponderEvent, link: string) => {
Linking.openURL(link);
};
const getBasicText = (
htmlAttribs: any,
children: any,
convertedCSSStyles: any,
passProps: any,
) => {
return <Text {...passProps}>{children}</Text>;
};
const getListBullet = () => {
return <Text>- </Text>;
};
// Surround description with p to allow text styling if the description is not html
return (
<HTML
html={`<p>${props.html}</p>`}
renderers={{
p: getBasicText,
li: getBasicText,
}}
listsPrefixesRenderers={{
ul: getListBullet,
}}
ignoredTags={['img']}
ignoredStyles={['color', 'background-color']}
onLinkPress={openWebLink}
/>
);
}
export default CustomHTML;

View file

@ -17,39 +17,31 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
// @flow
import * as React from 'react';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import {HeaderButton, HeaderButtons} from 'react-navigation-header-buttons';
import {withTheme} from 'react-native-paper';
import type {CustomThemeType} from '../../managers/ThemeManager';
import {
HeaderButton,
HeaderButtonProps,
HeaderButtons,
HeaderButtonsProps,
} from 'react-navigation-header-buttons';
import {useTheme} from 'react-native-paper';
const MaterialHeaderButton = (props: {
theme: CustomThemeType,
color: string,
}): React.Node => {
const {color, theme} = props;
const MaterialHeaderButton = (props: HeaderButtonProps) => {
const theme = useTheme();
return (
// $FlowFixMe
<HeaderButton
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
IconComponent={MaterialCommunityIcons}
iconSize={26}
color={color != null ? color : theme.colors.text}
color={props.color ? props.color : theme.colors.text}
/>
);
};
const MaterialHeaderButtons = (props: {...}): React.Node => {
const MaterialHeaderButtons = (props: HeaderButtonsProps) => {
return (
// $FlowFixMe
<HeaderButtons
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
HeaderButtonComponent={withTheme(MaterialHeaderButton)}
/>
<HeaderButtons {...props} HeaderButtonComponent={MaterialHeaderButton} />
);
};

View file

@ -17,10 +17,14 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
// @flow
import * as React from 'react';
import {Platform, StatusBar, StyleSheet, View} from 'react-native';
import {
ListRenderItemInfo,
Platform,
StatusBar,
StyleSheet,
View,
} from 'react-native';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import i18n from 'i18n-js';
import AppIntroSlider from 'react-native-app-intro-slider';
@ -35,26 +39,27 @@ import IntroIcon from '../Intro/IconIntro';
import MascotIntroEnd from '../Intro/MascotIntroEnd';
type PropsType = {
onDone: () => void,
isUpdate: boolean,
isAprilFools: boolean,
onDone: () => void;
isUpdate: boolean;
isAprilFools: boolean;
};
type StateType = {
currentSlide: number,
currentSlide: number;
};
export type IntroSlideType = {
key: string,
title: string,
text: string,
view: () => React.Node,
mascotStyle?: number,
colors: [string, string],
key: string;
title: string;
text: string;
view: () => React.ReactNode;
mascotStyle?: number;
colors: [string, string];
};
const styles = StyleSheet.create({
mainContent: {
flex: 1,
paddingBottom: 100,
},
text: {
@ -83,7 +88,7 @@ const styles = StyleSheet.create({
*/
export default class CustomIntroSlider extends React.Component<
PropsType,
StateType,
StateType
> {
sliderRef: {current: null | AppIntroSlider};
@ -98,8 +103,9 @@ export default class CustomIntroSlider extends React.Component<
/**
* Generates intro slides
*/
constructor() {
super();
constructor(props: PropsType) {
super(props);
this.currentSlides = [];
this.state = {
currentSlide: 0,
};
@ -109,14 +115,14 @@ export default class CustomIntroSlider extends React.Component<
key: '0', // Mascot
title: i18n.t('intro.slideMain.title'),
text: i18n.t('intro.slideMain.text'),
view: (): React.Node => <MascotIntroWelcome />,
view: () => <MascotIntroWelcome />,
colors: ['#be1522', '#57080e'],
},
{
key: '1',
title: i18n.t('intro.slidePlanex.title'),
text: i18n.t('intro.slidePlanex.text'),
view: (): React.Node => <IntroIcon icon="calendar-clock" />,
view: () => <IntroIcon icon="calendar-clock" />,
mascotStyle: MASCOT_STYLE.INTELLO,
colors: ['#be1522', '#57080e'],
},
@ -124,7 +130,7 @@ export default class CustomIntroSlider extends React.Component<
key: '2',
title: i18n.t('intro.slideEvents.title'),
text: i18n.t('intro.slideEvents.text'),
view: (): React.Node => <IntroIcon icon="calendar-star" />,
view: () => <IntroIcon icon="calendar-star" />,
mascotStyle: MASCOT_STYLE.HAPPY,
colors: ['#be1522', '#57080e'],
},
@ -132,7 +138,7 @@ export default class CustomIntroSlider extends React.Component<
key: '3',
title: i18n.t('intro.slideServices.title'),
text: i18n.t('intro.slideServices.text'),
view: (): React.Node => <IntroIcon icon="view-dashboard-variant" />,
view: () => <IntroIcon icon="view-dashboard-variant" />,
mascotStyle: MASCOT_STYLE.CUTE,
colors: ['#be1522', '#57080e'],
},
@ -140,7 +146,7 @@ export default class CustomIntroSlider extends React.Component<
key: '4',
title: i18n.t('intro.slideDone.title'),
text: i18n.t('intro.slideDone.text'),
view: (): React.Node => <MascotIntroEnd />,
view: () => <MascotIntroEnd />,
colors: ['#9c165b', '#3e042b'],
},
];
@ -152,7 +158,7 @@ export default class CustomIntroSlider extends React.Component<
key: '1',
title: i18n.t('intro.aprilFoolsSlide.title'),
text: i18n.t('intro.aprilFoolsSlide.text'),
view: (): React.Node => <View />,
view: () => <View />,
mascotStyle: MASCOT_STYLE.NORMAL,
colors: ['#e01928', '#be1522'],
},
@ -162,21 +168,21 @@ export default class CustomIntroSlider extends React.Component<
/**
* Render item to be used for the intro introSlides
*
* @param item The item to be displayed
* @param dimensions Dimensions of the item
* @param data
*/
getIntroRenderItem = ({
item,
dimensions,
}: {
item: IntroSlideType,
dimensions: {width: number, height: number},
}): React.Node => {
getIntroRenderItem = (
data:
| (ListRenderItemInfo<IntroSlideType> & {
dimensions: {width: number; height: number};
})
| ListRenderItemInfo<IntroSlideType>,
) => {
const item = data.item;
const {state} = this;
const index = parseInt(item.key, 10);
return (
<LinearGradient
style={[styles.mainContent, dimensions]}
style={[styles.mainContent]}
colors={item.colors}
start={{x: 0, y: 0.1}}
end={{x: 0.1, y: 1}}>
@ -254,7 +260,9 @@ export default class CustomIntroSlider extends React.Component<
};
static setStatusBarColor(color: string) {
if (Platform.OS === 'android') StatusBar.setBackgroundColor(color, true);
if (Platform.OS === 'android') {
StatusBar.setBackgroundColor(color, true);
}
}
onSlideChange = (index: number) => {
@ -266,8 +274,9 @@ export default class CustomIntroSlider extends React.Component<
CustomIntroSlider.setStatusBarColor(
this.currentSlides[this.currentSlides.length - 1].colors[0],
);
if (this.sliderRef.current != null)
if (this.sliderRef.current != null) {
this.sliderRef.current.goToSlide(this.currentSlides.length - 1);
}
};
onDone = () => {
@ -278,7 +287,7 @@ export default class CustomIntroSlider extends React.Component<
props.onDone();
};
getRenderNextButton = (): React.Node => {
getRenderNextButton = () => {
return (
<Animatable.View
useNativeDriver
@ -293,7 +302,7 @@ export default class CustomIntroSlider extends React.Component<
);
};
getRenderDoneButton = (): React.Node => {
getRenderDoneButton = () => {
return (
<Animatable.View
useNativeDriver
@ -308,11 +317,14 @@ export default class CustomIntroSlider extends React.Component<
);
};
render(): React.Node {
render() {
const {props, state} = this;
this.currentSlides = this.introSlides;
if (props.isUpdate) this.currentSlides = this.updateSlides;
else if (props.isAprilFools) this.currentSlides = this.aprilFoolsSlides;
if (props.isUpdate) {
this.currentSlides = this.updateSlides;
} else if (props.isAprilFools) {
this.currentSlides = this.aprilFoolsSlides;
}
CustomIntroSlider.setStatusBarColor(this.currentSlides[0].colors[0]);
return (
<AppIntroSlider

View file

@ -17,14 +17,11 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
// @flow
import * as React from 'react';
import {withTheme} from 'react-native-paper';
import {useTheme} from 'react-native-paper';
import {Modalize} from 'react-native-modalize';
import {View} from 'react-native-animatable';
import CustomTabBar from '../Tabbar/CustomTabBar';
import type {CustomThemeType} from '../../managers/ThemeManager';
/**
* Abstraction layer for Modalize component, using custom configuration
@ -33,11 +30,11 @@ import type {CustomThemeType} from '../../managers/ThemeManager';
* @return {*}
*/
function CustomModal(props: {
theme: CustomThemeType,
onRef: (re: Modalize) => void,
children?: React.Node,
}): React.Node {
const {theme, onRef, children} = props;
onRef: (re: Modalize) => void;
children?: React.ReactNode;
}) {
const theme = useTheme();
const {onRef, children} = props;
return (
<Modalize
ref={onRef}
@ -55,6 +52,4 @@ function CustomModal(props: {
);
}
CustomModal.defaultProps = {children: null};
export default withTheme(CustomModal);
export default CustomModal;

View file

@ -1,84 +0,0 @@
/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
// @flow
import * as React from 'react';
import {Text, withTheme} from 'react-native-paper';
import {View} from 'react-native-animatable';
import Slider, {SliderProps} from '@react-native-community/slider';
import type {CustomThemeType} from '../../managers/ThemeManager';
type PropsType = {
theme: CustomThemeType,
valueSuffix?: string,
...SliderProps,
};
type StateType = {
currentValue: number,
};
/**
* Abstraction layer for Modalize component, using custom configuration
*
* @param props Props to pass to the element. Must specify an onRef prop to get an Modalize ref.
* @return {*}
*/
class CustomSlider extends React.Component<PropsType, StateType> {
static defaultProps = {
valueSuffix: '',
};
constructor(props: PropsType) {
super(props);
this.state = {
currentValue: props.value,
};
}
onValueChange = (value: number) => {
const {props} = this;
this.setState({currentValue: value});
if (props.onValueChange != null) props.onValueChange(value);
};
render(): React.Node {
const {props, state} = this;
return (
<View style={{flex: 1, flexDirection: 'row'}}>
<Text
style={{
marginHorizontal: 10,
marginTop: 'auto',
marginBottom: 'auto',
}}>
{state.currentValue}min
</Text>
<Slider
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
onValueChange={this.onValueChange}
/>
</View>
);
}
}
export default withTheme(CustomSlider);

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
import * as React from 'react';
import {Text} from 'react-native-paper';
import {View} from 'react-native-animatable';
import Slider, {SliderProps} from '@react-native-community/slider';
import {useState} from 'react';
type PropsType = {
valueSuffix?: string;
} & SliderProps;
/**
* Abstraction layer for Modalize component, using custom configuration
*
* @param props Props to pass to the element. Must specify an onRef prop to get an Modalize ref.
* @return {*}
*/
function CustomSlider(props: PropsType) {
const [currentValue, setCurrentValue] = useState(props.value);
const onValueChange = (value: number) => {
setCurrentValue(value);
if (props.onValueChange) {
props.onValueChange(value);
}
};
return (
<View style={{flex: 1, flexDirection: 'row'}}>
<Text
style={{
marginHorizontal: 10,
marginTop: 'auto',
marginBottom: 'auto',
}}>
{currentValue}min
</Text>
<Slider {...props} ref={undefined} onValueChange={onValueChange} />
</View>
);
}
export default CustomSlider;