Improve override components to match linter

This commit is contained in:
Arnaud Vergnet 2020-08-04 21:24:43 +02:00
parent 7b94afadcc
commit 4db4516296
6 changed files with 573 additions and 543 deletions

View file

@ -1,58 +1,61 @@
import * as React from 'react'; // @flow
import {View} from "react-native";
import {withTheme} from 'react-native-paper';
import {Agenda} from "react-native-calendars";
type Props = { import * as React from 'react';
theme: Object, import {View} from 'react-native';
} import {withTheme} from 'react-native-paper';
import {Agenda} from 'react-native-calendars';
import type {CustomTheme} from '../../managers/ThemeManager';
type PropsType = {
theme: CustomTheme,
onRef: (ref: Agenda) => void,
};
/** /**
* Abstraction layer for Agenda component, using custom configuration * Abstraction layer for Agenda component, using custom configuration
*/ */
class CustomAgenda extends React.Component<Props> { class CustomAgenda extends React.Component<PropsType> {
getAgenda(): React.Node {
getAgenda() { const {props} = this;
return <Agenda return (
{...this.props} <Agenda
ref={this.props.onRef} // eslint-disable-next-line react/jsx-props-no-spreading
{...props}
ref={props.onRef}
theme={{ theme={{
backgroundColor: this.props.theme.colors.agendaBackgroundColor, backgroundColor: props.theme.colors.agendaBackgroundColor,
calendarBackground: this.props.theme.colors.background, calendarBackground: props.theme.colors.background,
textSectionTitleColor: this.props.theme.colors.agendaDayTextColor, textSectionTitleColor: props.theme.colors.agendaDayTextColor,
selectedDayBackgroundColor: this.props.theme.colors.primary, selectedDayBackgroundColor: props.theme.colors.primary,
selectedDayTextColor: '#ffffff', selectedDayTextColor: '#ffffff',
todayTextColor: this.props.theme.colors.primary, todayTextColor: props.theme.colors.primary,
dayTextColor: this.props.theme.colors.text, dayTextColor: props.theme.colors.text,
textDisabledColor: this.props.theme.colors.agendaDayTextColor, textDisabledColor: props.theme.colors.agendaDayTextColor,
dotColor: this.props.theme.colors.primary, dotColor: props.theme.colors.primary,
selectedDotColor: '#ffffff', selectedDotColor: '#ffffff',
arrowColor: 'orange', arrowColor: 'orange',
monthTextColor: this.props.theme.colors.primary, monthTextColor: props.theme.colors.primary,
indicatorColor: this.props.theme.colors.primary, indicatorColor: props.theme.colors.primary,
textDayFontWeight: '300', textDayFontWeight: '300',
textMonthFontWeight: 'bold', textMonthFontWeight: 'bold',
textDayHeaderFontWeight: '300', textDayHeaderFontWeight: '300',
textDayFontSize: 16, textDayFontSize: 16,
textMonthFontSize: 16, textMonthFontSize: 16,
textDayHeaderFontSize: 16, textDayHeaderFontSize: 16,
agendaDayTextColor: this.props.theme.colors.agendaDayTextColor, agendaDayTextColor: props.theme.colors.agendaDayTextColor,
agendaDayNumColor: this.props.theme.colors.agendaDayTextColor, agendaDayNumColor: props.theme.colors.agendaDayTextColor,
agendaTodayColor: this.props.theme.colors.primary, agendaTodayColor: props.theme.colors.primary,
agendaKnobColor: this.props.theme.colors.primary, agendaKnobColor: props.theme.colors.primary,
}} }}
/>; />
);
} }
render() { render(): React.Node {
const {props} = this;
// Completely recreate the component on theme change to force theme reload // Completely recreate the component on theme change to force theme reload
if (this.props.theme.dark) if (props.theme.dark)
return ( return <View style={{flex: 1}}>{this.getAgenda()}</View>;
<View style={{flex: 1}}>
{this.getAgenda()}
</View>
);
else
return this.getAgenda(); return this.getAgenda();
} }
} }

