Application Android et IOS pour l'amicale des élèves https://play.google.com/store/apps/details?id=fr.amicaleinsat.application
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 13KB

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