From 483970c9a83ee1089c2dc5cbcff424771cd7bce1 Mon Sep 17 00:00:00 2001 From: Arnaud Vergnet Date: Wed, 5 Aug 2020 00:37:51 +0200 Subject: [PATCH] Improve about components to match linter --- src/screens/About/AboutDependenciesScreen.js | 102 +-- src/screens/About/AboutScreen.js | 675 ++++++++++--------- src/screens/About/DebugScreen.js | 356 +++++----- 3 files changed, 601 insertions(+), 532 deletions(-) diff --git a/src/screens/About/AboutDependenciesScreen.js b/src/screens/About/AboutDependenciesScreen.js index 4cb7c6e..15a7341 100644 --- a/src/screens/About/AboutDependenciesScreen.js +++ b/src/screens/About/AboutDependenciesScreen.js @@ -1,36 +1,31 @@ // @flow import * as React from 'react'; -import packageJson from '../../../package'; import {List} from 'react-native-paper'; -import {StackNavigationProp} from "@react-navigation/stack"; -import CollapsibleFlatList from "../../components/Collapsible/CollapsibleFlatList"; -import {View} from "react-native-animatable"; +import {View} from 'react-native-animatable'; +import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList'; +import packageJson from '../../../package.json'; -type listItem = { - name: string, - version: string +type ListItemType = { + name: string, + version: string, }; /** * Generates the dependencies list from the raw json * * @param object The raw json - * @return {Array} + * @return {Array} */ -function generateListFromObject(object: { [key: string]: string }): Array { - let list = []; - let keys = Object.keys(object); - let values = Object.values(object); - for (let i = 0; i < keys.length; i++) { - list.push({name: keys[i], version: values[i]}); - } - //$FlowFixMe - return list; -} - -type Props = { - navigation: StackNavigationProp, +function generateListFromObject(object: { + [key: string]: string, +}): Array { + const list = []; + const keys = Object.keys(object); + keys.forEach((key: string) => { + list.push({name: key, version: object[key]}); + }); + return list; } const LIST_ITEM_HEIGHT = 64; @@ -38,38 +33,45 @@ const LIST_ITEM_HEIGHT = 64; /** * Class defining a screen showing the list of libraries used by the app, taken from package.json */ -export default class AboutDependenciesScreen extends React.Component { +export default class AboutDependenciesScreen extends React.Component { + data: Array; - data: Array; + constructor() { + super(); + this.data = generateListFromObject(packageJson.dependencies); + } - constructor() { - super(); - this.data = generateListFromObject(packageJson.dependencies); - } + keyExtractor = (item: ListItemType): string => item.name; - keyExtractor = (item: listItem) => item.name; + getRenderItem = ({item}: {item: ListItemType}): React.Node => ( + + ); - renderItem = ({item}: { item: listItem }) => - ; + getItemLayout = ( + data: ListItemType, + index: number, + ): {length: number, offset: number, index: number} => ({ + length: LIST_ITEM_HEIGHT, + offset: LIST_ITEM_HEIGHT * index, + index, + }); - itemLayout = (data: any, index: number) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index}); - - render() { - return ( - - - - ); - } + render(): React.Node { + return ( + + + + ); + } } diff --git a/src/screens/About/AboutScreen.js b/src/screens/About/AboutScreen.js index 20867f2..e9a7371 100644 --- a/src/screens/About/AboutScreen.js +++ b/src/screens/About/AboutScreen.js @@ -1,351 +1,390 @@ // @flow import * as React from 'react'; -import {FlatList, Linking, Platform, View} from 'react-native'; -import i18n from "i18n-js"; +import {FlatList, Linking, Platform} from 'react-native'; +import i18n from 'i18n-js'; import {Avatar, Card, List, Title, withTheme} from 'react-native-paper'; -import packageJson from "../../../package.json"; -import {StackNavigationProp} from "@react-navigation/stack"; -import CollapsibleFlatList from "../../components/Collapsible/CollapsibleFlatList"; +import {StackNavigationProp} from '@react-navigation/stack'; +import packageJson from '../../../package.json'; +import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList'; +import APP_LOGO from '../../../assets/android.icon.png'; -type ListItem = { - onPressCallback: () => void, - icon: string, - text: string, - showChevron: boolean +type ListItemType = { + onPressCallback: () => void, + icon: string, + text: string, + showChevron: boolean, }; const links = { - appstore: 'https://apps.apple.com/us/app/campus-amicale-insat/id1477722148', - playstore: 'https://play.google.com/store/apps/details?id=fr.amicaleinsat.application', - git: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/README.md', - changelog: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/Changelog.md', - license: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/LICENSE', - authorMail: "mailto:vergnet@etud.insa-toulouse.fr?" + - "subject=" + - "Application Amicale INSA Toulouse" + - "&body=" + - "Coucou !\n\n", - authorLinkedin: 'https://www.linkedin.com/in/arnaud-vergnet-434ba5179/', - yohanMail: "mailto:ysimard@etud.insa-toulouse.fr?" + - "subject=" + - "Application Amicale INSA Toulouse" + - "&body=" + - "Coucou !\n\n", - yohanLinkedin: 'https://www.linkedin.com/in/yohan-simard', - react: 'https://facebook.github.io/react-native/', - meme: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" + appstore: 'https://apps.apple.com/us/app/campus-amicale-insat/id1477722148', + playstore: + 'https://play.google.com/store/apps/details?id=fr.amicaleinsat.application', + git: + 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/README.md', + changelog: + 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/Changelog.md', + license: + 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/LICENSE', + authorMail: + 'mailto:vergnet@etud.insa-toulouse.fr?' + + 'subject=' + + 'Application Amicale INSA Toulouse' + + '&body=' + + 'Coucou !\n\n', + authorLinkedin: 'https://www.linkedin.com/in/arnaud-vergnet-434ba5179/', + yohanMail: + 'mailto:ysimard@etud.insa-toulouse.fr?' + + 'subject=' + + 'Application Amicale INSA Toulouse' + + '&body=' + + 'Coucou !\n\n', + yohanLinkedin: 'https://www.linkedin.com/in/yohan-simard', + react: 'https://facebook.github.io/react-native/', + meme: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', }; -type Props = { - navigation: StackNavigationProp, +type PropsType = { + navigation: StackNavigationProp, }; /** * Opens a link in the device's browser * @param link The link to open */ -function openWebLink(link) { - Linking.openURL(link).catch((err) => console.error('Error opening link', err)); +function openWebLink(link: string) { + Linking.openURL(link); } /** * Class defining an about screen. This screen shows the user information about the app and it's author. */ -class AboutScreen extends React.Component { +class AboutScreen extends React.Component { + /** + * Data to be displayed in the app card + */ + appData = [ + { + onPressCallback: () => { + openWebLink(Platform.OS === 'ios' ? links.appstore : links.playstore); + }, + icon: Platform.OS === 'ios' ? 'apple' : 'google-play', + text: + Platform.OS === 'ios' + ? i18n.t('screens.about.appstore') + : i18n.t('screens.about.playstore'), + showChevron: true, + }, + { + onPressCallback: () => { + const {navigation} = this.props; + navigation.navigate('feedback'); + }, + icon: 'bug', + text: i18n.t('screens.feedback.homeButtonTitle'), + showChevron: true, + }, + { + onPressCallback: () => { + openWebLink(links.git); + }, + icon: 'git', + text: 'Git', + showChevron: true, + }, + { + onPressCallback: () => { + openWebLink(links.changelog); + }, + icon: 'refresh', + text: i18n.t('screens.about.changelog'), + showChevron: true, + }, + { + onPressCallback: () => { + openWebLink(links.license); + }, + icon: 'file-document', + text: i18n.t('screens.about.license'), + showChevron: true, + }, + ]; - /** - * Data to be displayed in the app card - */ - appData = [ - { - onPressCallback: () => openWebLink(Platform.OS === "ios" ? links.appstore : links.playstore), - icon: Platform.OS === "ios" ? 'apple' : 'google-play', - text: Platform.OS === "ios" ? i18n.t('screens.about.appstore') : i18n.t('screens.about.playstore'), - showChevron: true - }, - { - onPressCallback: () => this.props.navigation.navigate("feedback"), - icon: 'bug', - text: i18n.t("screens.feedback.homeButtonTitle"), - showChevron: true - }, - { - onPressCallback: () => openWebLink(links.git), - icon: 'git', - text: 'Git', - showChevron: true - }, - { - onPressCallback: () => openWebLink(links.changelog), - icon: 'refresh', - text: i18n.t('screens.about.changelog'), - showChevron: true - }, - { - onPressCallback: () => openWebLink(links.license), - icon: 'file-document', - text: i18n.t('screens.about.license'), - showChevron: true - }, - ]; - /** - * Data to be displayed in the author card - */ - authorData = [ - { - onPressCallback: () => openWebLink(links.meme), - icon: 'account-circle', - text: 'Arnaud VERGNET', - showChevron: false - }, - { - onPressCallback: () => openWebLink(links.authorMail), - icon: 'email', - text: i18n.t('screens.about.authorMail'), - showChevron: true - }, - { - onPressCallback: () => openWebLink(links.authorLinkedin), - icon: 'linkedin', - text: 'Linkedin', - showChevron: true - }, - ]; - /** - * Data to be displayed in the additional developer card - */ - additionalDevData = [ - { - onPressCallback: () => console.log('Meme this'), - icon: 'account', - text: 'Yohan SIMARD', - showChevron: false - }, - { - onPressCallback: () => openWebLink(links.yohanMail), - icon: 'email', - text: i18n.t('screens.about.authorMail'), - showChevron: true - }, - { - onPressCallback: () => openWebLink(links.yohanLinkedin), - icon: 'linkedin', - text: 'Linkedin', - showChevron: true - }, - ]; - /** - * Data to be displayed in the technologies card - */ - technoData = [ - { - onPressCallback: () => openWebLink(links.react), - icon: 'react', - text: i18n.t('screens.about.reactNative'), - showChevron: true - }, - { - onPressCallback: () => this.props.navigation.navigate('dependencies'), - icon: 'developer-board', - text: i18n.t('screens.about.libs'), - showChevron: true - }, - ]; - /** - * Order of information cards - */ - dataOrder = [ - { - id: 'app', - }, - { - id: 'team', - }, - { - id: 'techno', - }, - ]; + /** + * Data to be displayed in the author card + */ + authorData = [ + { + onPressCallback: () => { + openWebLink(links.meme); + }, + icon: 'account-circle', + text: 'Arnaud VERGNET', + showChevron: false, + }, + { + onPressCallback: () => { + openWebLink(links.authorMail); + }, + icon: 'email', + text: i18n.t('screens.about.authorMail'), + showChevron: true, + }, + { + onPressCallback: () => { + openWebLink(links.authorLinkedin); + }, + icon: 'linkedin', + text: 'Linkedin', + showChevron: true, + }, + ]; - /** - * Gets the app icon - * - * @param props - * @return {*} - */ - getAppIcon(props) { - return ( + /** + * Data to be displayed in the additional developer card + */ + additionalDevData = [ + { + onPressCallback: () => { + console.log('Meme this'); + }, + icon: 'account', + text: 'Yohan SIMARD', + showChevron: false, + }, + { + onPressCallback: () => { + openWebLink(links.yohanMail); + }, + icon: 'email', + text: i18n.t('screens.about.authorMail'), + showChevron: true, + }, + { + onPressCallback: () => { + openWebLink(links.yohanLinkedin); + }, + icon: 'linkedin', + text: 'Linkedin', + showChevron: true, + }, + ]; + + /** + * Data to be displayed in the technologies card + */ + technoData = [ + { + onPressCallback: () => { + openWebLink(links.react); + }, + icon: 'react', + text: i18n.t('screens.about.reactNative'), + showChevron: true, + }, + { + onPressCallback: () => { + const {navigation} = this.props; + navigation.navigate('dependencies'); + }, + icon: 'developer-board', + text: i18n.t('screens.about.libs'), + showChevron: true, + }, + ]; + + /** + * Order of information cards + */ + dataOrder = [ + { + id: 'app', + }, + { + id: 'team', + }, + { + id: 'techno', + }, + ]; + + /** + * Gets the app card showing information and links about the app. + * + * @return {*} + */ + getAppCard(): React.Node { + return ( + + ( - ); + )} + /> + + + + + ); + } + + /** + * Gets the team card showing information and links about the team + * + * @return {*} + */ + getTeamCard(): React.Node { + return ( + + ( + + )} + /> + + {i18n.t('screens.about.author')} + + {i18n.t('screens.about.additionalDev')} + + + + ); + } + + /** + * Gets the techno card showing information and links about the technologies used in the app + * + * @return {*} + */ + getTechnoCard(): React.Node { + return ( + + + {i18n.t('screens.about.technologies')} + + + + ); + } + + /** + * Gets a chevron icon + * + * @param props + * @return {*} + */ + static getChevronIcon({ + size, + color, + }: { + size: number, + color: string, + }): React.Node { + return ; + } + + /** + * Gets a custom list item icon + * + * @param item The item to show the icon for + * @param props + * @return {*} + */ + static getItemIcon( + item: ListItemType, + {size, color}: {size: number, color: string}, + ): React.Node { + return ; + } + + /** + * Gets a clickable card item to be rendered inside a card. + * + * @returns {*} + */ + getCardItem = ({item}: {item: ListItemType}): React.Node => { + const getItemIcon = (props: {size: number, color: string}): React.Node => + AboutScreen.getItemIcon(item, props); + if (item.showChevron) { + return ( + + ); } + return ( + + ); + }; - /** - * Extracts a key from the given item - * - * @param item The item to extract the key from - * @return {string} The extracted key - */ - keyExtractor(item: ListItem): string { - return item.icon; + /** + * Gets a card, depending on the given item's id + * + * @param item The item to show + * @return {*} + */ + getMainCard = ({item}: {item: {id: string}}): React.Node => { + switch (item.id) { + case 'app': + return this.getAppCard(); + case 'team': + return this.getTeamCard(); + case 'techno': + return this.getTechnoCard(); + default: + return null; } + }; - /** - * Gets the app card showing information and links about the app. - * - * @return {*} - */ - getAppCard() { - return ( - - - - - - - ); - } + /** + * Extracts a key from the given item + * + * @param item The item to extract the key from + * @return {string} The extracted key + */ + keyExtractor = (item: ListItemType): string => item.icon; - /** - * Gets the team card showing information and links about the team - * - * @return {*} - */ - getTeamCard() { - return ( - - }/> - - {i18n.t('screens.about.author')} - - {i18n.t('screens.about.additionalDev')} - - - - ); - } - - /** - * Gets the techno card showing information and links about the technologies used in the app - * - * @return {*} - */ - getTechnoCard() { - return ( - - - {i18n.t('screens.about.technologies')} - - - - ); - } - - /** - * Gets a chevron icon - * - * @param props - * @return {*} - */ - getChevronIcon(props) { - return ( - - ); - } - - /** - * Gets a custom list item icon - * - * @param item The item to show the icon for - * @param props - * @return {*} - */ - getItemIcon(item: ListItem, props) { - return ( - - ); - } - - /** - * Gets a clickable card item to be rendered inside a card. - * - * @returns {*} - */ - getCardItem = ({item}: { item: ListItem }) => { - const getItemIcon = this.getItemIcon.bind(this, item); - if (item.showChevron) { - return ( - - ); - } else { - return ( - - ); - } - }; - - /** - * Gets a card, depending on the given item's id - * - * @param item The item to show - * @return {*} - */ - getMainCard = ({item}: { item: { id: string } }) => { - switch (item.id) { - case 'app': - return this.getAppCard(); - case 'team': - return this.getTeamCard(); - case 'techno': - return this.getTechnoCard(); - } - return ; - }; - - render() { - return ( - - ); - } + render(): React.Node { + return ( + + ); + } } export default withTheme(AboutScreen); diff --git a/src/screens/About/DebugScreen.js b/src/screens/About/DebugScreen.js index 101683d..c1dea21 100644 --- a/src/screens/About/DebugScreen.js +++ b/src/screens/About/DebugScreen.js @@ -1,183 +1,211 @@ // @flow import * as React from 'react'; -import {View} from "react-native"; -import AsyncStorageManager from "../../managers/AsyncStorageManager"; -import CustomModal from "../../components/Overrides/CustomModal"; -import {Button, List, Subheading, TextInput, Title, withTheme} from 'react-native-paper'; -import {StackNavigationProp} from "@react-navigation/stack"; -import {Modalize} from "react-native-modalize"; -import type {CustomTheme} from "../../managers/ThemeManager"; -import CollapsibleFlatList from "../../components/Collapsible/CollapsibleFlatList"; +import {View} from 'react-native'; +import { + Button, + List, + Subheading, + TextInput, + Title, + withTheme, +} from 'react-native-paper'; +import {Modalize} from 'react-native-modalize'; +import CustomModal from '../../components/Overrides/CustomModal'; +import AsyncStorageManager from '../../managers/AsyncStorageManager'; +import type {CustomThemeType} from '../../managers/ThemeManager'; +import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList'; -type PreferenceItem = { - key: string, - default: string, - current: string, -} - -type Props = { - navigation: StackNavigationProp, - theme: CustomTheme +type PreferenceItemType = { + key: string, + default: string, + current: string, }; -type State = { - modalCurrentDisplayItem: PreferenceItem, - currentPreferences: Array, -} +type PropsType = { + theme: CustomThemeType, +}; + +type StateType = { + modalCurrentDisplayItem: PreferenceItemType, + currentPreferences: Array, +}; /** * Class defining the Debug screen. * This screen allows the user to get and modify information on the app/device. */ -class DebugScreen extends React.Component { +class DebugScreen extends React.Component { + modalRef: Modalize; - modalRef: Modalize; - modalInputValue: string; + modalInputValue: string; - /** - * Copies user preferences to state for easier manipulation - * - * @param props - */ - constructor(props) { - super(props); - this.modalInputValue = ""; - let currentPreferences : Array = []; - Object.values(AsyncStorageManager.PREFERENCES).map((object: any) => { - let newObject: PreferenceItem = {...object}; - newObject.current = AsyncStorageManager.getString(newObject.key); - currentPreferences.push(newObject); - }); - this.state = { - modalCurrentDisplayItem: {}, - currentPreferences: currentPreferences - }; - } - - /** - * Shows the edit modal - * - * @param item - */ - showEditModal(item: PreferenceItem) { - this.setState({ - modalCurrentDisplayItem: item - }); - if (this.modalRef) { - this.modalRef.open(); - } - } - - /** - * Gets the edit modal content - * - * @return {*} - */ - getModalContent() { - return ( - - {this.state.modalCurrentDisplayItem.key} - Default: {this.state.modalCurrentDisplayItem.default} - Current: {this.state.modalCurrentDisplayItem.current} - this.modalInputValue = text} - /> - - - - - - - ); - } - - /** - * Finds the index of the given key in the preferences array - * - * @param key THe key to find the index of - * @returns {number} - */ - findIndexOfKey(key: string) { - let index = -1; - for (let i = 0; i < this.state.currentPreferences.length; i++) { - if (this.state.currentPreferences[i].key === key) { - index = i; - break; - } - } - return index; - } - - /** - * Saves the new value of the given preference - * - * @param key The pref key - * @param value The pref value - */ - saveNewPrefs(key: string, value: string) { - this.setState((prevState) => { - let currentPreferences = [...prevState.currentPreferences]; - currentPreferences[this.findIndexOfKey(key)].current = value; - return {currentPreferences}; - }); - AsyncStorageManager.set(key, value); - this.modalRef.close(); - } - - /** - * Callback used when receiving the modal ref - * - * @param ref - */ - onModalRef = (ref: Modalize) => { - this.modalRef = ref; - } - - renderItem = ({item}: {item: PreferenceItem}) => { - return ( - this.showEditModal(item)} - /> - ); + /** + * Copies user preferences to state for easier manipulation + * + * @param props + */ + constructor(props: PropsType) { + super(props); + this.modalInputValue = ''; + const currentPreferences: Array = []; + // eslint-disable-next-line flowtype/no-weak-types + Object.values(AsyncStorageManager.PREFERENCES).forEach((object: any) => { + const newObject: PreferenceItemType = {...object}; + newObject.current = AsyncStorageManager.getString(newObject.key); + currentPreferences.push(newObject); + }); + this.state = { + modalCurrentDisplayItem: {}, + currentPreferences, }; + } - render() { - return ( - - - {this.getModalContent()} - - {/*$FlowFixMe*/} - - - ); + /** + * Gets the edit modal content + * + * @return {*} + */ + getModalContent(): React.Node { + const {props, state} = this; + return ( + + {state.modalCurrentDisplayItem.key} + + Default: {state.modalCurrentDisplayItem.default} + + + Current: {state.modalCurrentDisplayItem.current} + + { + this.modalInputValue = text; + }} + /> + + + + + + ); + } + + getRenderItem = ({item}: {item: PreferenceItemType}): React.Node => { + return ( + { + this.showEditModal(item); + }} + /> + ); + }; + + /** + * Callback used when receiving the modal ref + * + * @param ref + */ + onModalRef = (ref: Modalize) => { + this.modalRef = ref; + }; + + /** + * Shows the edit modal + * + * @param item + */ + showEditModal(item: PreferenceItemType) { + this.setState({ + modalCurrentDisplayItem: item, + }); + if (this.modalRef) this.modalRef.open(); + } + + /** + * Finds the index of the given key in the preferences array + * + * @param key THe key to find the index of + * @returns {number} + */ + findIndexOfKey(key: string): number { + const {currentPreferences} = this.state; + let index = -1; + for (let i = 0; i < currentPreferences.length; i += 1) { + if (currentPreferences[i].key === key) { + index = i; + break; + } } + return index; + } + + /** + * Saves the new value of the given preference + * + * @param key The pref key + * @param value The pref value + */ + saveNewPrefs(key: string, value: string) { + this.setState((prevState: StateType): { + currentPreferences: Array, + } => { + const currentPreferences = [...prevState.currentPreferences]; + currentPreferences[this.findIndexOfKey(key)].current = value; + return {currentPreferences}; + }); + AsyncStorageManager.set(key, value); + this.modalRef.close(); + } + + render(): React.Node { + const {state} = this; + return ( + + + {this.getModalContent()} + + {/* $FlowFixMe */} + + + ); + } } export default withTheme(DebugScreen);