View file

@ -1,46 +1,57 @@
/* eslint-disable flowtype/require-parameter-type */
// @flow
import * as React from 'react'; import * as React from 'react';
import {Text, withTheme} from 'react-native-paper'; import {Text, withTheme} from 'react-native-paper';
import HTML from "react-native-render-html"; import HTML from 'react-native-render-html';
import {Linking} from "react-native"; import {Linking} from 'react-native';
import type {CustomTheme} from '../../managers/ThemeManager';
type Props = { type PropsType = {
theme: Object, theme: CustomTheme,
html: string, html: string,
} };
/** /**
* Abstraction layer for Agenda component, using custom configuration * Abstraction layer for Agenda component, using custom configuration
*/ */
class CustomHTML extends React.Component<Props> { class CustomHTML extends React.Component<PropsType> {
openWebLink = (event: {...}, link: string) => {
openWebLink = (event, link) => { Linking.openURL(link);
Linking.openURL(link).catch((err) => console.error('Error opening link', err));
}; };
getBasicText = (htmlAttribs, children, convertedCSSStyles, passProps) => { getBasicText = (
htmlAttribs,
children,
convertedCSSStyles,
passProps,
): React.Node => {
// eslint-disable-next-line react/jsx-props-no-spreading
return <Text {...passProps}>{children}</Text>; return <Text {...passProps}>{children}</Text>;
}; };
getListBullet = (htmlAttribs, children, convertedCSSStyles, passProps) => { getListBullet = (): React.Node => {
return ( return <Text>- </Text>;
<Text>- </Text>
);
}; };
render() { render(): React.Node {
const {props} = this;
// Surround description with p to allow text styling if the description is not html // Surround description with p to allow text styling if the description is not html
return <HTML return (
html={"<p>" + this.props.html + "</p>"} <HTML
html={`<p>${props.html}</p>`}
renderers={{ renderers={{
p: this.getBasicText, p: this.getBasicText,
li: this.getBasicText, li: this.getBasicText,
}} }}
listsPrefixesRenderers={{ listsPrefixesRenderers={{
ul: this.getListBullet ul: this.getListBullet,
}} }}
ignoredTags={['img']} ignoredTags={['img']}
ignoredStyles={['color', 'background-color']} ignoredStyles={['color', 'background-color']}
onLinkPress={this.openWebLink}/>; onLinkPress={this.openWebLink}
/>
);
} }
} }

View file

@ -1,27 +1,39 @@
// @flow // @flow
import * as React from 'react'; import * as React from 'react';
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons"; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import {HeaderButton, HeaderButtons} from 'react-navigation-header-buttons'; import {HeaderButton, HeaderButtons} from 'react-navigation-header-buttons';
import {withTheme} from "react-native-paper"; import {withTheme} from 'react-native-paper';
import type {CustomTheme} from '../../managers/ThemeManager';
const MaterialHeaderButton = (props: Object) => const MaterialHeaderButton = (props: {
theme: CustomTheme,
color: string,
}): React.Node => {
const {color, theme} = props;
return (
// $FlowFixMe
<HeaderButton <HeaderButton
// eslint-disable-next-line react/jsx-props-no-spreading
{...props} {...props}
IconComponent={MaterialCommunityIcons} IconComponent={MaterialCommunityIcons}
iconSize={26} iconSize={26}
color={props.color != null ? props.color : props.theme.colors.text} color={color != null ? color : theme.colors.text}
/>; />
);
};
const MaterialHeaderButtons = (props: Object) => { const MaterialHeaderButtons = (props: {...}): React.Node => {
return ( return (
// $FlowFixMe
<HeaderButtons <HeaderButtons
// eslint-disable-next-line react/jsx-props-no-spreading
{...props} {...props}
HeaderButtonComponent={withTheme(MaterialHeaderButton)} HeaderButtonComponent={withTheme(MaterialHeaderButton)}
/> />
); );
}; };
export default withTheme(MaterialHeaderButtons); export default MaterialHeaderButtons;
export {Item} from 'react-navigation-header-buttons'; export {Item} from 'react-navigation-header-buttons';

