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,60 +1,63 @@
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 {
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,
}}
/>
);
}
getAgenda() { render(): React.Node {
return <Agenda const {props} = this;
{...this.props} // Completely recreate the component on theme change to force theme reload
ref={this.props.onRef} if (props.theme.dark)
theme={{ return <View style={{flex: 1}}>{this.getAgenda()}</View>;
backgroundColor: this.props.theme.colors.agendaBackgroundColor, return this.getAgenda();
calendarBackground: this.props.theme.colors.background, }
textSectionTitleColor: this.props.theme.colors.agendaDayTextColor,
selectedDayBackgroundColor: this.props.theme.colors.primary,
selectedDayTextColor: '#ffffff',
todayTextColor: this.props.theme.colors.primary,
dayTextColor: this.props.theme.colors.text,
textDisabledColor: this.props.theme.colors.agendaDayTextColor,
dotColor: this.props.theme.colors.primary,
selectedDotColor: '#ffffff',
arrowColor: 'orange',
monthTextColor: this.props.theme.colors.primary,
indicatorColor: this.props.theme.colors.primary,
textDayFontWeight: '300',
textMonthFontWeight: 'bold',
textDayHeaderFontWeight: '300',
textDayFontSize: 16,
textMonthFontSize: 16,
textDayHeaderFontSize: 16,
agendaDayTextColor: this.props.theme.colors.agendaDayTextColor,
agendaDayNumColor: this.props.theme.colors.agendaDayTextColor,
agendaTodayColor: this.props.theme.colors.primary,
agendaKnobColor: this.props.theme.colors.primary,
}}
/>;
}
render() {
// Completely recreate the component on theme change to force theme reload
if (this.props.theme.dark)
return (
<View style={{flex: 1}}>
{this.getAgenda()}
</View>
);
else
return this.getAgenda();
}
} }
export default withTheme(CustomAgenda); export default withTheme(CustomAgenda);

View file

