Update about screens to use TypeScript

This commit is contained in:
Arnaud Vergnet 2020-09-22 18:58:56 +02:00
parent 172b7e8187
commit f7e767748a
3 changed files with 100 additions and 88 deletions

View file

@ -17,8 +17,6 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/ */
// @flow
import * as React from 'react'; import * as React from 'react';
import {List} from 'react-native-paper'; import {List} from 'react-native-paper';
import {View} from 'react-native-animatable'; import {View} from 'react-native-animatable';
@ -26,8 +24,8 @@ import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatLis
import packageJson from '../../../package.json'; import packageJson from '../../../package.json';
type ListItemType = { type ListItemType = {
name: string, name: string;
version: string, version: string;
}; };
/** /**
@ -37,9 +35,9 @@ type ListItemType = {
* @return {Array<ListItemType>} * @return {Array<ListItemType>}
*/ */
function generateListFromObject(object: { function generateListFromObject(object: {
[key: string]: string, [key: string]: string;
}): Array<ListItemType> { }): Array<ListItemType> {
const list = []; const list: Array<ListItemType> = [];
const keys = Object.keys(object); const keys = Object.keys(object);
keys.forEach((key: string) => { keys.forEach((key: string) => {
list.push({name: key, version: object[key]}); list.push({name: key, version: object[key]});
@ -56,13 +54,13 @@ export default class AboutDependenciesScreen extends React.Component<null> {
data: Array<ListItemType>; data: Array<ListItemType>;
constructor() { constructor() {
super(); super(null);
this.data = generateListFromObject(packageJson.dependencies); this.data = generateListFromObject(packageJson.dependencies);
} }
keyExtractor = (item: ListItemType): string => item.name; keyExtractor = (item: ListItemType): string => item.name;
getRenderItem = ({item}: {item: ListItemType}): React.Node => ( getRenderItem = ({item}: {item: ListItemType}) => (
<List.Item <List.Item
title={item.name} title={item.name}
description={item.version.replace('^', '').replace('~', '')} description={item.version.replace('^', '').replace('~', '')}
@ -71,15 +69,15 @@ export default class AboutDependenciesScreen extends React.Component<null> {
); );
getItemLayout = ( getItemLayout = (
data: ListItemType, data: Array<ListItemType> | null | undefined,
index: number, index: number,
): {length: number, offset: number, index: number} => ({ ): {length: number; offset: number; index: number} => ({
length: LIST_ITEM_HEIGHT, length: LIST_ITEM_HEIGHT,
offset: LIST_ITEM_HEIGHT * index, offset: LIST_ITEM_HEIGHT * index,
index, index,
}); });
render(): React.Node { render() {
return ( return (
<View> <View>
<CollapsibleFlatList <CollapsibleFlatList

View file

@ -17,37 +17,32 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/ */
// @flow
import * as React from 'react'; import * as React from 'react';
import {FlatList, Linking, Platform, Image, View} from 'react-native'; import {FlatList, Linking, Platform, Image, View} from 'react-native';
import i18n from 'i18n-js'; import i18n from 'i18n-js';
import {Avatar, Card, List, withTheme} from 'react-native-paper'; import {Avatar, Card, List} from 'react-native-paper';
import {StackNavigationProp} from '@react-navigation/stack'; import {StackNavigationProp} from '@react-navigation/stack';
import packageJson from '../../../package.json'; import packageJson from '../../../package.json';
import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList'; import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList';
import APP_LOGO from '../../../assets/android.icon.round.png';
import type {
CardTitleIconPropsType,
ListIconPropsType,
} from '../../constants/PaperStyles';
import OptionsDialog from '../../components/Dialogs/OptionsDialog'; import OptionsDialog from '../../components/Dialogs/OptionsDialog';
import type {OptionsDialogButtonType} from '../../components/Dialogs/OptionsDialog'; import type {OptionsDialogButtonType} from '../../components/Dialogs/OptionsDialog';
const APP_LOGO = require('../../../assets/android.icon.round.png');
type ListItemType = { type ListItemType = {
onPressCallback: () => void, onPressCallback: () => void;
icon: string, icon: string;
text: string, text: string;
showChevron: boolean, showChevron: boolean;
}; };
type MemberItemType = { type MemberItemType = {
name: string, name: string;
message: string, message: string;
icon: string, icon: string;
trollLink?: string, trollLink?: string;
linkedin?: string, linkedin?: string;
mail?: string, mail?: string;
}; };
const links = { const links = {
@ -64,14 +59,14 @@ const links = {
}; };
type PropsType = { type PropsType = {
navigation: StackNavigationProp, navigation: StackNavigationProp<any>;
}; };
type StateType = { type StateType = {
dialogVisible: boolean, dialogVisible: boolean;
dialogTitle: string, dialogTitle: string;
dialogMessage: string, dialogMessage: string;
dialogButtons: Array<OptionsDialogButtonType>, dialogButtons: Array<OptionsDialogButtonType>;
}; };
/** /**
@ -86,7 +81,6 @@ function openWebLink(link: string) {
* Class defining an about screen. This screen shows the user information about the app and it's author. * Class defining an about screen. This screen shows the user information about the app and it's author.
*/ */
class AboutScreen extends React.Component<PropsType, StateType> { class AboutScreen extends React.Component<PropsType, StateType> {
/** /**
* Object containing data relative to major contributors * Object containing data relative to major contributors
*/ */
@ -109,7 +103,8 @@ class AboutScreen extends React.Component<PropsType, StateType> {
message: i18n.t('screens.about.user.yohan'), message: i18n.t('screens.about.user.yohan'),
icon: 'xml', icon: 'xml',
linkedin: 'https://www.linkedin.com/in/yohan-simard', linkedin: 'https://www.linkedin.com/in/yohan-simard',
mail: 'mailto:ysimard@etud.insa-toulouse.fr?' + mail:
'mailto:ysimard@etud.insa-toulouse.fr?' +
'subject=' + 'subject=' +
'Application Amicale INSA Toulouse' + 'Application Amicale INSA Toulouse' +
'&body=' + '&body=' +
@ -333,7 +328,7 @@ class AboutScreen extends React.Component<PropsType, StateType> {
* @param user The member to show information for * @param user The member to show information for
*/ */
onContributorListItemPress(user: MemberItemType) { onContributorListItemPress(user: MemberItemType) {
const dialogBtn = [ const dialogBtn: Array<OptionsDialogButtonType> = [
{ {
title: 'OK', title: 'OK',
onPress: this.onDialogDismiss, onPress: this.onDialogDismiss,
@ -379,15 +374,14 @@ class AboutScreen extends React.Component<PropsType, StateType> {
* *
* @return {*} * @return {*}
*/ */
getAppCard(): React.Node { getAppCard() {
return ( return (
<Card style={{marginBottom: 10}}> <Card style={{marginBottom: 10}}>
<Card.Title <Card.Title
title="Campus" title="Campus"
subtitle={packageJson.version} subtitle={packageJson.version}
left={(iconProps: CardTitleIconPropsType): React.Node => ( left={(iconProps) => (
<Image <Image
size={iconProps.size}
source={APP_LOGO} source={APP_LOGO}
style={{width: iconProps.size, height: iconProps.size}} style={{width: iconProps.size, height: iconProps.size}}
/> />
@ -409,12 +403,12 @@ class AboutScreen extends React.Component<PropsType, StateType> {
* *
* @return {*} * @return {*}
*/ */
getTeamCard(): React.Node { getTeamCard() {
return ( return (
<Card style={{marginBottom: 10}}> <Card style={{marginBottom: 10}}>
<Card.Title <Card.Title
title={i18n.t('screens.about.team')} title={i18n.t('screens.about.team')}
left={(iconProps: CardTitleIconPropsType): React.Node => ( left={(iconProps) => (
<Avatar.Icon size={iconProps.size} icon="account-multiple" /> <Avatar.Icon size={iconProps.size} icon="account-multiple" />
)} )}
/> />
@ -434,12 +428,12 @@ class AboutScreen extends React.Component<PropsType, StateType> {
* *
* @return {*} * @return {*}
*/ */
getThanksCard(): React.Node { getThanksCard() {
return ( return (
<Card style={{marginBottom: 10}}> <Card style={{marginBottom: 10}}>
<Card.Title <Card.Title
title={i18n.t('screens.about.thanks')} title={i18n.t('screens.about.thanks')}
left={(iconProps: CardTitleIconPropsType): React.Node => ( left={(iconProps) => (
<Avatar.Icon size={iconProps.size} icon="hand-heart" /> <Avatar.Icon size={iconProps.size} icon="hand-heart" />
)} )}
/> />
@ -459,12 +453,12 @@ class AboutScreen extends React.Component<PropsType, StateType> {
* *
* @return {*} * @return {*}
*/ */
getTechnoCard(): React.Node { getTechnoCard() {
return ( return (
<Card style={{marginBottom: 10}}> <Card style={{marginBottom: 10}}>
<Card.Title <Card.Title
title={i18n.t('screens.about.technologies')} title={i18n.t('screens.about.technologies')}
left={(iconProps: CardTitleIconPropsType): React.Node => ( left={(iconProps) => (
<Avatar.Icon size={iconProps.size} icon="wrench" /> <Avatar.Icon size={iconProps.size} icon="wrench" />
)} )}
/> />
@ -485,7 +479,13 @@ class AboutScreen extends React.Component<PropsType, StateType> {
* @param props * @param props
* @return {*} * @return {*}
*/ */
static getChevronIcon(props: ListIconPropsType): React.Node { static getChevronIcon(props: {
color: string;
style?: {
marginRight: number;
marginVertical?: number;
};
}) {
return ( return (
<List.Icon color={props.color} style={props.style} icon="chevron-right" /> <List.Icon color={props.color} style={props.style} icon="chevron-right" />
); );
@ -498,7 +498,16 @@ class AboutScreen extends React.Component<PropsType, StateType> {
* @param props * @param props
* @return {*} * @return {*}
*/ */
static getItemIcon(item: ListItemType, props: ListIconPropsType): React.Node { static getItemIcon(
item: ListItemType,
props: {
color: string;
style?: {
marginRight: number;
marginVertical?: number;
};
},
) {
return ( return (
<List.Icon color={props.color} style={props.style} icon={item.icon} /> <List.Icon color={props.color} style={props.style} icon={item.icon} />
); );
@ -509,9 +518,14 @@ class AboutScreen extends React.Component<PropsType, StateType> {
* *
* @returns {*} * @returns {*}
*/ */
getCardItem = ({item}: {item: ListItemType}): React.Node => { getCardItem = ({item}: {item: ListItemType}) => {
const getItemIcon = (props: ListIconPropsType): React.Node => const getItemIcon = (props: {
AboutScreen.getItemIcon(item, props); color: string;
style?: {
marginRight: number;
marginVertical?: number;
};
}) => AboutScreen.getItemIcon(item, props);
if (item.showChevron) { if (item.showChevron) {
return ( return (
<List.Item <List.Item
@ -537,7 +551,7 @@ class AboutScreen extends React.Component<PropsType, StateType> {
* @param item The item to show * @param item The item to show
* @return {*} * @return {*}
*/ */
getMainCard = ({item}: {item: {id: string}}): React.Node => { getMainCard = ({item}: {item: {id: string}}) => {
switch (item.id) { switch (item.id) {
case 'app': case 'app':
return this.getAppCard(); return this.getAppCard();
@ -564,7 +578,7 @@ class AboutScreen extends React.Component<PropsType, StateType> {
*/ */
keyExtractor = (item: ListItemType): string => item.icon; keyExtractor = (item: ListItemType): string => item.icon;
render(): React.Node { render() {
const {state} = this; const {state} = this;
return ( return (
<View <View
@ -588,4 +602,4 @@ class AboutScreen extends React.Component<PropsType, StateType> {
} }
} }
export default withTheme(AboutScreen); export default AboutScreen;

View file

@ -17,8 +17,6 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/ */
// @flow
import * as React from 'react'; import * as React from 'react';
import {View} from 'react-native'; import {View} from 'react-native';
import { import {
@ -32,22 +30,21 @@ import {
import {Modalize} from 'react-native-modalize'; import {Modalize} from 'react-native-modalize';
import CustomModal from '../../components/Overrides/CustomModal'; import CustomModal from '../../components/Overrides/CustomModal';
import AsyncStorageManager from '../../managers/AsyncStorageManager'; import AsyncStorageManager from '../../managers/AsyncStorageManager';
import type {CustomThemeType} from '../../managers/ThemeManager';
import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList'; import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList';
type PreferenceItemType = { type PreferenceItemType = {
key: string, key: string;
default: string, default: string;
current: string, current: string;
}; };
type PropsType = { type PropsType = {
theme: CustomThemeType, theme: ReactNativePaper.Theme;
}; };
type StateType = { type StateType = {
modalCurrentDisplayItem: PreferenceItemType, modalCurrentDisplayItem: PreferenceItemType | null;
currentPreferences: Array<PreferenceItemType>, currentPreferences: Array<PreferenceItemType>;
}; };
/** /**
@ -55,7 +52,7 @@ type StateType = {
* This screen allows the user to get and modify information on the app/device. * This screen allows the user to get and modify information on the app/device.
*/ */
class DebugScreen extends React.Component<PropsType, StateType> { class DebugScreen extends React.Component<PropsType, StateType> {
modalRef: Modalize; modalRef: Modalize | null;
modalInputValue: string; modalInputValue: string;
@ -66,16 +63,16 @@ class DebugScreen extends React.Component<PropsType, StateType> {
*/ */
constructor(props: PropsType) { constructor(props: PropsType) {
super(props); super(props);
this.modalRef = null;
this.modalInputValue = ''; this.modalInputValue = '';
const currentPreferences: Array<PreferenceItemType> = []; const currentPreferences: Array<PreferenceItemType> = [];
// eslint-disable-next-line flowtype/no-weak-types
Object.values(AsyncStorageManager.PREFERENCES).forEach((object: any) => { Object.values(AsyncStorageManager.PREFERENCES).forEach((object: any) => {
const newObject: PreferenceItemType = {...object}; const newObject: PreferenceItemType = {...object};
newObject.current = AsyncStorageManager.getString(newObject.key); newObject.current = AsyncStorageManager.getString(newObject.key);
currentPreferences.push(newObject); currentPreferences.push(newObject);
}); });
this.state = { this.state = {
modalCurrentDisplayItem: {}, modalCurrentDisplayItem: null,
currentPreferences, currentPreferences,
}; };
} }
@ -85,21 +82,27 @@ class DebugScreen extends React.Component<PropsType, StateType> {
* *
* @return {*} * @return {*}
*/ */
getModalContent(): React.Node { getModalContent() {
const {props, state} = this; const {props, state} = this;
let key = '';
let defaultValue = '';
let current = '';
if (state.modalCurrentDisplayItem) {
key = state.modalCurrentDisplayItem.key;
defaultValue = state.modalCurrentDisplayItem.default;
defaultValue = state.modalCurrentDisplayItem.default;
current = state.modalCurrentDisplayItem.current;
}
return ( return (
<View <View
style={{ style={{
flex: 1, flex: 1,
padding: 20, padding: 20,
}}> }}>
<Title>{state.modalCurrentDisplayItem.key}</Title> <Title>{key}</Title>
<Subheading> <Subheading>Default: {defaultValue}</Subheading>
Default: {state.modalCurrentDisplayItem.default} <Subheading>Current: {current}</Subheading>
</Subheading>
<Subheading>
Current: {state.modalCurrentDisplayItem.current}
</Subheading>
<TextInput <TextInput
label="New Value" label="New Value"
onChangeText={(text: string) => { onChangeText={(text: string) => {
@ -116,10 +119,7 @@ class DebugScreen extends React.Component<PropsType, StateType> {
dark dark
color={props.theme.colors.success} color={props.theme.colors.success}
onPress={() => { onPress={() => {
this.saveNewPrefs( this.saveNewPrefs(key, this.modalInputValue);
state.modalCurrentDisplayItem.key,
this.modalInputValue,
);
}}> }}>
Save new value Save new value
</Button> </Button>
@ -128,10 +128,7 @@ class DebugScreen extends React.Component<PropsType, StateType> {
dark dark
color={props.theme.colors.danger} color={props.theme.colors.danger}
onPress={() => { onPress={() => {
this.saveNewPrefs( this.saveNewPrefs(key, defaultValue);
state.modalCurrentDisplayItem.key,
state.modalCurrentDisplayItem.default,
);
}}> }}>
Reset to default Reset to default
</Button> </Button>
@ -140,7 +137,7 @@ class DebugScreen extends React.Component<PropsType, StateType> {
); );
} }
getRenderItem = ({item}: {item: PreferenceItemType}): React.Node => { getRenderItem = ({item}: {item: PreferenceItemType}) => {
return ( return (
<List.Item <List.Item
title={item.key} title={item.key}
@ -170,7 +167,9 @@ class DebugScreen extends React.Component<PropsType, StateType> {
this.setState({ this.setState({
modalCurrentDisplayItem: item, modalCurrentDisplayItem: item,
}); });
if (this.modalRef) this.modalRef.open(); if (this.modalRef) {
this.modalRef.open();
}
} }
/** /**
@ -199,24 +198,25 @@ class DebugScreen extends React.Component<PropsType, StateType> {
*/ */
saveNewPrefs(key: string, value: string) { saveNewPrefs(key: string, value: string) {
this.setState((prevState: StateType): { this.setState((prevState: StateType): {
currentPreferences: Array<PreferenceItemType>, currentPreferences: Array<PreferenceItemType>;
} => { } => {
const currentPreferences = [...prevState.currentPreferences]; const currentPreferences = [...prevState.currentPreferences];
currentPreferences[this.findIndexOfKey(key)].current = value; currentPreferences[this.findIndexOfKey(key)].current = value;
return {currentPreferences}; return {currentPreferences};
}); });
AsyncStorageManager.set(key, value); AsyncStorageManager.set(key, value);
if (this.modalRef) {
this.modalRef.close(); this.modalRef.close();
} }
}
render(): React.Node { render() {
const {state} = this; const {state} = this;
return ( return (
<View> <View>
<CustomModal onRef={this.onModalRef}> <CustomModal onRef={this.onModalRef}>
{this.getModalContent()} {this.getModalContent()}
</CustomModal> </CustomModal>
{/* $FlowFixMe */}
<CollapsibleFlatList <CollapsibleFlatList
data={state.currentPreferences} data={state.currentPreferences}
extraData={state.currentPreferences} extraData={state.currentPreferences}