View file

@ -1,390 +1,37 @@
// @flow // @flow
import * as React from 'react'; import * as React from 'react';
import {Platform, StatusBar, StyleSheet, View} from "react-native"; import {Platform, StatusBar, StyleSheet, View} from 'react-native';
import type {MaterialCommunityIconsGlyphs} from "react-native-vector-icons/MaterialCommunityIcons"; import type {MaterialCommunityIconsGlyphs} from 'react-native-vector-icons/MaterialCommunityIcons';
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons"; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import i18n from 'i18n-js'; import i18n from 'i18n-js';
import AppIntroSlider from "react-native-app-intro-slider"; import AppIntroSlider from 'react-native-app-intro-slider';
import Update from "../../constants/Update";
import ThemeManager from "../../managers/ThemeManager";
import LinearGradient from 'react-native-linear-gradient'; import LinearGradient from 'react-native-linear-gradient';
import Mascot, {MASCOT_STYLE} from "../Mascot/Mascot"; import * as Animatable from 'react-native-animatable';
import * as Animatable from "react-native-animatable"; import {Card} from 'react-native-paper';
import {Card} from "react-native-paper"; import Update from '../../constants/Update';
import ThemeManager from '../../managers/ThemeManager';
import Mascot, {MASCOT_STYLE} from '../Mascot/Mascot';
type Props = { type PropsType = {
onDone: Function, onDone: () => void,
isUpdate: boolean, isUpdate: boolean,
isAprilFools: boolean, isAprilFools: boolean,
}; };
type State = { type StateType = {
currentSlide: number, currentSlide: number,
} };
type Slide = { type IntroSlideType = {
key: string, key: string,
title: string, title: string,
text: string, text: string,
view: () => React.Node, view: () => React.Node,
mascotStyle: number, mascotStyle: number,
colors: [string, string] colors: [string, string],
}; };
/**
* Class used to create intro slides
*/
export default class CustomIntroSlider extends React.Component<Props, State> {
state = {
currentSlide: 0,
}
sliderRef: { current: null | AppIntroSlider };
introSlides: Array<Slide>;
updateSlides: Array<Slide>;
aprilFoolsSlides: Array<Slide>;
currentSlides: Array<Slide>;
/**
* Generates intro slides
*/
constructor() {
super();
this.sliderRef = React.createRef();
this.introSlides = [
{
key: '0', // Mascot
title: i18n.t('intro.slideMain.title'),
text: i18n.t('intro.slideMain.text'),
view: this.getWelcomeView,
mascotStyle: MASCOT_STYLE.NORMAL,
colors: ['#be1522', '#57080e'],
},
{
key: '1',
title: i18n.t('intro.slidePlanex.title'),
text: i18n.t('intro.slidePlanex.text'),
view: () => this.getIconView("calendar-clock"),
mascotStyle: MASCOT_STYLE.INTELLO,
colors: ['#be1522', '#57080e'],
},
{
key: '2',
title: i18n.t('intro.slideEvents.title'),
text: i18n.t('intro.slideEvents.text'),
view: () => this.getIconView("calendar-star",),
mascotStyle: MASCOT_STYLE.HAPPY,
colors: ['#be1522', '#57080e'],
},
{
key: '3',
title: i18n.t('intro.slideServices.title'),
text: i18n.t('intro.slideServices.text'),
view: () => this.getIconView("view-dashboard-variant",),
mascotStyle: MASCOT_STYLE.CUTE,
colors: ['#be1522', '#57080e'],
},
{
key: '4',
title: i18n.t('intro.slideDone.title'),
text: i18n.t('intro.slideDone.text'),
view: () => this.getEndView(),
mascotStyle: MASCOT_STYLE.COOL,
colors: ['#9c165b', '#3e042b'],
},
];
this.updateSlides = [];
for (let i = 0; i < Update.slidesNumber; i++) {
this.updateSlides.push(
{
key: i.toString(),
title: Update.getInstance().titleList[i],
text: Update.getInstance().descriptionList[i],
icon: Update.iconList[i],
colors: Update.colorsList[i],
},
);
}
this.aprilFoolsSlides = [
{
key: '1',
title: i18n.t('intro.aprilFoolsSlide.title'),
text: i18n.t('intro.aprilFoolsSlide.text'),
view: () => <View/>,
mascotStyle: MASCOT_STYLE.NORMAL,
colors: ['#e01928', '#be1522'],
},
];
}
/**
* Render item to be used for the intro introSlides
*
* @param item The item to be displayed
* @param dimensions Dimensions of the item
*/
getIntroRenderItem = ({item, dimensions}: { item: Slide, dimensions: { width: number, height: number } }) => {
const index = parseInt(item.key);
return (
<LinearGradient
style={[
styles.mainContent,
dimensions
]}
colors={item.colors}
start={{x: 0, y: 0.1}}
end={{x: 0.1, y: 1}}
>
{this.state.currentSlide === index
? <View style={{height: "100%", flex: 1}}>
<View style={{flex: 1}}>
{item.view()}
</View>
<Animatable.View
animation={"fadeIn"}>
{index !== 0 && index !== this.introSlides.length - 1
?
<Mascot
style={{
marginLeft: 30,
marginBottom: 0,
width: 100,
marginTop: -30,
}}
emotion={item.mascotStyle}
animated={true}
entryAnimation={{
animation: "slideInLeft",
duration: 500
}}
loopAnimation={{
animation: "pulse",
iterationCount: "infinite",
duration: 2000,
}}
/> : null}
<View style={{
marginLeft: 50,
width: 0,
height: 0,
borderLeftWidth: 20,
borderRightWidth: 0,
borderBottomWidth: 20,
borderStyle: 'solid',
backgroundColor: 'transparent',
borderLeftColor: 'transparent',
borderRightColor: 'transparent',
borderBottomColor: "rgba(0,0,0,0.60)",
}}/>
<Card style={{
backgroundColor: "rgba(0,0,0,0.38)",
marginHorizontal: 20,
borderColor: "rgba(0,0,0,0.60)",
borderWidth: 4,
borderRadius: 10,
}}>
<Card.Content>
<Animatable.Text
animation={"fadeIn"}
delay={100}
style={styles.title}>
{item.title}
</Animatable.Text>
<Animatable.Text
animation={"fadeIn"}
delay={200}
style={styles.text}>
{item.text}
</Animatable.Text>
</Card.Content>
</Card>
</Animatable.View>
</View> : null}
</LinearGradient>
);
}
getEndView = () => {
return (
<View style={{flex: 1}}>
<Mascot
style={{
...styles.center,
height: "80%"
}}
emotion={MASCOT_STYLE.COOL}
animated={true}
entryAnimation={{
animation: "slideInDown",
duration: 2000,
}}
loopAnimation={{
animation: "pulse",
duration: 2000,
iterationCount: "infinite"
}}
/>
</View>
);
}
getWelcomeView = () => {
return (
<View style={{flex: 1}}>
<Mascot
style={{
...styles.center,
height: "80%"
}}
emotion={MASCOT_STYLE.NORMAL}
animated={true}
entryAnimation={{
animation: "bounceIn",
duration: 2000,
}}
/>
<Animatable.Text
useNativeDriver={true}
animation={"fadeInUp"}
duration={500}
style={{
color: "#fff",
textAlign: "center",
fontSize: 25,
}}>
PABLO
</Animatable.Text>
<Animatable.View
useNativeDriver={true}
animation={"fadeInUp"}
duration={500}
delay={200}
style={{
position: "absolute",
bottom: 30,
right: "20%",
width: 50,
height: 50,
}}>
<MaterialCommunityIcons
style={{
...styles.center,
transform: [{rotateZ: "70deg"}],
}}
name={"undo"}
color={'#fff'}
size={40}/>
</Animatable.View>
</View>
)
}
getIconView(icon: MaterialCommunityIconsGlyphs) {
return (
<View style={{flex: 1}}>
<Animatable.View
style={styles.center}
animation={"fadeIn"}
>
<MaterialCommunityIcons
name={icon}
color={'#fff'}
size={200}/>
</Animatable.View>
</View>
)
}
setStatusBarColor(color: string) {
if (Platform.OS === 'android')
StatusBar.setBackgroundColor(color, true);
}
onSlideChange = (index: number, lastIndex: number) => {
this.setStatusBarColor(this.currentSlides[index].colors[0]);
this.setState({currentSlide: index});
};
onSkip = () => {
this.setStatusBarColor(this.currentSlides[this.currentSlides.length - 1].colors[0]);
if (this.sliderRef.current != null)
this.sliderRef.current.goToSlide(this.currentSlides.length - 1);
}
onDone = () => {
this.setStatusBarColor(ThemeManager.getCurrentTheme().colors.surface);
this.props.onDone();
}
renderNextButton = () => {
return (
<Animatable.View
animation={"fadeIn"}
style={{
borderRadius: 25,
padding: 5,
backgroundColor: "rgba(0,0,0,0.2)"
}}>
<MaterialCommunityIcons
name={"arrow-right"}
color={'#fff'}
size={40}/>
</Animatable.View>
)
}
renderDoneButton = () => {
return (
<Animatable.View
animation={"bounceIn"}
style={{
borderRadius: 25,
padding: 5,
backgroundColor: "rgb(190,21,34)"
}}>
<MaterialCommunityIcons
name={"check"}
color={'#fff'}
size={40}/>
</Animatable.View>
)
}
render() {
this.currentSlides = this.introSlides;
if (this.props.isUpdate)
this.currentSlides = this.updateSlides;
else if (this.props.isAprilFools)
this.currentSlides = this.aprilFoolsSlides;
this.setStatusBarColor(this.currentSlides[0].colors[0]);
return (
<AppIntroSlider
ref={this.sliderRef}
data={this.currentSlides}
extraData={this.state.currentSlide}
renderItem={this.getIntroRenderItem}
renderNextButton={this.renderNextButton}
renderDoneButton={this.renderDoneButton}
onDone={this.onDone}
onSlideChange={this.onSlideChange}
onSkip={this.onSkip}
/>
);
}
}
const styles = StyleSheet.create({ const styles = StyleSheet.create({
mainContent: { mainContent: {
paddingBottom: 100, paddingBottom: 100,
@ -409,3 +56,348 @@ const styles = StyleSheet.create({
marginLeft: 'auto', marginLeft: 'auto',
}, },
}); });
/**
* Class used to create intro slides
*/
export default class CustomIntroSlider extends React.Component<
PropsType,
StateType,
> {
sliderRef: {current: null | AppIntroSlider};
introSlides: Array<IntroSlideType>;
updateSlides: Array<IntroSlideType>;
aprilFoolsSlides: Array<IntroSlideType>;
currentSlides: Array<IntroSlideType>;
/**
* Generates intro slides
*/
constructor() {
super();
this.state = {
currentSlide: 0,
};
this.sliderRef = React.createRef();
this.introSlides = [
{
key: '0', // Mascot
title: i18n.t('intro.slideMain.title'),
text: i18n.t('intro.slideMain.text'),
view: this.getWelcomeView,
mascotStyle: MASCOT_STYLE.NORMAL,
colors: ['#be1522', '#57080e'],
},
{
key: '1',
title: i18n.t('intro.slidePlanex.title'),
text: i18n.t('intro.slidePlanex.text'),
view: (): React.Node => CustomIntroSlider.getIconView('calendar-clock'),
mascotStyle: MASCOT_STYLE.INTELLO,
colors: ['#be1522', '#57080e'],
},
{
key: '2',
title: i18n.t('intro.slideEvents.title'),
text: i18n.t('intro.slideEvents.text'),
view: (): React.Node => CustomIntroSlider.getIconView('calendar-star'),
mascotStyle: MASCOT_STYLE.HAPPY,
colors: ['#be1522', '#57080e'],
},
{
key: '3',
title: i18n.t('intro.slideServices.title'),
text: i18n.t('intro.slideServices.text'),
view: (): React.Node =>
CustomIntroSlider.getIconView('view-dashboard-variant'),
mascotStyle: MASCOT_STYLE.CUTE,
colors: ['#be1522', '#57080e'],
},
{
key: '4',
title: i18n.t('intro.slideDone.title'),
text: i18n.t('intro.slideDone.text'),
view: (): React.Node => this.getEndView(),
mascotStyle: MASCOT_STYLE.COOL,
colors: ['#9c165b', '#3e042b'],
},
];
// $FlowFixMe
this.updateSlides = [];
for (let i = 0; i < Update.slidesNumber; i += 1) {
this.updateSlides.push({
key: i.toString(),
title: Update.getInstance().titleList[i],
text: Update.getInstance().descriptionList[i],
icon: Update.iconList[i],
colors: Update.colorsList[i],
});
}
this.aprilFoolsSlides = [
{
key: '1',
title: i18n.t('intro.aprilFoolsSlide.title'),
text: i18n.t('intro.aprilFoolsSlide.text'),
view: (): React.Node => <View />,
mascotStyle: MASCOT_STYLE.NORMAL,
colors: ['#e01928', '#be1522'],
},
];
}
/**
* Render item to be used for the intro introSlides
*
* @param item The item to be displayed
* @param dimensions Dimensions of the item
*/
getIntroRenderItem = ({
item,
dimensions,
}: {
item: IntroSlideType,
dimensions: {width: number, height: number},
}): React.Node => {
const {state} = this;
const index = parseInt(item.key, 10);
return (
<LinearGradient
style={[styles.mainContent, dimensions]}
colors={item.colors}
start={{x: 0, y: 0.1}}
end={{x: 0.1, y: 1}}>
{state.currentSlide === index ? (
<View style={{height: '100%', flex: 1}}>
<View style={{flex: 1}}>{item.view()}</View>
<Animatable.View animation="fadeIn">
{index !== 0 && index !== this.introSlides.length - 1 ? (
<Mascot
style={{
marginLeft: 30,
marginBottom: 0,
width: 100,
marginTop: -30,
}}
emotion={item.mascotStyle}
animated
entryAnimation={{
animation: 'slideInLeft',
duration: 500,
}}
loopAnimation={{
animation: 'pulse',
iterationCount: 'infinite',
duration: 2000,
}}
/>
) : null}
<View
style={{
marginLeft: 50,
width: 0,
height: 0,
borderLeftWidth: 20,
borderRightWidth: 0,
borderBottomWidth: 20,
borderStyle: 'solid',
backgroundColor: 'transparent',
borderLeftColor: 'transparent',
borderRightColor: 'transparent',
borderBottomColor: 'rgba(0,0,0,0.60)',
}}
/>
<Card
style={{
backgroundColor: 'rgba(0,0,0,0.38)',
marginHorizontal: 20,
borderColor: 'rgba(0,0,0,0.60)',
borderWidth: 4,
borderRadius: 10,
}}>
<Card.Content>
<Animatable.Text
animation="fadeIn"
delay={100}
style={styles.title}>
{item.title}
</Animatable.Text>
<Animatable.Text
animation="fadeIn"
delay={200}
style={styles.text}>
{item.text}
</Animatable.Text>
</Card.Content>
</Card>
</Animatable.View>
</View>
) : null}
</LinearGradient>
);
};
getEndView = (): React.Node => {
return (
<View style={{flex: 1}}>
<Mascot
style={{
...styles.center,
height: '80%',
}}
emotion={MASCOT_STYLE.COOL}
animated
entryAnimation={{
animation: 'slideInDown',
duration: 2000,
}}
loopAnimation={{
animation: 'pulse',
duration: 2000,
iterationCount: 'infinite',
}}
/>
</View>
);
};
getWelcomeView = (): React.Node => {
return (
<View style={{flex: 1}}>
<Mascot
style={{
...styles.center,
height: '80%',
}}
emotion={MASCOT_STYLE.NORMAL}
animated
entryAnimation={{
animation: 'bounceIn',
duration: 2000,
}}
/>
<Animatable.Text
useNativeDriver
animation="fadeInUp"
duration={500}
style={{
color: '#fff',
textAlign: 'center',
fontSize: 25,
}}>
PABLO
</Animatable.Text>
<Animatable.View
useNativeDriver
animation="fadeInUp"
duration={500}
delay={200}
style={{
position: 'absolute',
bottom: 30,
right: '20%',
width: 50,
height: 50,
}}>
<MaterialCommunityIcons
style={{
...styles.center,
transform: [{rotateZ: '70deg'}],
}}
name="undo"
color="#fff"
size={40}
/>
</Animatable.View>
</View>
);
};
static getIconView(icon: MaterialCommunityIconsGlyphs): React.Node {
return (
<View style={{flex: 1}}>
<Animatable.View style={styles.center} animation="fadeIn">
<MaterialCommunityIcons name={icon} color="#fff" size={200} />
</Animatable.View>
</View>
);
}
static setStatusBarColor(color: string) {
if (Platform.OS === 'android') StatusBar.setBackgroundColor(color, true);
}
onSlideChange = (index: number) => {
CustomIntroSlider.setStatusBarColor(this.currentSlides[index].colors[0]);
this.setState({currentSlide: index});
};
onSkip = () => {
CustomIntroSlider.setStatusBarColor(
this.currentSlides[this.currentSlides.length - 1].colors[0],
);
if (this.sliderRef.current != null)
this.sliderRef.current.goToSlide(this.currentSlides.length - 1);
};
onDone = () => {
const {props} = this;
CustomIntroSlider.setStatusBarColor(
ThemeManager.getCurrentTheme().colors.surface,
);
props.onDone();
};
getRenderNextButton = (): React.Node => {
return (
<Animatable.View
animation="fadeIn"
style={{
borderRadius: 25,
padding: 5,
backgroundColor: 'rgba(0,0,0,0.2)',
}}>
<MaterialCommunityIcons name="arrow-right" color="#fff" size={40} />
</Animatable.View>
);
};
getRenderDoneButton = (): React.Node => {
return (
<Animatable.View
animation="bounceIn"
style={{
borderRadius: 25,
padding: 5,
backgroundColor: 'rgb(190,21,34)',
}}>
<MaterialCommunityIcons name="check" color="#fff" size={40} />
</Animatable.View>
);
};
render(): React.Node {
const {props, state} = this;
this.currentSlides = this.introSlides;
if (props.isUpdate) this.currentSlides = this.updateSlides;
else if (props.isAprilFools) this.currentSlides = this.aprilFoolsSlides;
CustomIntroSlider.setStatusBarColor(this.currentSlides[0].colors[0]);
return (
<AppIntroSlider
ref={this.sliderRef}
data={this.currentSlides}
extraData={state.currentSlide}
renderItem={this.getIntroRenderItem}
renderNextButton={this.getRenderNextButton}
renderDoneButton={this.getRenderDoneButton}
onDone={this.onDone}
onSlideChange={this.onSlideChange}
onSkip={this.onSkip}
/>
);
}
}

View file

@ -2,9 +2,10 @@
import * as React from 'react'; import * as React from 'react';
import {withTheme} from 'react-native-paper'; import {withTheme} from 'react-native-paper';
import {Modalize} from "react-native-modalize"; import {Modalize} from 'react-native-modalize';
import {View} from "react-native-animatable"; import {View} from 'react-native-animatable';
import CustomTabBar from "../Tabbar/CustomTabBar"; import CustomTabBar from '../Tabbar/CustomTabBar';
import type {CustomTheme} from '../../managers/ThemeManager';
/** /**
* Abstraction layer for Modalize component, using custom configuration * Abstraction layer for Modalize component, using custom configuration
@ -12,25 +13,29 @@ import CustomTabBar from "../Tabbar/CustomTabBar";
* @param props Props to pass to the element. Must specify an onRef prop to get an Modalize ref. * @param props Props to pass to the element. Must specify an onRef prop to get an Modalize ref.
* @return {*} * @return {*}
*/ */
function CustomModal(props) { function CustomModal(props: {
const {colors} = props.theme; theme: CustomTheme,
onRef: (re: Modalize) => void,
children?: React.Node,
}): React.Node {
const {theme, onRef, children} = props;
return ( return (
<Modalize <Modalize
ref={props.onRef} ref={onRef}
adjustToContentHeight adjustToContentHeight
handlePosition={'inside'} handlePosition="inside"
modalStyle={{backgroundColor: colors.card}} modalStyle={{backgroundColor: theme.colors.card}}
handleStyle={{backgroundColor: colors.primary}} handleStyle={{backgroundColor: theme.colors.primary}}>
> <View
<View style={{ style={{
paddingBottom: CustomTabBar.TAB_BAR_HEIGHT paddingBottom: CustomTabBar.TAB_BAR_HEIGHT,
}}> }}>
{props.children} {children}
</View> </View>
</Modalize> </Modalize>
); );
} }
export default withTheme(CustomModal); CustomModal.defaultProps = {children: null};
export default withTheme(CustomModal);

View file

@ -2,19 +2,19 @@
import * as React from 'react'; import * as React from 'react';
import {Text, withTheme} from 'react-native-paper'; import {Text, withTheme} from 'react-native-paper';
import {View} from "react-native-animatable"; import {View} from 'react-native-animatable';
import type {CustomTheme} from "../../managers/ThemeManager"; import Slider, {SliderProps} from '@react-native-community/slider';
import Slider, {SliderProps} from "@react-native-community/slider"; import type {CustomTheme} from '../../managers/ThemeManager';
type Props = { type PropsType = {
theme: CustomTheme, theme: CustomTheme,
valueSuffix: string, valueSuffix?: string,
...SliderProps ...SliderProps,
} };
type State = { type StateType = {
currentValue: number, currentValue: number,
} };
/** /**
* Abstraction layer for Modalize component, using custom configuration * Abstraction layer for Modalize component, using custom configuration
@ -22,37 +22,44 @@ type State = {
* @param props Props to pass to the element. Must specify an onRef prop to get an Modalize ref. * @param props Props to pass to the element. Must specify an onRef prop to get an Modalize ref.
* @return {*} * @return {*}
*/ */
class CustomSlider extends React.Component<Props, State> { class CustomSlider extends React.Component<PropsType, StateType> {
static defaultProps = { static defaultProps = {
valueSuffix: "", valueSuffix: '',
} };
state = { constructor(props: PropsType) {
currentValue: this.props.value, super(props);
this.state = {
currentValue: props.value,
};
} }
onValueChange = (value: number) => { onValueChange = (value: number) => {
const {props} = this;
this.setState({currentValue: value}); this.setState({currentValue: value});
if (this.props.onValueChange != null) if (props.onValueChange != null) props.onValueChange(value);
this.props.onValueChange(value); };
}
render() { render(): React.Node {
const {props, state} = this;
return ( return (
<View style={{flex: 1, flexDirection: 'row'}}> <View style={{flex: 1, flexDirection: 'row'}}>
<Text style={{marginHorizontal: 10, marginTop: 'auto', marginBottom: 'auto'}}> <Text
{this.state.currentValue}min style={{
marginHorizontal: 10,
marginTop: 'auto',
marginBottom: 'auto',
}}>
{state.currentValue}min
</Text> </Text>
<Slider <Slider
{...this.props} // eslint-disable-next-line react/jsx-props-no-spreading
{...props}
onValueChange={this.onValueChange} onValueChange={this.onValueChange}
/> />
</View> </View>
); );
} }
} }
export default withTheme(CustomSlider); export default withTheme(CustomSlider);