@ -1,47 +1,58 @@
/* 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) => {
Linking.openURL(link);
};
openWebLink = (event, link) => { getBasicText = (
Linking.openURL(link).catch((err) => console.error('Error opening link', err)); htmlAttribs,
}; children,
convertedCSSStyles,
passProps,
): React.Node => {
// eslint-disable-next-line react/jsx-props-no-spreading
return <Text {...passProps}>{children}</Text>;
};
getBasicText = (htmlAttribs, children, convertedCSSStyles, passProps) => { getListBullet = (): React.Node => {
return <Text {...passProps}>{children}</Text>; return <Text>- </Text>;
}; };
getListBullet = (htmlAttribs, children, convertedCSSStyles, passProps) => { render(): React.Node {
return ( const {props} = this;
<Text>- </Text> // Surround description with p to allow text styling if the description is not html
); return (
}; <HTML
html={`<p>${props.html}</p>`}
render() { renderers={{
// Surround description with p to allow text styling if the description is not html p: this.getBasicText,
return <HTML li: this.getBasicText,
html={"<p>" + this.props.html + "</p>"} }}
renderers={{ listsPrefixesRenderers={{
p: this.getBasicText, ul: this.getListBullet,
li: this.getBasicText, }}
}} ignoredTags={['img']}
listsPrefixesRenderers={{ ignoredStyles={['color', 'background-color']}
ul: this.getListBullet onLinkPress={this.openWebLink}
}} />
ignoredTags={['img']} );
ignoredStyles={['color', 'background-color']} }
onLinkPress={this.openWebLink}/>;
}
} }
export default withTheme(CustomHTML); export default withTheme(CustomHTML);

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
{...props} // eslint-disable-next-line react/jsx-props-no-spreading
IconComponent={MaterialCommunityIcons} {...props}
iconSize={26} IconComponent={MaterialCommunityIcons}
color={props.color != null ? props.color : props.theme.colors.text} iconSize={26}
/>; color={color != null ? color : theme.colors.text}
/>
const MaterialHeaderButtons = (props: Object) => { );
return (
<HeaderButtons
{...props}
HeaderButtonComponent={withTheme(MaterialHeaderButton)}
/>
);
}; };
export default withTheme(MaterialHeaderButtons); const MaterialHeaderButtons = (props: {...}): React.Node => {
return (
// $FlowFixMe
<HeaderButtons
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
HeaderButtonComponent={withTheme(MaterialHeaderButton)}
/>
);
};
export default MaterialHeaderButtons;
export {Item} from 'react-navigation-header-buttons'; export {Item} from 'react-navigation-header-buttons';

View file

@ -1,411 +1,403 @@
// @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 = {
key: string,
title: string,
text: string,
view: () => React.Node,
mascotStyle: number,
colors: [string, string]
}; };
type IntroSlideType = {
key: string,
title: string,
text: string,
view: () => React.Node,
mascotStyle: number,
colors: [string, string],
};
const styles = StyleSheet.create({
mainContent: {
paddingBottom: 100,
},
text: {
color: 'rgba(255, 255, 255, 0.8)',
backgroundColor: 'transparent',
textAlign: 'center',
paddingHorizontal: 16,
},
title: {
fontSize: 22,
color: 'white',
backgroundColor: 'transparent',
textAlign: 'center',
marginBottom: 16,
},
center: {
marginTop: 'auto',
marginBottom: 'auto',
marginRight: 'auto',
marginLeft: 'auto',
},
});
/** /**
* Class used to create intro slides * Class used to create intro slides
*/ */
export default class CustomIntroSlider extends React.Component<Props, State> { export default class CustomIntroSlider extends React.Component<
PropsType,
StateType,
> {
sliderRef: {current: null | AppIntroSlider};
state = { introSlides: Array<IntroSlideType>;
currentSlide: 0,
}
sliderRef: { current: null | AppIntroSlider }; updateSlides: Array<IntroSlideType>;
introSlides: Array<Slide>; aprilFoolsSlides: Array<IntroSlideType>;
updateSlides: Array<Slide>;
aprilFoolsSlides: Array<Slide>;
currentSlides: Array<Slide>;
/** currentSlides: Array<IntroSlideType>;
* 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 = [ /**
{ * Generates intro slides
key: '1', */
title: i18n.t('intro.aprilFoolsSlide.title'), constructor() {
text: i18n.t('intro.aprilFoolsSlide.text'), super();
view: () => <View/>, this.state = {
mascotStyle: MASCOT_STYLE.NORMAL, currentSlide: 0,
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});
}; };
this.sliderRef = React.createRef();
onSkip = () => { this.introSlides = [
this.setStatusBarColor(this.currentSlides[this.currentSlides.length - 1].colors[0]); {
if (this.sliderRef.current != null) key: '0', // Mascot
this.sliderRef.current.goToSlide(this.currentSlides.length - 1); 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],
});
} }
onDone = () => { this.aprilFoolsSlides = [
this.setStatusBarColor(ThemeManager.getCurrentTheme().colors.surface); {
this.props.onDone(); key: '1',
} title: i18n.t('intro.aprilFoolsSlide.title'),
text: i18n.t('intro.aprilFoolsSlide.text'),
renderNextButton = () => { view: (): React.Node => <View />,
return ( mascotStyle: MASCOT_STYLE.NORMAL,
<Animatable.View colors: ['#e01928', '#be1522'],
animation={"fadeIn"} },
];
}
/**
* 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={{ style={{
borderRadius: 25, marginLeft: 50,
padding: 5, width: 0,
backgroundColor: "rgba(0,0,0,0.2)" height: 0,
}}> borderLeftWidth: 20,
<MaterialCommunityIcons borderRightWidth: 0,
name={"arrow-right"} borderBottomWidth: 20,
color={'#fff'} borderStyle: 'solid',
size={40}/> backgroundColor: 'transparent',
</Animatable.View> borderLeftColor: 'transparent',
) borderRightColor: 'transparent',
} borderBottomColor: 'rgba(0,0,0,0.60)',
}}
renderDoneButton = () => { />
return ( <Card
<Animatable.View
animation={"bounceIn"}
style={{ style={{
borderRadius: 25, backgroundColor: 'rgba(0,0,0,0.38)',
padding: 5, marginHorizontal: 20,
backgroundColor: "rgb(190,21,34)" borderColor: 'rgba(0,0,0,0.60)',
borderWidth: 4,
borderRadius: 10,
}}> }}>
<MaterialCommunityIcons <Card.Content>
name={"check"} <Animatable.Text
color={'#fff'} animation="fadeIn"
size={40}/> 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> </Animatable.View>
) </View>
} ) : null}
</LinearGradient>
);
};
render() { getEndView = (): React.Node => {
this.currentSlides = this.introSlides; return (
if (this.props.isUpdate) <View style={{flex: 1}}>
this.currentSlides = this.updateSlides; <Mascot
else if (this.props.isAprilFools) style={{
this.currentSlides = this.aprilFoolsSlides; ...styles.center,
this.setStatusBarColor(this.currentSlides[0].colors[0]); height: '80%',
return ( }}
<AppIntroSlider emotion={MASCOT_STYLE.COOL}
ref={this.sliderRef} animated
data={this.currentSlides} entryAnimation={{
extraData={this.state.currentSlide} animation: 'slideInDown',
duration: 2000,
}}
loopAnimation={{
animation: 'pulse',
duration: 2000,
iterationCount: 'infinite',
}}
/>
</View>
);
};
renderItem={this.getIntroRenderItem} getWelcomeView = (): React.Node => {
renderNextButton={this.renderNextButton} return (
renderDoneButton={this.renderDoneButton} <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>
);
};
onDone={this.onDone} static getIconView(icon: MaterialCommunityIconsGlyphs): React.Node {
onSlideChange={this.onSlideChange} return (
onSkip={this.onSkip} <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}
/>
);
}
} }
const styles = StyleSheet.create({
mainContent: {
paddingBottom: 100,
},
text: {
color: 'rgba(255, 255, 255, 0.8)',
backgroundColor: 'transparent',
textAlign: 'center',
paddingHorizontal: 16,
},
title: {
fontSize: 22,
color: 'white',
backgroundColor: 'transparent',
textAlign: 'center',
marginBottom: 16,
},
center: {
marginTop: 'auto',
marginBottom: 'auto',
marginRight: 'auto',
marginLeft: 'auto',
},
});

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,
return ( onRef: (re: Modalize) => void,
<Modalize children?: React.Node,
ref={props.onRef} }): React.Node {
adjustToContentHeight const {theme, onRef, children} = props;
handlePosition={'inside'} return (
modalStyle={{backgroundColor: colors.card}} <Modalize
handleStyle={{backgroundColor: colors.primary}} ref={onRef}
> adjustToContentHeight
<View style={{ handlePosition="inside"
paddingBottom: CustomTabBar.TAB_BAR_HEIGHT modalStyle={{backgroundColor: theme.colors.card}}
}}> handleStyle={{backgroundColor: theme.colors.primary}}>
{props.children} <View
</View> style={{
paddingBottom: CustomTabBar.TAB_BAR_HEIGHT,
</Modalize> }}>
); {children}
</View>
</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 = {
valueSuffix: '',
};
static defaultProps = { constructor(props: PropsType) {
valueSuffix: "", super(props);
} this.state = {
currentValue: props.value,
};
}
state = { onValueChange = (value: number) => {
currentValue: this.props.value, const {props} = this;
} this.setState({currentValue: value});
if (props.onValueChange != null) props.onValueChange(value);
onValueChange = (value: number) => { };
this.setState({currentValue: value});
if (this.props.onValueChange != null)
this.props.onValueChange(value);
}
render() {
return (
<View style={{flex: 1, flexDirection: 'row'}}>
<Text style={{marginHorizontal: 10, marginTop: 'auto', marginBottom: 'auto'}}>
{this.state.currentValue}min
</Text>
<Slider
{...this.props}
onValueChange={this.onValueChange}
/>
</View>
);
}
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); export default withTheme(CustomSlider);