Application Android et IOS pour l'amicale des élèves
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AboutScreen.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. // @flow
  2. import * as React from 'react';
  3. import {FlatList, Linking, Platform, View} from 'react-native';
  4. import i18n from "i18n-js";
  5. import appJson from '../../../app';
  6. import AsyncStorageManager from "../../managers/AsyncStorageManager";
  7. import {Avatar, Card, List, Title, withTheme} from 'react-native-paper';
  8. const links = {
  9. appstore: 'https://apps.apple.com/us/app/campus-amicale-insat/id1477722148',
  10. playstore: 'https://play.google.com/store/apps/details?id=fr.amicaleinsat.application',
  11. git: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/README.md',
  12. changelog: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/Changelog.md',
  13. license: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/LICENSE',
  14. authorMail: "mailto:vergnet@etud.insa-toulouse.fr?" +
  15. "subject=" +
  16. "Application Amicale INSA Toulouse" +
  17. "&body=" +
  18. "Coucou !\n\n",
  19. authorLinkedin: 'https://www.linkedin.com/in/arnaud-vergnet-434ba5179/',
  20. yohanMail: "mailto:ysimard@etud.insa-toulouse.fr?" +
  21. "subject=" +
  22. "Application Amicale INSA Toulouse" +
  23. "&body=" +
  24. "Coucou !\n\n",
  25. yohanLinkedin: 'https://www.linkedin.com/in/yohan-simard',
  26. react: 'https://facebook.github.io/react-native/',
  27. expo: 'https://expo.io/',
  28. };
  29. type Props = {
  30. navigation: Object,
  31. };
  32. type State = {
  33. isDebugUnlocked: boolean,
  34. };
  35. /**
  36. * Opens a link in the device's browser
  37. * @param link The link to open
  38. */
  39. function openWebLink(link) {
  40. Linking.openURL(link).catch((err) => console.error('Error opening link', err));
  41. }
  42. /**
  43. * Class defining an about screen. This screen shows the user information about the app and it's author.
  44. */
  45. class AboutScreen extends React.Component<Props, State> {
  46. debugTapCounter = 0;
  47. modalRef: Object;
  48. state = {
  49. isDebugUnlocked: AsyncStorageManager.getInstance().preferences.debugUnlocked.current === '1'
  50. };
  51. /**
  52. * Data to be displayed in the app card
  53. */
  54. appData: Array<Object> = [
  55. {
  56. onPressCallback: () => openWebLink(Platform.OS === "ios" ? links.appstore : links.playstore),
  57. icon: Platform.OS === "ios" ? 'apple' : 'google-play',
  58. text: Platform.OS === "ios" ? i18n.t('aboutScreen.appstore') : i18n.t('aboutScreen.playstore'),
  59. showChevron: true
  60. },
  61. {
  62. onPressCallback: () => this.props.navigation.navigate("feedback"),
  63. icon: 'bug',
  64. text: i18n.t("feedbackScreen.homeButtonTitle"),
  65. showChevron: true
  66. },
  67. {
  68. onPressCallback: () => openWebLink(links.git),
  69. icon: 'git',
  70. text: 'Git',
  71. showChevron: true
  72. },
  73. {
  74. onPressCallback: () => openWebLink(links.changelog),
  75. icon: 'refresh',
  76. text: i18n.t('aboutScreen.changelog'),
  77. showChevron: true
  78. },
  79. {
  80. onPressCallback: () => openWebLink(links.license),
  81. icon: 'file-document',
  82. text: i18n.t('aboutScreen.license'),
  83. showChevron: true
  84. },
  85. {
  86. onPressCallback: () => this.props.navigation.navigate('debug'),
  87. icon: 'bug-check',
  88. text: i18n.t('aboutScreen.debug'),
  89. showChevron: true,
  90. showOnlyInDebug: true
  91. },
  92. ];
  93. /**
  94. * Data to be displayed in the author card
  95. */
  96. authorData: Array<Object> = [
  97. {
  98. onPressCallback: () => this.tryUnlockDebugMode(),
  99. icon: 'account-circle',
  100. text: 'Arnaud VERGNET',
  101. showChevron: false
  102. },
  103. {
  104. onPressCallback: () => openWebLink(links.authorMail),
  105. icon: 'email',
  106. text: i18n.t('aboutScreen.authorMail'),
  107. showChevron: true
  108. },
  109. {
  110. onPressCallback: () => openWebLink(links.authorLinkedin),
  111. icon: 'linkedin',
  112. text: 'Linkedin',
  113. showChevron: true
  114. },
  115. ];
  116. /**
  117. * Data to be displayed in the additional developer card
  118. */
  119. additionalDevData: Array<Object> = [
  120. {
  121. onPressCallback: () => console.log('Meme this'),
  122. icon: 'account',
  123. text: 'Yohan SIMARD',
  124. showChevron: false
  125. },
  126. {
  127. onPressCallback: () => openWebLink(links.yohanMail),
  128. icon: 'email',
  129. text: i18n.t('aboutScreen.authorMail'),
  130. showChevron: true
  131. },
  132. {
  133. onPressCallback: () => openWebLink(links.yohanLinkedin),
  134. icon: 'linkedin',
  135. text: 'Linkedin',
  136. showChevron: true
  137. },
  138. ];
  139. /**
  140. * Data to be displayed in the technologies card
  141. */
  142. technoData: Array<Object> = [
  143. {
  144. onPressCallback: () => openWebLink(links.react),
  145. icon: 'react',
  146. text: i18n.t('aboutScreen.reactNative'),
  147. showChevron: true
  148. },
  149. {
  150. onPressCallback: () => openWebLink(links.react),
  151. icon: 'language-javascript',
  152. text: i18n.t('aboutScreen.expo'),
  153. showChevron: true
  154. },
  155. {
  156. onPressCallback: () => this.props.navigation.navigate('dependencies'),
  157. icon: 'developer-board',
  158. text: i18n.t('aboutScreen.libs'),
  159. showChevron: true
  160. },
  161. ];
  162. /**
  163. * Order of information cards
  164. */
  165. dataOrder: Array<Object> = [
  166. {
  167. id: 'app',
  168. },
  169. {
  170. id: 'team',
  171. },
  172. {
  173. id: 'techno',
  174. },
  175. ];
  176. colors: Object;
  177. constructor(props) {
  178. super(props);
  179. this.colors = props.theme.colors;
  180. }
  181. /**
  182. * Gets the app icon
  183. * @param props
  184. * @return {*}
  185. */
  186. getAppIcon(props) {
  187. return (
  188. <Avatar.Image
  189. {...props}
  190. source={require('../../../assets/android.icon.png')}
  191. style={{backgroundColor: 'transparent'}}
  192. />
  193. );
  194. }
  195. /**
  196. * Extracts a key from the given item
  197. *
  198. * @param item The item to extract the key from
  199. * @return {string} The extracted key
  200. */
  201. keyExtractor(item: Object): string {
  202. return item.icon;
  203. }
  204. /**
  205. * Gets the app card showing information and links about the app.
  206. *
  207. * @return {*}
  208. */
  209. getAppCard() {
  210. return (
  211. <Card style={{marginBottom: 10}}>
  212. <Card.Title
  213. title={appJson.expo.name}
  214. subtitle={appJson.expo.version}
  215. left={this.getAppIcon}/>
  216. <Card.Content>
  217. <FlatList
  218. data={this.appData}
  219. keyExtractor={this.keyExtractor}
  220. renderItem={this.getCardItem}
  221. />
  222. </Card.Content>
  223. </Card>
  224. );
  225. }
  226. /**
  227. * Gets the team card showing information and links about the team
  228. *
  229. * @return {*}
  230. */
  231. getTeamCard() {
  232. return (
  233. <Card style={{marginBottom: 10}}>
  234. <Card.Title
  235. title={i18n.t('aboutScreen.team')}
  236. left={(props) => <Avatar.Icon {...props} icon={'account-multiple'}/>}/>
  237. <Card.Content>
  238. <Title>{i18n.t('aboutScreen.author')}</Title>
  239. <FlatList
  240. data={this.authorData}
  241. keyExtractor={this.keyExtractor}
  242. listKey={"1"}
  243. renderItem={this.getCardItem}
  244. />
  245. <Title>{i18n.t('aboutScreen.additionalDev')}</Title>
  246. <FlatList
  247. data={this.additionalDevData}
  248. keyExtractor={this.keyExtractor}
  249. listKey={"2"}
  250. renderItem={this.getCardItem}
  251. />
  252. </Card.Content>
  253. </Card>
  254. );
  255. }
  256. /**
  257. * Gets the techno card showing information and links about the technologies used in the app
  258. *
  259. * @return {*}
  260. */
  261. getTechnoCard() {
  262. return (
  263. <Card style={{marginBottom: 10}}>
  264. <Card.Content>
  265. <Title>{i18n.t('aboutScreen.technologies')}</Title>
  266. <FlatList
  267. data={this.technoData}
  268. keyExtractor={this.keyExtractor}
  269. renderItem={this.getCardItem}
  270. />
  271. </Card.Content>
  272. </Card>
  273. );
  274. }
  275. /**
  276. * Gets a chevron icon
  277. *
  278. * @param props
  279. * @return {*}
  280. */
  281. getChevronIcon(props: Object) {
  282. return (
  283. <List.Icon {...props} icon={'chevron-right'}/>
  284. );
  285. }
  286. /**
  287. * Gets a custom list item icon
  288. *
  289. * @param item The item to show the icon for
  290. * @param props
  291. * @return {*}
  292. */
  293. getItemIcon(item: Object, props: Object) {
  294. return (
  295. <List.Icon {...props} icon={item.icon}/>
  296. );
  297. }
  298. /**
  299. * Get a clickable card item to be rendered inside a card.
  300. *
  301. * @returns {*}
  302. */
  303. getCardItem = ({item}: Object) => {
  304. let shouldShow = item === undefined
  305. || !item.showOnlyInDebug
  306. || (item.showOnlyInDebug && this.state.isDebugUnlocked);
  307. const getItemIcon = this.getItemIcon.bind(this, item);
  308. if (shouldShow) {
  309. if (item.showChevron) {
  310. return (
  311. <List.Item
  312. title={item.text}
  313. left={getItemIcon}
  314. right={this.getChevronIcon}
  315. onPress={item.onPressCallback}
  316. />
  317. );
  318. } else {
  319. return (
  320. <List.Item
  321. title={item.text}
  322. left={getItemIcon}
  323. onPress={item.onPressCallback}
  324. />
  325. );
  326. }
  327. } else
  328. return null;
  329. };
  330. /**
  331. * Tries to unlock debug mode
  332. */
  333. tryUnlockDebugMode() {
  334. this.debugTapCounter = this.debugTapCounter + 1;
  335. if (this.debugTapCounter >= 4) {
  336. this.unlockDebugMode();
  337. }
  338. }
  339. /**
  340. * Unlocks debug mode
  341. */
  342. unlockDebugMode() {
  343. this.setState({isDebugUnlocked: true});
  344. let key = AsyncStorageManager.getInstance().preferences.debugUnlocked.key;
  345. AsyncStorageManager.getInstance().savePref(key, '1');
  346. }
  347. /**
  348. * Gets a card, depending on the given item's id
  349. *
  350. * @param item The item to show
  351. * @return {*}
  352. */
  353. getMainCard = ({item}: Object) => {
  354. switch (item.id) {
  355. case 'app':
  356. return this.getAppCard();
  357. case 'team':
  358. return this.getTeamCard();
  359. case 'techno':
  360. return this.getTechnoCard();
  361. }
  362. return <View/>;
  363. };
  364. render() {
  365. return (
  366. <FlatList
  367. style={{padding: 5}}
  368. data={this.dataOrder}
  369. renderItem={this.getMainCard}
  370. />
  371. );
  372. }
  373. }
  374. export default withTheme(AboutScreen);