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 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. // @flow
  2. import * as React from 'react';
  3. import {FlatList, Linking, Platform, View} from 'react-native';
  4. import {Body, Card, CardItem, Container, Content, H1, Left, Right, Text, Thumbnail, Button} from 'native-base';
  5. import CustomHeader from "../../components/CustomHeader";
  6. import i18n from "i18n-js";
  7. import appJson from '../../app';
  8. import packageJson from '../../package';
  9. import CustomMaterialIcon from "../../components/CustomMaterialIcon";
  10. import AsyncStorageManager from "../../utils/AsyncStorageManager";
  11. import {Modalize} from "react-native-modalize";
  12. import ThemeManager from "../../utils/ThemeManager";
  13. const links = {
  14. appstore: 'https://apps.apple.com/us/app/campus-amicale-insat/id1477722148',
  15. playstore: 'https://play.google.com/store/apps/details?id=fr.amicaleinsat.application',
  16. git: 'https://git.srv-falcon.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/README.md',
  17. bugsMail: 'mailto:vergnet@etud.insa-toulouse.fr?' +
  18. 'subject=' +
  19. '[BUG] Application Amicale INSA Toulouse' +
  20. '&body=' +
  21. 'Coucou Arnaud ça bug c\'est nul,\n\n' +
  22. 'Informations sur ton système si tu sais (iOS ou Android, modèle du tel, version):\n\n\n' +
  23. 'Nature du problème :\n\n\n' +
  24. 'Étapes pour reproduire ce pb :\n\n\n\n' +
  25. 'Stp corrige le pb, bien cordialement.',
  26. bugsGit: 'https://git.srv-falcon.etud.insa-toulouse.fr/vergnet/application-amicale/issues',
  27. changelog: 'https://git.srv-falcon.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/Changelog.md',
  28. license: 'https://git.srv-falcon.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/LICENSE',
  29. authorMail: "mailto:vergnet@etud.insa-toulouse.fr?" +
  30. "subject=" +
  31. "Application Amicale INSA Toulouse" +
  32. "&body=" +
  33. "Coucou !\n\n",
  34. authorLinkedin: 'https://www.linkedin.com/in/arnaud-vergnet-434ba5179/',
  35. yohanMail: "mailto:ysimard@etud.insa-toulouse.fr?" +
  36. "subject=" +
  37. "Application Amicale INSA Toulouse" +
  38. "&body=" +
  39. "Coucou !\n\n",
  40. yohanLinkedin: 'https://www.linkedin.com/in/yohan-simard', // TODO set real link
  41. react: 'https://facebook.github.io/react-native/',
  42. };
  43. type Props = {
  44. navigation: Object,
  45. };
  46. type State = {
  47. isDebugUnlocked: boolean,
  48. };
  49. /**
  50. * Opens a link in the device's browser
  51. * @param link The link to open
  52. */
  53. function openWebLink(link) {
  54. Linking.openURL(link).catch((err) => console.error('Error opening link', err));
  55. }
  56. /**
  57. * Class defining an about screen. This screen shows the user information about the app and it's author.
  58. */
  59. export default class AboutScreen extends React.Component<Props, State> {
  60. debugTapCounter = 0;
  61. modalRef: { current: null | Modalize };
  62. state = {
  63. isDebugUnlocked: AsyncStorageManager.getInstance().preferences.debugUnlocked.current === '1'
  64. };
  65. constructor(props: any) {
  66. super(props);
  67. this.modalRef = React.createRef();
  68. }
  69. /**
  70. * Data to be displayed in the app card
  71. */
  72. appData: Array<Object> = [
  73. {
  74. onPressCallback: () => openWebLink(Platform.OS === "ios" ? links.appstore : links.playstore),
  75. icon: Platform.OS === "ios" ? 'apple' : 'google-play',
  76. text: Platform.OS === "ios" ? i18n.t('aboutScreen.appstore') : i18n.t('aboutScreen.playstore'),
  77. showChevron: true
  78. },
  79. {
  80. onPressCallback: () => this.openBugReportModal(),
  81. icon: 'bug',
  82. text: i18n.t('aboutScreen.bugs'),
  83. showChevron: true
  84. },
  85. {
  86. onPressCallback: () => openWebLink(links.git),
  87. icon: 'git',
  88. text: 'Git',
  89. showChevron: true
  90. },
  91. {
  92. onPressCallback: () => openWebLink(links.changelog),
  93. icon: 'refresh',
  94. text: i18n.t('aboutScreen.changelog'),
  95. showChevron: true
  96. },
  97. {
  98. onPressCallback: () => openWebLink(links.license),
  99. icon: 'file-document',
  100. text: i18n.t('aboutScreen.license'),
  101. showChevron: true
  102. },
  103. {
  104. onPressCallback: () => this.props.navigation.navigate('DebugScreen'),
  105. icon: 'bug-check',
  106. text: i18n.t('aboutScreen.debug'),
  107. showChevron: true,
  108. showOnlyDebug: true
  109. },
  110. ];
  111. /**
  112. * Data to be displayed in the author card
  113. */
  114. authorData: Array<Object> = [
  115. {
  116. onPressCallback: () => this.tryUnlockDebugMode(),
  117. icon: 'account-circle',
  118. text: 'Arnaud VERGNET',
  119. showChevron: false
  120. },
  121. {
  122. onPressCallback: () => openWebLink(links.authorMail),
  123. icon: 'email',
  124. text: i18n.t('aboutScreen.authorMail'),
  125. showChevron: true
  126. },
  127. {
  128. onPressCallback: () => openWebLink(links.authorLinkedin),
  129. icon: 'linkedin',
  130. text: 'Linkedin',
  131. showChevron: true
  132. },
  133. ];
  134. /**
  135. * Data to be displayed in the additional developer card
  136. */
  137. additionalDevData: Array<Object> = [
  138. {
  139. onPressCallback: () => console.log('Meme this'),
  140. icon: 'account',
  141. text: 'Yohan SIMARD',
  142. showChevron: false
  143. },
  144. {
  145. onPressCallback: () => openWebLink(links.yohanMail),
  146. icon: 'email',
  147. text: i18n.t('aboutScreen.authorMail'),
  148. showChevron: true
  149. },
  150. {
  151. onPressCallback: () => openWebLink(links.yohanLinkedin),
  152. icon: 'linkedin',
  153. text: 'Linkedin',
  154. showChevron: true
  155. },
  156. ];
  157. /**
  158. * Data to be displayed in the technologies card
  159. */
  160. technoData: Array<Object> = [
  161. {
  162. onPressCallback: () => openWebLink(links.react),
  163. icon: 'react',
  164. text: i18n.t('aboutScreen.reactNative'),
  165. showChevron: true
  166. },
  167. {
  168. onPressCallback: () => this.props.navigation.navigate('AboutDependenciesScreen', {data: packageJson.dependencies}),
  169. icon: 'developer-board',
  170. text: i18n.t('aboutScreen.libs'),
  171. showChevron: true
  172. },
  173. ];
  174. /**
  175. * Get a clickable card item to be rendered inside a card.
  176. *
  177. * @param onPressCallback The callback to use when the item is clicked
  178. * @param icon The icon name to use from MaterialCommunityIcons
  179. * @param text The text to show
  180. * @param showChevron Whether to show a chevron indicating this button will change screen
  181. * @param showOnlyInDebug Should we show te current item only in debug mode?
  182. * @returns {React.Node}
  183. */
  184. getCardItem(onPressCallback: Function, icon: string, text: string, showChevron: boolean, showOnlyInDebug: boolean) {
  185. let shouldShow = !showOnlyInDebug || (showOnlyInDebug && this.state.isDebugUnlocked);
  186. if (shouldShow) {
  187. return (
  188. <CardItem button
  189. onPress={onPressCallback}>
  190. <Left>
  191. <CustomMaterialIcon icon={icon}/>
  192. <Text>{text}</Text>
  193. </Left>
  194. {showChevron ?
  195. <Right>
  196. <CustomMaterialIcon icon="chevron-right"
  197. fontSize={20}/>
  198. </Right>
  199. :
  200. <Right/>
  201. }
  202. </CardItem>)
  203. ;
  204. } else {
  205. return <View/>
  206. }
  207. }
  208. tryUnlockDebugMode() {
  209. this.debugTapCounter = this.debugTapCounter + 1;
  210. console.log(this.debugTapCounter);
  211. if (this.debugTapCounter >= 4) {
  212. this.unlockDebugMode();
  213. }
  214. }
  215. unlockDebugMode() {
  216. console.log('unlocked');
  217. this.setState({isDebugUnlocked: true});
  218. let key = AsyncStorageManager.getInstance().preferences.debugUnlocked.key;
  219. AsyncStorageManager.getInstance().savePref(key, '1');
  220. }
  221. getBugReportModal() {
  222. return (
  223. <Modalize ref={this.modalRef}
  224. adjustToContentHeight
  225. modalStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
  226. <View style={{
  227. flex: 1,
  228. padding: 20
  229. }}>
  230. <H1>{i18n.t('aboutScreen.bugs')}</H1>
  231. <Text>
  232. {i18n.t('aboutScreen.bugsDescription')}
  233. </Text>
  234. <Button
  235. style={{
  236. marginTop: 20,
  237. marginLeft: 'auto',
  238. marginRight: 'auto',
  239. }}
  240. onPress={() => openWebLink(links.bugsMail)}>
  241. <CustomMaterialIcon
  242. icon={'email'}
  243. color={'#fff'}/>
  244. <Text>{i18n.t('aboutScreen.bugsMail')}</Text>
  245. </Button>
  246. <Button
  247. style={{
  248. marginTop: 20,
  249. marginLeft: 'auto',
  250. marginRight: 'auto',
  251. }}
  252. onPress={() => openWebLink(links.bugsGit)}>
  253. <CustomMaterialIcon
  254. icon={'git'}
  255. color={'#fff'}/>
  256. <Text>{i18n.t('aboutScreen.bugsGit')}</Text>
  257. </Button>
  258. </View>
  259. </Modalize>
  260. );
  261. }
  262. openBugReportModal() {
  263. if (this.modalRef.current) {
  264. this.modalRef.current.open();
  265. }
  266. }
  267. render() {
  268. const nav = this.props.navigation;
  269. return (
  270. <Container>
  271. {this.getBugReportModal()}
  272. <CustomHeader navigation={nav} title={i18n.t('screens.about')} hasBackButton={true}/>
  273. <Content padder>
  274. <Card>
  275. <CardItem>
  276. <Left>
  277. <Thumbnail square source={require('../../assets/icon.png')}/>
  278. <Body>
  279. <H1>{appJson.expo.name}</H1>
  280. <Text note>
  281. v.{appJson.expo.version}
  282. </Text>
  283. </Body>
  284. </Left>
  285. </CardItem>
  286. <FlatList
  287. data={this.appData}
  288. extraData={this.state}
  289. keyExtractor={(item) => item.icon}
  290. renderItem={({item}) =>
  291. this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
  292. }
  293. />
  294. </Card>
  295. <Card>
  296. <CardItem>
  297. <Left>
  298. <CustomMaterialIcon
  299. icon={'account-multiple'}
  300. fontSize={40}
  301. width={40}
  302. color={ThemeManager.getCurrentThemeVariables().brandPrimary}/>
  303. <Body>
  304. <H1>{i18n.t('aboutScreen.team')}</H1>
  305. </Body>
  306. </Left>
  307. </CardItem>
  308. <CardItem header>
  309. <Text>{i18n.t('aboutScreen.author')}</Text>
  310. </CardItem>
  311. <FlatList
  312. data={this.authorData}
  313. extraData={this.state}
  314. keyExtractor={(item) => item.icon}
  315. renderItem={({item}) =>
  316. this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
  317. }
  318. />
  319. <CardItem header>
  320. <Text>{i18n.t('aboutScreen.additionalDev')}</Text>
  321. </CardItem>
  322. <FlatList
  323. data={this.additionalDevData}
  324. extraData={this.state}
  325. keyExtractor={(item) => item.icon}
  326. renderItem={({item}) =>
  327. this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
  328. }
  329. />
  330. </Card>
  331. <Card>
  332. <CardItem header>
  333. <Text>{i18n.t('aboutScreen.technologies')}</Text>
  334. </CardItem>
  335. <FlatList
  336. data={this.technoData}
  337. extraData={this.state}
  338. keyExtractor={(item) => item.icon}
  339. renderItem={({item}) =>
  340. this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
  341. }
  342. />
  343. </Card>
  344. </Content>
  345. </Container>
  346. );
  347. }
  348. }