From 17e360dd9bb1458cffbe670bca76fbfc3bd66d24 Mon Sep 17 00:00:00 2001 From: jyu65 <jyu65@illinois.edu> Date: Mon, 29 Oct 2018 10:57:15 -0500 Subject: [PATCH] assignment3.1 --- .DS_Store | Bin 6148 -> 8196 bytes README.md | 2 +- mp3/.DS_Store | Bin 0 -> 6148 bytes mp3/__tests__/Screen-test.js | 87 ++ mp3/__tests__/__snapshots__/App-test.js.snap | 796 ++++++++++++++++++ .../__snapshots__/Screen-test.js.snap | 265 ++++++ .../__snapshots__/StyledText-test.js.snap | 19 + mp3/navigation/MainTabNavigator.js | 2 +- mp3/package-lock.json | 725 +++++++++++++++- mp3/package.json | 5 +- mp3/screens/FollowerScreen.js | 175 +++- mp3/screens/FollowingScreen.js | 240 +++++- mp3/screens/Profile/Detail.js | 37 +- mp3/screens/Profile/Header.js | 2 +- mp3/screens/Profile/Intro.js | 20 +- mp3/screens/Profile/ProfileScreen.js | 296 ++++++- mp3/screens/RepoScreen.js | 93 +- 17 files changed, 2644 insertions(+), 120 deletions(-) create mode 100644 mp3/.DS_Store create mode 100644 mp3/__tests__/Screen-test.js create mode 100644 mp3/__tests__/__snapshots__/App-test.js.snap create mode 100644 mp3/__tests__/__snapshots__/Screen-test.js.snap create mode 100644 mp3/components/__tests__/__snapshots__/StyledText-test.js.snap diff --git a/.DS_Store b/.DS_Store index 2dc296fcb6e4b3372bd4752c1674abacd624a1ed..91a9ae24f3e68eeda67e6662e655a0ef7af967b3 100644 GIT binary patch literal 8196 zcmeHLU2GLa6h5adFuVM8S_*V8La(h=graS!Z4|1vKWH0D+R#FOrR=@C!ph#=>)pM* zK&e)JG0Kw(AUyf^AmL5ogNZN3MBzbAunE<~2OoUU7axsA6VJ?S3l#dQ26mF2Z|2N7 zGxvP+-QCOp0CpCvCV*-HVDt#&tEsw65#!>yqm)FJ6@*Cf5aiOXpQhfmbnXuC*bp-i zGY~TnGY~TnGw^?4fWFzHuw}mcYBa8624V*8O9sUIAxV$GRD`n%<*S1#c?2LVBeN{j z=AuEEj4&19tU?;0f-00yg<^EXKow5*WaO8Ma8{uT2aFCM7_E%a2?gcqG=EaM1Ev(l zb<9A_z?}?;vwJCIAqTtC#aqwst`mffjW@8Qv~0!7RZP>EwpM$7@R(m549&0*bej2b z(Hk(sW9g_p<ooVo+e{yF?BXP^>hitNbUZsRgB{Bzmx*D=v;1PGU+}Cz&NHY6<U*6Y zdV0FGsktH9($q53keqI7YozwB)|nZNZK`i-?>&+|d20If%*z*4Mi{*npnOS&7jLF# z1sOL@KTvo?8N0z$m%6bic{`m`8P6|ftgkkDdi8xHPR92Jom2KCFApf;Ug{3y?I}ub zIODs8tQSo3ij3)I3a%O29j+^!gOSia5sKDW;OE0G={U)GA+QhF<mXJ;-Q-Q7m13s; zT<G{-aLCRFgmtM#m4|kD&4w+t5ASGv;;E;*=GLw&=X#}HH9X}6PTI8(79A@*HfjbL z+p`?+=onGxh0Y6(o!2U`K^yYStUb4JQ#Cgd#skYmF<!?;3Tfx1f)k!pYt$GIYWx#6 zVbL$#?^|L<OO6;dMm=NW!rqm)skY|$y7IM;Y%}zsfO6#~)1;+gr>+kjr#<F@rYud( zx^d7o)3(bkjY+50Hr*JWQYrI&k#TpWZj5C7Y?e|9$R?6DQbs4^SJ`2)aGx23{W;qc zYj3LF*j-~7qr%={S+>O(t4nQD<jM3kF1{=V)ItmFfdLo=3yN?C&cZo(A1=cc_!Pc? zZ{S<F4&T8%`~<(iZ}12F34g)gxDv~eV<oP~BtDAUaR;_x3isl3*n_=z0EclD$8a1i zd=XvDqK8F%1z*M2@O3<cXYm}K$9M5P`~W}1EBG0HiC^JWyoT5D2F|NrS+XGAKGk2S z@ds+%)M<3HRx)}wohJ4^t9SgTI{ki)*r$rh^;H|T)@|F_+_opRxQR=4?N;?j(I{0& zwJfMXZr$zjBN-cs&H9$*WPFgsW}jd}_k7iyLCUB}CK6o8hRN<j_0%mPSu^pMF!b#S z@-!JQmEFYSdJ`jM@)c^dMQ_zeySz+|KB@0!BvHOnPSw6y*Ex`|#WEfB37sR;mI`lK z*<FH<;dA(!1UC;q!q4z4{EmPO*I_ko#Tu-|I;_XXuo0Va7q(zKK7$?DiCx%-`>`Jf zNO<EofroJtO%mR5DZCt>#8Y@0XGnl=;G6iC6ySM$2QT1765vNm<kqtwG=+HSrrf3m z^PcN_N6E4v&fA^i-aWxUsmh{Sod5SOfB%0^<QgXtGY~UycLuPmd$7Bc#+G~Ai?eo; zo+I>#BK&3*$`Gn<y9l6ubR3tyNpcl2sR(Bk%22Y)P{M!dA|U?$3;H4c{!1F}+v*?H C_Sq5u delta 145 zcmZp1XfcprU|?W$DortDU=RQ@Ie-{MGpJ516gFlAGME{1844JTQ;L&wlJfI&KyqNf z1f@Z0fLMS5BEPY48vDcs;l=D69D>XcB?8<)+7*aZHx_<pp3E<!$jCU^R7RTzXavYU NkP{d-$Mei#1^@wM6_o%0 diff --git a/README.md b/README.md index 0a635c5..7b2b2e7 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,4 @@ 1. Source code in `./screens`. 2. Navigators in `./navigation`. 3. Citations: Expo initiate doc. - +4. Username and Password for my github is required; diff --git a/mp3/.DS_Store b/mp3/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..88bed5d2a6d5d839c7961075035f66a5e2242460 GIT binary patch literal 6148 zcmeHKyH3ME5S)b+k)TLPdB4CPoTBgrd;kcXF5n_c?~3orr!o5w!g7#kXwa;*J9q1y zJ9!GP7l3U~!#%J8u%<iW!^6`2x%<MdDq}=C&v?QcMhrONu&BPAaPBSMgSDUW_c#v6 z*Tc&={`RcPHz+Fwq<|EV0#ZN<d{@AGFKvC3s3--bfE4&rz`qZT?$`^b#Q1bD#0WrK zF&)Nr%o4=r31Tmt5}Bb{Qi(~m8Zj*C%(trRg;QeEVKsbM-E1|XSlrI@Ta?3kqM{U# z0&@kfbGz~W|3Lp?{-2YylLAuUUnyX#-Q#Y{SE}B+cscL2js8scnls&v>!2`1J0?au h=EmFcT@+<q^EIFM!YMK6%m<yQp8?lJCI$XlflrXF7HR+h literal 0 HcmV?d00001 diff --git a/mp3/__tests__/Screen-test.js b/mp3/__tests__/Screen-test.js new file mode 100644 index 0000000..4241984 --- /dev/null +++ b/mp3/__tests__/Screen-test.js @@ -0,0 +1,87 @@ +import 'react-native'; +import React from 'react'; +import renderer from 'react-test-renderer'; +import NavigationTestUtils from 'react-navigation/NavigationTestUtils'; +import { AsyncStorage } from 'react-native'; +import ProfileScreen from '../screens/Profile/ProfileScreen'; +import RepoScreen from '../screens/RepoScreen'; +import FollowerScreen from '../screens/FollowerScreen'; +import FollowingScreen from '../screens/FollowingScreen'; + +// Test case will run a new empty AsyncStorage, thus can prove that +// every first time, the app communicates with API. +test('My profile storage is working', async () => { + const data = await AsyncStorage.getItem('cs242HW'); + expect(data).toBe(null); +}); + +test('My repo storage is working', async () => { + const data = await AsyncStorage.getItem('cs242HWRepos'); + expect(data).toBe(null); +}); + +test('My follower storage is working', async () => { + const data = await AsyncStorage.getItem('cs242HWFollowers'); + expect(data).toBe(null); +}); + +test('My following storage is working', async () => { + const data = await AsyncStorage.getItem('cs242HWFollowing'); + expect(data).toBe(null); +}); + +test('Profile renders correctly', () => { + const tree = renderer.create(<ProfileScreen />).toJSON(); + expect(tree).toMatchSnapshot(); +}); + +test('Get number of repo correctly', async () => { + let profile = renderer.create(<ProfileScreen />).getInstance(); + profile._retrieveData('cs242HW'); + expect(profile.state.data.repo).not.toBe(null); +}); + +test('Get number of followers correctly', async () => { + let profile = renderer.create(<ProfileScreen />).getInstance(); + profile._retrieveData('cs242HW'); + expect(profile.state.data.followers).not.toBe(null); +}); + +test('Get number of following correctly', async () => { + let profile = renderer.create(<ProfileScreen />).getInstance(); + profile._retrieveData('cs242HW'); + expect(profile.state.data.following).not.toBe(null); +}); + +test('Profile refresh works correctly', async () => { + let profile = renderer.create(<ProfileScreen />).getInstance(); + profile._handleRefresh(); + expect(profile.state.data).not.toBe(null); +}); + +test('Repo renders correctly', () => { + const tree = renderer.create(<RepoScreen />).toJSON(); + expect(tree).toMatchSnapshot(); +}); + +test('Follower renders correctly', () => { + const tree = renderer.create(<FollowerScreen />).toJSON(); + expect(tree).toMatchSnapshot(); +}); + +test('Followers refresh works correctly', async () => { + let followers = renderer.create(<FollowerScreen />).getInstance(); + followers._handlePress(); + expect(followers.state.data).not.toBe(null); +}); + +test('Following renders correctly', () => { + const tree = renderer.create(<FollowingScreen />).toJSON(); + expect(tree).toMatchSnapshot(); +}); + +test('Following refresh works correctly', async () => { + let following = renderer.create(<FollowingScreen />).getInstance(); + following._handlePress(); + expect(following.state.data).not.toBe(null); +}); diff --git a/mp3/__tests__/__snapshots__/App-test.js.snap b/mp3/__tests__/__snapshots__/App-test.js.snap new file mode 100644 index 0000000..30f89a2 --- /dev/null +++ b/mp3/__tests__/__snapshots__/App-test.js.snap @@ -0,0 +1,796 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`App snapshot renders the loading screen 1`] = `null`; + +exports[`App snapshot renders the root without loading screen 1`] = ` +<View + style={ + Object { + "backgroundColor": "#fff", + "flex": 1, + } + } +> + <View + style={ + Object { + "flex": 1, + "overflow": "hidden", + } + } + > + <View + style={ + Object { + "flex": 1, + } + } + > + <View + collapsable={false} + pointerEvents="auto" + removeClippedSubviews={false} + style={ + Array [ + Object { + "flex": 1, + "overflow": "hidden", + }, + Array [ + Object { + "bottom": 0, + "left": 0, + "position": "absolute", + "right": 0, + "top": 0, + }, + Object { + "opacity": 1, + }, + ], + ] + } + > + <View + style={ + Object { + "flex": 1, + } + } + > + <View + onLayout={[Function]} + style={ + Object { + "flex": 1, + } + } + > + <View + onMoveShouldSetResponder={[Function]} + onMoveShouldSetResponderCapture={[Function]} + onResponderEnd={[Function]} + onResponderGrant={[Function]} + onResponderMove={[Function]} + onResponderReject={[Function]} + onResponderRelease={[Function]} + onResponderStart={[Function]} + onResponderTerminate={[Function]} + onResponderTerminationRequest={[Function]} + onStartShouldSetResponder={[Function]} + onStartShouldSetResponderCapture={[Function]} + style={ + Array [ + Object { + "flex": 1, + "flexDirection": "column-reverse", + "overflow": "hidden", + }, + Object { + "backgroundColor": "#000", + }, + ] + } + > + <View + style={ + Object { + "flex": 1, + } + } + > + <View + accessibilityElementsHidden={false} + pointerEvents="auto" + style={ + Object { + "backgroundColor": "#E9E9EF", + "bottom": 0, + "left": 0, + "opacity": 1, + "paddingTop": 64, + "position": "absolute", + "right": 0, + "shadowColor": "black", + "shadowOffset": Object { + "height": 0, + "width": 0, + }, + "shadowOpacity": 0.2, + "shadowRadius": 5, + "top": 0, + "transform": Array [ + Object { + "translateX": 0, + }, + Object { + "translateY": 0, + }, + ], + } + } + /> + </View> + <View + onLayout={[Function]} + pointerEvents="box-none" + style={ + Object { + "left": 0, + "position": "absolute", + "right": 0, + "top": 0, + } + } + > + <View + style={ + Object { + "backgroundColor": "#FFF", + "transform": Array [ + Object { + "translateX": 0, + }, + ], + } + } + > + <View + onLayout={[Function]} + pointerEvents="box-none" + style={ + Object { + "backgroundColor": "#FFF", + "borderBottomColor": "#A7A7AA", + "borderBottomWidth": 0.5, + "height": 64, + "paddingBottom": 0, + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 20, + } + } + > + <View + style={ + Object { + "flex": 1, + } + } + > + <View + style={ + Object { + "bottom": 0, + "flexDirection": "row", + "left": 0, + "position": "absolute", + "right": 0, + "top": 0, + } + } + > + <View + pointerEvents="box-none" + style={ + Object { + "alignItems": "center", + "backgroundColor": "transparent", + "bottom": 0, + "flexDirection": "row", + "justifyContent": "center", + "left": 0, + "opacity": 1, + "position": "absolute", + "right": 0, + "top": 0, + } + } + > + <Text + accessibilityTraits="header" + accessible={false} + allowFontScaling={true} + ellipsizeMode="tail" + numberOfLines={1} + onLayout={[Function]} + style={ + Object { + "color": "rgba(0, 0, 0, .9)", + "fontSize": 17, + "fontWeight": "600", + "marginHorizontal": 16, + "textAlign": "center", + } + } + > + Profile + </Text> + </View> + </View> + </View> + </View> + </View> + </View> + </View> + </View> + </View> + </View> + </View> + <View + onLayout={[Function]} + pointerEvents="box-none" + style={ + Object { + "backgroundColor": "#fff", + "borderTopColor": "rgba(0, 0, 0, .3)", + "borderTopWidth": 0.5, + "flexDirection": "row", + "height": 49, + "paddingBottom": 0, + "paddingLeft": 0, + "paddingRight": 0, + "paddingTop": 0, + } + } + > + <View + accessibilityLabel="Profile" + accessible={true} + onResponderGrant={[Function]} + onResponderMove={[Function]} + onResponderRelease={[Function]} + onResponderTerminate={[Function]} + onResponderTerminationRequest={[Function]} + onStartShouldSetResponder={[Function]} + style={ + Array [ + Object { + "alignItems": "center", + "flex": 1, + }, + Object { + "backgroundColor": "transparent", + }, + Object { + "flexDirection": "column", + "justifyContent": "flex-end", + }, + undefined, + ] + } + > + <View + style={ + Array [ + Object { + "height": 29, + }, + false, + Object { + "flex": 1, + }, + ] + } + > + <View + style={ + Object { + "alignItems": "center", + "alignSelf": "center", + "height": "100%", + "justifyContent": "center", + "minWidth": 25, + "opacity": 1, + "position": "absolute", + "width": "100%", + } + } + > + <Text + accessible={true} + allowFontScaling={false} + ellipsizeMode="tail" + style={ + Array [ + Object { + "color": "#2f95dc", + "fontSize": 26, + }, + Object { + "marginBottom": -3, + }, + Object { + "fontFamily": "ionicons", + "fontStyle": "normal", + "fontWeight": "normal", + }, + ] + } + > + ï† + </Text> + </View> + <View + style={ + Object { + "alignItems": "center", + "alignSelf": "center", + "height": "100%", + "justifyContent": "center", + "minWidth": 25, + "opacity": 0, + "position": "absolute", + "width": "100%", + } + } + > + <Text + accessible={true} + allowFontScaling={false} + ellipsizeMode="tail" + style={ + Array [ + Object { + "color": "#ccc", + "fontSize": 26, + }, + Object { + "marginBottom": -3, + }, + Object { + "fontFamily": "ionicons", + "fontStyle": "normal", + "fontWeight": "normal", + }, + ] + } + > +  + </Text> + </View> + </View> + <Text + accessible={true} + allowFontScaling={true} + ellipsizeMode="tail" + numberOfLines={1} + style={ + Object { + "backgroundColor": "transparent", + "color": "#3478f6", + "fontSize": 11, + "marginBottom": 1.5, + "textAlign": "center", + } + } + > + Profile + </Text> + </View> + <View + accessibilityLabel="Repo" + accessible={true} + onResponderGrant={[Function]} + onResponderMove={[Function]} + onResponderRelease={[Function]} + onResponderTerminate={[Function]} + onResponderTerminationRequest={[Function]} + onStartShouldSetResponder={[Function]} + style={ + Array [ + Object { + "alignItems": "center", + "flex": 1, + }, + Object { + "backgroundColor": "transparent", + }, + Object { + "flexDirection": "column", + "justifyContent": "flex-end", + }, + undefined, + ] + } + > + <View + style={ + Array [ + Object { + "height": 29, + }, + false, + Object { + "flex": 1, + }, + ] + } + > + <View + style={ + Object { + "alignItems": "center", + "alignSelf": "center", + "height": "100%", + "justifyContent": "center", + "minWidth": 25, + "opacity": 0, + "position": "absolute", + "width": "100%", + } + } + > + <Text + accessible={true} + allowFontScaling={false} + ellipsizeMode="tail" + style={ + Array [ + Object { + "color": "#2f95dc", + "fontSize": 26, + }, + Object { + "marginBottom": -3, + }, + Object { + "fontFamily": "ionicons", + "fontStyle": "normal", + "fontWeight": "normal", + }, + ] + } + > +  + </Text> + </View> + <View + style={ + Object { + "alignItems": "center", + "alignSelf": "center", + "height": "100%", + "justifyContent": "center", + "minWidth": 25, + "opacity": 1, + "position": "absolute", + "width": "100%", + } + } + > + <Text + accessible={true} + allowFontScaling={false} + ellipsizeMode="tail" + style={ + Array [ + Object { + "color": "#ccc", + "fontSize": 26, + }, + Object { + "marginBottom": -3, + }, + Object { + "fontFamily": "ionicons", + "fontStyle": "normal", + "fontWeight": "normal", + }, + ] + } + > +  + </Text> + </View> + </View> + <Text + accessible={true} + allowFontScaling={true} + ellipsizeMode="tail" + numberOfLines={1} + style={ + Object { + "backgroundColor": "transparent", + "color": "#929292", + "fontSize": 11, + "marginBottom": 1.5, + "textAlign": "center", + } + } + > + Repo + </Text> + </View> + <View + accessibilityLabel="Follower" + accessible={true} + onResponderGrant={[Function]} + onResponderMove={[Function]} + onResponderRelease={[Function]} + onResponderTerminate={[Function]} + onResponderTerminationRequest={[Function]} + onStartShouldSetResponder={[Function]} + style={ + Array [ + Object { + "alignItems": "center", + "flex": 1, + }, + Object { + "backgroundColor": "transparent", + }, + Object { + "flexDirection": "column", + "justifyContent": "flex-end", + }, + undefined, + ] + } + > + <View + style={ + Array [ + Object { + "height": 29, + }, + false, + Object { + "flex": 1, + }, + ] + } + > + <View + style={ + Object { + "alignItems": "center", + "alignSelf": "center", + "height": "100%", + "justifyContent": "center", + "minWidth": 25, + "opacity": 0, + "position": "absolute", + "width": "100%", + } + } + > + <Text + accessible={true} + allowFontScaling={false} + ellipsizeMode="tail" + style={ + Array [ + Object { + "color": "#2f95dc", + "fontSize": 26, + }, + Object { + "marginBottom": -3, + }, + Object { + "fontFamily": "ionicons", + "fontStyle": "normal", + "fontWeight": "normal", + }, + ] + } + > +  + </Text> + </View> + <View + style={ + Object { + "alignItems": "center", + "alignSelf": "center", + "height": "100%", + "justifyContent": "center", + "minWidth": 25, + "opacity": 1, + "position": "absolute", + "width": "100%", + } + } + > + <Text + accessible={true} + allowFontScaling={false} + ellipsizeMode="tail" + style={ + Array [ + Object { + "color": "#ccc", + "fontSize": 26, + }, + Object { + "marginBottom": -3, + }, + Object { + "fontFamily": "ionicons", + "fontStyle": "normal", + "fontWeight": "normal", + }, + ] + } + > +  + </Text> + </View> + </View> + <Text + accessible={true} + allowFontScaling={true} + ellipsizeMode="tail" + numberOfLines={1} + style={ + Object { + "backgroundColor": "transparent", + "color": "#929292", + "fontSize": 11, + "marginBottom": 1.5, + "textAlign": "center", + } + } + > + Follower + </Text> + </View> + <View + accessibilityLabel="Following" + accessible={true} + onResponderGrant={[Function]} + onResponderMove={[Function]} + onResponderRelease={[Function]} + onResponderTerminate={[Function]} + onResponderTerminationRequest={[Function]} + onStartShouldSetResponder={[Function]} + style={ + Array [ + Object { + "alignItems": "center", + "flex": 1, + }, + Object { + "backgroundColor": "transparent", + }, + Object { + "flexDirection": "column", + "justifyContent": "flex-end", + }, + undefined, + ] + } + > + <View + style={ + Array [ + Object { + "height": 29, + }, + false, + Object { + "flex": 1, + }, + ] + } + > + <View + style={ + Object { + "alignItems": "center", + "alignSelf": "center", + "height": "100%", + "justifyContent": "center", + "minWidth": 25, + "opacity": 0, + "position": "absolute", + "width": "100%", + } + } + > + <Text + accessible={true} + allowFontScaling={false} + ellipsizeMode="tail" + style={ + Array [ + Object { + "color": "#2f95dc", + "fontSize": 26, + }, + Object { + "marginBottom": -3, + }, + Object { + "fontFamily": "ionicons", + "fontStyle": "normal", + "fontWeight": "normal", + }, + ] + } + > + ï’³ + </Text> + </View> + <View + style={ + Object { + "alignItems": "center", + "alignSelf": "center", + "height": "100%", + "justifyContent": "center", + "minWidth": 25, + "opacity": 1, + "position": "absolute", + "width": "100%", + } + } + > + <Text + accessible={true} + allowFontScaling={false} + ellipsizeMode="tail" + style={ + Array [ + Object { + "color": "#ccc", + "fontSize": 26, + }, + Object { + "marginBottom": -3, + }, + Object { + "fontFamily": "ionicons", + "fontStyle": "normal", + "fontWeight": "normal", + }, + ] + } + > + ï’² + </Text> + </View> + </View> + <Text + accessible={true} + allowFontScaling={true} + ellipsizeMode="tail" + numberOfLines={1} + style={ + Object { + "backgroundColor": "transparent", + "color": "#929292", + "fontSize": 11, + "marginBottom": 1.5, + "textAlign": "center", + } + } + > + Following + </Text> + </View> + </View> + </View> +</View> +`; diff --git a/mp3/__tests__/__snapshots__/Screen-test.js.snap b/mp3/__tests__/__snapshots__/Screen-test.js.snap new file mode 100644 index 0000000..adc9bd5 --- /dev/null +++ b/mp3/__tests__/__snapshots__/Screen-test.js.snap @@ -0,0 +1,265 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Follower renders correctly 1`] = ` +<View> + <View + style={ + Array [ + Object { + "backgroundColor": "#ffffff", + "borderColor": "#bbb", + "borderTopWidth": 1, + "marginTop": 20, + }, + Object { + "borderBottomWidth": 0, + "borderTopWidth": 0, + "marginTop": 0, + }, + ] + } + /> + <View + style={ + Array [ + Object { + "marginLeft": 15, + "marginRight": 15, + }, + undefined, + undefined, + undefined, + ] + } + > + <View + accessible={true} + isTVSelectable={true} + onResponderGrant={[Function]} + onResponderMove={[Function]} + onResponderRelease={[Function]} + onResponderTerminate={[Function]} + onResponderTerminationRequest={[Function]} + onStartShouldSetResponder={[Function]} + style={null} + > + <View + pointerEvents="box-only" + style={ + Array [ + Object { + "alignItems": "center", + "backgroundColor": "#9E9E9E", + "flexDirection": "row", + "justifyContent": "center", + "padding": 19, + }, + undefined, + undefined, + undefined, + undefined, + undefined, + Object { + "backgroundColor": "#AF7AC5", + }, + undefined, + Object { + "padding": 12, + }, + undefined, + undefined, + undefined, + Object { + "alignSelf": "center", + "marginTop": "2%", + "width": "50%", + }, + undefined, + undefined, + ] + } + > + <Text + accessible={true} + allowFontScaling={true} + ellipsizeMode="tail" + style={ + Array [ + Object {}, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + Array [ + Object { + "color": "white", + "fontSize": 20, + }, + undefined, + Object { + "fontSize": 17.5, + }, + undefined, + undefined, + undefined, + undefined, + undefined, + ], + ] + } + > + REFRESH + </Text> + </View> + </View> + </View> +</View> +`; + +exports[`Following renders correctly 1`] = ` +<View> + <View + style={ + Array [ + Object { + "backgroundColor": "#ffffff", + "borderColor": "#bbb", + "borderTopWidth": 1, + "marginTop": 20, + }, + Object { + "borderBottomWidth": 0, + "borderTopWidth": 0, + "marginTop": 0, + }, + ] + } + /> + <View + style={ + Array [ + Object { + "marginLeft": 15, + "marginRight": 15, + }, + undefined, + undefined, + undefined, + ] + } + > + <View + accessible={true} + isTVSelectable={true} + onResponderGrant={[Function]} + onResponderMove={[Function]} + onResponderRelease={[Function]} + onResponderTerminate={[Function]} + onResponderTerminationRequest={[Function]} + onStartShouldSetResponder={[Function]} + style={null} + > + <View + pointerEvents="box-only" + style={ + Array [ + Object { + "alignItems": "center", + "backgroundColor": "#9E9E9E", + "flexDirection": "row", + "justifyContent": "center", + "padding": 19, + }, + undefined, + undefined, + undefined, + undefined, + undefined, + Object { + "backgroundColor": "#AF7AC5", + }, + undefined, + Object { + "padding": 12, + }, + undefined, + undefined, + undefined, + Object { + "alignSelf": "center", + "marginTop": "2%", + "width": "50%", + }, + undefined, + undefined, + ] + } + > + <Text + accessible={true} + allowFontScaling={true} + ellipsizeMode="tail" + style={ + Array [ + Object {}, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + Array [ + Object { + "color": "white", + "fontSize": 20, + }, + undefined, + Object { + "fontSize": 17.5, + }, + undefined, + undefined, + undefined, + undefined, + undefined, + ], + ] + } + > + REFRESH + </Text> + </View> + </View> + </View> +</View> +`; + +exports[`Profile renders correctly 1`] = `null`; + +exports[`Repo renders correctly 1`] = ` +<View + style={ + Array [ + Object { + "backgroundColor": "#ffffff", + "borderColor": "#bbb", + "borderTopWidth": 1, + "marginTop": 20, + }, + Object { + "borderBottomWidth": 0, + "borderTopWidth": 0, + "marginTop": 0, + }, + ] + } +/> +`; diff --git a/mp3/components/__tests__/__snapshots__/StyledText-test.js.snap b/mp3/components/__tests__/__snapshots__/StyledText-test.js.snap new file mode 100644 index 0000000..32610a0 --- /dev/null +++ b/mp3/components/__tests__/__snapshots__/StyledText-test.js.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +<Text + accessible={true} + allowFontScaling={true} + ellipsizeMode="tail" + style={ + Array [ + undefined, + Object { + "fontFamily": "space-mono", + }, + ] + } +> + Snapshot test! +</Text> +`; diff --git a/mp3/navigation/MainTabNavigator.js b/mp3/navigation/MainTabNavigator.js index a34811b..39a96ae 100644 --- a/mp3/navigation/MainTabNavigator.js +++ b/mp3/navigation/MainTabNavigator.js @@ -64,7 +64,7 @@ FollowingStack.navigationOptions = { tabBarIcon: ({ focused }) => ( <TabBarIcon focused={focused} - name={Platform.OS === 'ios' ? `ios-options${focused ? '' : '-outline'}` : 'md-options'} + name={Platform.OS === 'ios' ? `ios-star${focused ? '' : '-outline'}` : 'md-options'} /> ), }; diff --git a/mp3/package-lock.json b/mp3/package-lock.json index 685fdc0..87c9307 100644 --- a/mp3/package-lock.json +++ b/mp3/package-lock.json @@ -1452,13 +1452,13 @@ } }, "babel-jest": { - "version": "22.4.4", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-22.4.4.tgz", - "integrity": "sha512-A9NB6/lZhYyypR9ATryOSDcqBaqNdzq4U+CN+/wcMsLcmKkPxQEoTKLajGfd3IkxNyVBT8NewUK2nWyGbSzHEQ==", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-23.6.0.tgz", + "integrity": "sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew==", "dev": true, "requires": { "babel-plugin-istanbul": "4.1.6", - "babel-preset-jest": "22.4.4" + "babel-preset-jest": "23.2.0" } }, "babel-messages": { @@ -1498,9 +1498,9 @@ } }, "babel-plugin-jest-hoist": { - "version": "22.4.4", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.4.tgz", - "integrity": "sha512-DUvGfYaAIlkdnygVIEl0O4Av69NtuQWcrjMOv6DODPuhuGLDnbsARz3AwiiI/EkIMMlxQDUcrZ9yoyJvTNjcVQ==", + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz", + "integrity": "sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc=", "dev": true }, "babel-plugin-module-resolver": { @@ -1953,12 +1953,12 @@ } }, "babel-preset-jest": { - "version": "22.4.4", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-22.4.4.tgz", - "integrity": "sha512-+dxMtOFwnSYWfum0NaEc0O03oSdwBsjx4tMSChRDPGwu/4wSY6Q6ANW3wkjKpJzzguaovRs/DODcT4hbSN8yiA==", + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz", + "integrity": "sha1-jsegOhOPABoaj7HoETZSvxpV2kY=", "dev": true, "requires": { - "babel-plugin-jest-hoist": "22.4.4", + "babel-plugin-jest-hoist": "23.2.0", "babel-plugin-syntax-object-rest-spread": "6.13.0" } }, @@ -4916,6 +4916,509 @@ "handlebars": "4.0.12" } }, + "jest": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-23.6.0.tgz", + "integrity": "sha512-lWzcd+HSiqeuxyhG+EnZds6iO3Y3ZEnMrfZq/OTGvF/C+Z4fPMCdhWTGSAiO2Oym9rbEXfwddHhh6jqrTF3+Lw==", + "dev": true, + "requires": { + "import-local": "1.0.0", + "jest-cli": "23.6.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.3" + } + }, + "babel-jest": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-23.6.0.tgz", + "integrity": "sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew==", + "dev": true, + "requires": { + "babel-plugin-istanbul": "4.1.6", + "babel-preset-jest": "23.2.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz", + "integrity": "sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc=", + "dev": true + }, + "babel-preset-jest": { + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz", + "integrity": "sha1-jsegOhOPABoaj7HoETZSvxpV2kY=", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "23.2.0", + "babel-plugin-syntax-object-rest-spread": "6.13.0" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" + } + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" + } + }, + "expect": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-23.6.0.tgz", + "integrity": "sha512-dgSoOHgmtn/aDGRVFWclQyPDKl2CQRq0hmIEoUAuQs/2rn2NcvCWcSCovm6BLeuB/7EZuLGu2QfnR+qRt5OM4w==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "jest-diff": "23.6.0", + "jest-get-type": "22.4.3", + "jest-matcher-utils": "23.6.0", + "jest-message-util": "23.4.0", + "jest-regex-util": "23.3.0" + } + }, + "jest-changed-files": { + "version": "23.4.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-23.4.2.tgz", + "integrity": "sha512-EyNhTAUWEfwnK0Is/09LxoqNDOn7mU7S3EHskG52djOFS/z+IT0jT3h3Ql61+dklcG7bJJitIWEMB4Sp1piHmA==", + "dev": true, + "requires": { + "throat": "4.1.0" + } + }, + "jest-cli": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-23.6.0.tgz", + "integrity": "sha512-hgeD1zRUp1E1zsiyOXjEn4LzRLWdJBV//ukAHGlx6s5mfCNJTbhbHjgxnDUXA8fsKWN/HqFFF6X5XcCwC/IvYQ==", + "dev": true, + "requires": { + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "exit": "0.1.2", + "glob": "7.1.3", + "graceful-fs": "4.1.11", + "import-local": "1.0.0", + "is-ci": "1.2.1", + "istanbul-api": "1.3.7", + "istanbul-lib-coverage": "1.2.1", + "istanbul-lib-instrument": "1.10.2", + "istanbul-lib-source-maps": "1.2.6", + "jest-changed-files": "23.4.2", + "jest-config": "23.6.0", + "jest-environment-jsdom": "23.4.0", + "jest-get-type": "22.4.3", + "jest-haste-map": "23.6.0", + "jest-message-util": "23.4.0", + "jest-regex-util": "23.3.0", + "jest-resolve-dependencies": "23.6.0", + "jest-runner": "23.6.0", + "jest-runtime": "23.6.0", + "jest-snapshot": "23.6.0", + "jest-util": "23.4.0", + "jest-validate": "23.6.0", + "jest-watcher": "23.4.0", + "jest-worker": "23.2.0", + "micromatch": "2.3.11", + "node-notifier": "5.3.0", + "prompts": "0.1.14", + "realpath-native": "1.0.2", + "rimraf": "2.6.2", + "slash": "1.0.0", + "string-length": "2.0.0", + "strip-ansi": "4.0.0", + "which": "1.3.1", + "yargs": "11.1.0" + } + }, + "jest-config": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-23.6.0.tgz", + "integrity": "sha512-i8V7z9BeDXab1+VNo78WM0AtWpBRXJLnkT+lyT+Slx/cbP5sZJ0+NDuLcmBE5hXAoK0aUp7vI+MOxR+R4d8SRQ==", + "dev": true, + "requires": { + "babel-core": "6.26.3", + "babel-jest": "23.6.0", + "chalk": "2.4.1", + "glob": "7.1.3", + "jest-environment-jsdom": "23.4.0", + "jest-environment-node": "23.4.0", + "jest-get-type": "22.4.3", + "jest-jasmine2": "23.6.0", + "jest-regex-util": "23.3.0", + "jest-resolve": "23.6.0", + "jest-util": "23.4.0", + "jest-validate": "23.6.0", + "micromatch": "2.3.11", + "pretty-format": "23.6.0" + } + }, + "jest-diff": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-23.6.0.tgz", + "integrity": "sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g==", + "dev": true, + "requires": { + "chalk": "2.4.1", + "diff": "3.5.0", + "jest-get-type": "22.4.3", + "pretty-format": "23.6.0" + } + }, + "jest-docblock": { + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-23.2.0.tgz", + "integrity": "sha1-8IXh8YVI2Z/dabICB+b9VdkTg6c=", + "dev": true, + "requires": { + "detect-newline": "2.1.0" + } + }, + "jest-environment-jsdom": { + "version": "23.4.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-23.4.0.tgz", + "integrity": "sha1-BWp5UrP+pROsYqFAosNox52eYCM=", + "dev": true, + "requires": { + "jest-mock": "23.2.0", + "jest-util": "23.4.0", + "jsdom": "11.12.0" + } + }, + "jest-environment-node": { + "version": "23.4.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-23.4.0.tgz", + "integrity": "sha1-V+gO0IQd6jAxZ8zozXlSHeuv3hA=", + "dev": true, + "requires": { + "jest-mock": "23.2.0", + "jest-util": "23.4.0" + } + }, + "jest-haste-map": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-23.6.0.tgz", + "integrity": "sha512-uyNhMyl6dr6HaXGHp8VF7cK6KpC6G9z9LiMNsst+rJIZ8l7wY0tk8qwjPmEghczojZ2/ZhtEdIabZ0OQRJSGGg==", + "dev": true, + "requires": { + "fb-watchman": "2.0.0", + "graceful-fs": "4.1.11", + "invariant": "2.2.4", + "jest-docblock": "23.2.0", + "jest-serializer": "23.0.1", + "jest-worker": "23.2.0", + "micromatch": "2.3.11", + "sane": "2.5.2" + } + }, + "jest-jasmine2": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-23.6.0.tgz", + "integrity": "sha512-pe2Ytgs1nyCs8IvsEJRiRTPC0eVYd8L/dXJGU08GFuBwZ4sYH/lmFDdOL3ZmvJR8QKqV9MFuwlsAi/EWkFUbsQ==", + "dev": true, + "requires": { + "babel-traverse": "6.26.0", + "chalk": "2.4.1", + "co": "4.6.0", + "expect": "23.6.0", + "is-generator-fn": "1.0.0", + "jest-diff": "23.6.0", + "jest-each": "23.6.0", + "jest-matcher-utils": "23.6.0", + "jest-message-util": "23.4.0", + "jest-snapshot": "23.6.0", + "jest-util": "23.4.0", + "pretty-format": "23.6.0" + } + }, + "jest-leak-detector": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-23.6.0.tgz", + "integrity": "sha512-f/8zA04rsl1Nzj10HIyEsXvYlMpMPcy0QkQilVZDFOaPbv2ur71X5u2+C4ZQJGyV/xvVXtCCZ3wQ99IgQxftCg==", + "dev": true, + "requires": { + "pretty-format": "23.6.0" + } + }, + "jest-matcher-utils": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-23.6.0.tgz", + "integrity": "sha512-rosyCHQfBcol4NsckTn01cdelzWLU9Cq7aaigDf8VwwpIRvWE/9zLgX2bON+FkEW69/0UuYslUe22SOdEf2nog==", + "dev": true, + "requires": { + "chalk": "2.4.1", + "jest-get-type": "22.4.3", + "pretty-format": "23.6.0" + } + }, + "jest-message-util": { + "version": "23.4.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-23.4.0.tgz", + "integrity": "sha1-F2EMUJQjSVCNAaPR4L2iwHkIap8=", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0", + "chalk": "2.4.1", + "micromatch": "2.3.11", + "slash": "1.0.0", + "stack-utils": "1.0.1" + } + }, + "jest-mock": { + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-23.2.0.tgz", + "integrity": "sha1-rRxg8p6HGdR8JuETgJi20YsmETQ=", + "dev": true + }, + "jest-regex-util": { + "version": "23.3.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-23.3.0.tgz", + "integrity": "sha1-X4ZylUfCeFxAAs6qj4Sf6MpHG8U=", + "dev": true + }, + "jest-resolve": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-23.6.0.tgz", + "integrity": "sha512-XyoRxNtO7YGpQDmtQCmZjum1MljDqUCob7XlZ6jy9gsMugHdN2hY4+Acz9Qvjz2mSsOnPSH7skBmDYCHXVZqkA==", + "dev": true, + "requires": { + "browser-resolve": "1.11.3", + "chalk": "2.4.1", + "realpath-native": "1.0.2" + } + }, + "jest-resolve-dependencies": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-23.6.0.tgz", + "integrity": "sha512-EkQWkFWjGKwRtRyIwRwI6rtPAEyPWlUC2MpzHissYnzJeHcyCn1Hc8j7Nn1xUVrS5C6W5+ZL37XTem4D4pLZdA==", + "dev": true, + "requires": { + "jest-regex-util": "23.3.0", + "jest-snapshot": "23.6.0" + } + }, + "jest-runner": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-23.6.0.tgz", + "integrity": "sha512-kw0+uj710dzSJKU6ygri851CObtCD9cN8aNkg8jWJf4ewFyEa6kwmiH/r/M1Ec5IL/6VFa0wnAk6w+gzUtjJzA==", + "dev": true, + "requires": { + "exit": "0.1.2", + "graceful-fs": "4.1.11", + "jest-config": "23.6.0", + "jest-docblock": "23.2.0", + "jest-haste-map": "23.6.0", + "jest-jasmine2": "23.6.0", + "jest-leak-detector": "23.6.0", + "jest-message-util": "23.4.0", + "jest-runtime": "23.6.0", + "jest-util": "23.4.0", + "jest-worker": "23.2.0", + "source-map-support": "0.5.9", + "throat": "4.1.0" + } + }, + "jest-runtime": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-23.6.0.tgz", + "integrity": "sha512-ycnLTNPT2Gv+TRhnAYAQ0B3SryEXhhRj1kA6hBPSeZaNQkJ7GbZsxOLUkwg6YmvWGdX3BB3PYKFLDQCAE1zNOw==", + "dev": true, + "requires": { + "babel-core": "6.26.3", + "babel-plugin-istanbul": "4.1.6", + "chalk": "2.4.1", + "convert-source-map": "1.6.0", + "exit": "0.1.2", + "fast-json-stable-stringify": "2.0.0", + "graceful-fs": "4.1.11", + "jest-config": "23.6.0", + "jest-haste-map": "23.6.0", + "jest-message-util": "23.4.0", + "jest-regex-util": "23.3.0", + "jest-resolve": "23.6.0", + "jest-snapshot": "23.6.0", + "jest-util": "23.4.0", + "jest-validate": "23.6.0", + "micromatch": "2.3.11", + "realpath-native": "1.0.2", + "slash": "1.0.0", + "strip-bom": "3.0.0", + "write-file-atomic": "2.3.0", + "yargs": "11.1.0" + } + }, + "jest-serializer": { + "version": "23.0.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-23.0.1.tgz", + "integrity": "sha1-o3dq6zEekP6D+rnlM+hRAr0WQWU=", + "dev": true + }, + "jest-snapshot": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-23.6.0.tgz", + "integrity": "sha512-tM7/Bprftun6Cvj2Awh/ikS7zV3pVwjRYU2qNYS51VZHgaAMBs5l4o/69AiDHhQrj5+LA2Lq4VIvK7zYk/bswg==", + "dev": true, + "requires": { + "babel-types": "6.26.0", + "chalk": "2.4.1", + "jest-diff": "23.6.0", + "jest-matcher-utils": "23.6.0", + "jest-message-util": "23.4.0", + "jest-resolve": "23.6.0", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "pretty-format": "23.6.0", + "semver": "5.6.0" + } + }, + "jest-util": { + "version": "23.4.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-23.4.0.tgz", + "integrity": "sha1-TQY8uSe68KI4Mf9hvsLLv0l5NWE=", + "dev": true, + "requires": { + "callsites": "2.0.0", + "chalk": "2.4.1", + "graceful-fs": "4.1.11", + "is-ci": "1.2.1", + "jest-message-util": "23.4.0", + "mkdirp": "0.5.1", + "slash": "1.0.0", + "source-map": "0.6.1" + } + }, + "jest-validate": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-23.6.0.tgz", + "integrity": "sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A==", + "dev": true, + "requires": { + "chalk": "2.4.1", + "jest-get-type": "22.4.3", + "leven": "2.1.0", + "pretty-format": "23.6.0" + } + }, + "jest-worker": { + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-23.2.0.tgz", + "integrity": "sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk=", + "dev": true, + "requires": { + "merge-stream": "1.0.1" + } + }, + "pretty-format": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", + "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", + "dev": true, + "requires": { + "ansi-regex": "3.0.0", + "ansi-styles": "3.2.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", + "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", + "dev": true, + "requires": { + "buffer-from": "1.1.1", + "source-map": "0.6.1" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + }, + "write-file-atomic": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", + "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "signal-exit": "3.0.2" + } + }, + "yargs": { + "version": "11.1.0", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", + "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", + "dev": true, + "requires": { + "cliui": "4.1.0", + "decamelize": "1.2.0", + "find-up": "2.1.0", + "get-caller-file": "1.0.3", + "os-locale": "2.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "9.0.2" + } + }, + "yargs-parser": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", + "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "dev": true, + "requires": { + "camelcase": "4.1.0" + } + } + } + }, "jest-changed-files": { "version": "22.4.3", "resolved": "http://registry.npmjs.org/jest-changed-files/-/jest-changed-files-22.4.3.tgz", @@ -5058,6 +5561,63 @@ "detect-newline": "2.1.0" } }, + "jest-each": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-23.6.0.tgz", + "integrity": "sha512-x7V6M/WGJo6/kLoissORuvLIeAoyo2YqLOoCDkohgJ4XOXSqOtyvr8FbInlAWS77ojBsZrafbozWoKVRdtxFCg==", + "dev": true, + "requires": { + "chalk": "2.4.1", + "pretty-format": "23.6.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.3" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" + } + }, + "pretty-format": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", + "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", + "dev": true, + "requires": { + "ansi-regex": "3.0.0", + "ansi-styles": "3.2.1" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, "jest-environment-jsdom": { "version": "22.4.3", "resolved": "http://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-22.4.3.tgz", @@ -5088,7 +5648,7 @@ "babel-jest": "22.4.4", "jest": "22.4.4", "json5": "0.5.1", - "react-test-renderer": "16.5.2" + "react-test-renderer": "16.6.0" }, "dependencies": { "ansi-regex": { @@ -5106,6 +5666,32 @@ "color-convert": "1.9.3" } }, + "babel-jest": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-22.4.4.tgz", + "integrity": "sha512-A9NB6/lZhYyypR9ATryOSDcqBaqNdzq4U+CN+/wcMsLcmKkPxQEoTKLajGfd3IkxNyVBT8NewUK2nWyGbSzHEQ==", + "dev": true, + "requires": { + "babel-plugin-istanbul": "4.1.6", + "babel-preset-jest": "22.4.4" + } + }, + "babel-plugin-jest-hoist": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.4.tgz", + "integrity": "sha512-DUvGfYaAIlkdnygVIEl0O4Av69NtuQWcrjMOv6DODPuhuGLDnbsARz3AwiiI/EkIMMlxQDUcrZ9yoyJvTNjcVQ==", + "dev": true + }, + "babel-preset-jest": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-22.4.4.tgz", + "integrity": "sha512-+dxMtOFwnSYWfum0NaEc0O03oSdwBsjx4tMSChRDPGwu/4wSY6Q6ANW3wkjKpJzzguaovRs/DODcT4hbSN8yiA==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "22.4.4", + "babel-plugin-syntax-object-rest-spread": "6.13.0" + } + }, "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", @@ -5579,6 +6165,32 @@ "color-convert": "1.9.3" } }, + "babel-jest": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-22.4.4.tgz", + "integrity": "sha512-A9NB6/lZhYyypR9ATryOSDcqBaqNdzq4U+CN+/wcMsLcmKkPxQEoTKLajGfd3IkxNyVBT8NewUK2nWyGbSzHEQ==", + "dev": true, + "requires": { + "babel-plugin-istanbul": "4.1.6", + "babel-preset-jest": "22.4.4" + } + }, + "babel-plugin-jest-hoist": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.4.tgz", + "integrity": "sha512-DUvGfYaAIlkdnygVIEl0O4Av69NtuQWcrjMOv6DODPuhuGLDnbsARz3AwiiI/EkIMMlxQDUcrZ9yoyJvTNjcVQ==", + "dev": true + }, + "babel-preset-jest": { + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-22.4.4.tgz", + "integrity": "sha512-+dxMtOFwnSYWfum0NaEc0O03oSdwBsjx4tMSChRDPGwu/4wSY6Q6ANW3wkjKpJzzguaovRs/DODcT4hbSN8yiA==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "22.4.4", + "babel-plugin-syntax-object-rest-spread": "6.13.0" + } + }, "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", @@ -5839,6 +6451,48 @@ } } }, + "jest-watcher": { + "version": "23.4.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-23.4.0.tgz", + "integrity": "sha1-0uKM50+NrWxq/JIrksq+9u0FyRw=", + "dev": true, + "requires": { + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "string-length": "2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.3" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, "jest-worker": { "version": "22.2.2", "resolved": "http://registry.npmjs.org/jest-worker/-/jest-worker-22.2.2.tgz", @@ -5993,6 +6647,12 @@ "graceful-fs": "4.1.11" } }, + "kleur": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-2.0.2.tgz", + "integrity": "sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ==", + "dev": true + }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -9900,6 +10560,16 @@ "asap": "2.0.6" } }, + "prompts": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-0.1.14.tgz", + "integrity": "sha512-rxkyiE9YH6zAz/rZpywySLKkpaj0NMVyNw1qhsubdbjjSgcayjTShDreZGlFMcGSu5sab3bAKPfFk78PB90+8w==", + "dev": true, + "requires": { + "kleur": "2.0.2", + "sisteransi": "0.1.1" + } + }, "prop-types": { "version": "15.6.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", @@ -10019,9 +10689,9 @@ } }, "react-is": { - "version": "16.5.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.5.2.tgz", - "integrity": "sha512-hSl7E6l25GTjNEZATqZIuWOgSnpXb3kD0DVCujmg46K5zLxsbiKaaT6VO9slkSBDPZfYs30lwfJwbOFOnoEnKQ==", + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.6.0.tgz", + "integrity": "sha512-q8U7k0Fi7oxF1HvQgyBjPwDXeMplEsArnKt2iYhuIF86+GBbgLHdAmokL3XUFjTd7Q363OSNG55FOGUdONVn1g==", "dev": true }, "react-lifecycles-compat": { @@ -10352,15 +11022,15 @@ } }, "react-test-renderer": { - "version": "16.5.2", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.5.2.tgz", - "integrity": "sha512-AGbJYbCVx1J6jdUgI4s0hNp+9LxlgzKvXl0ROA3DHTrtjAr00Po1RhDZ/eAq2VC/ww8AHgpDXULh5V2rhEqqJg==", + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.6.0.tgz", + "integrity": "sha512-w+Y3YT7OX1LP5KO7HCd0YR34Ol1qmISHaooPNMRYa6QzmwtcWhEGuZPr34wO8UCBIokswuhyLQUq7rjPDcEtJA==", "dev": true, "requires": { "object-assign": "4.1.1", "prop-types": "15.6.2", - "react-is": "16.5.2", - "schedule": "0.5.0" + "react-is": "16.6.0", + "scheduler": "0.10.0" } }, "react-timer-mixin": { @@ -10983,12 +11653,13 @@ "resolved": "http://registry.npmjs.org/sax/-/sax-1.1.6.tgz", "integrity": "sha1-XWFr6KXmB9VOEUr65Vt+ry/MMkA=" }, - "schedule": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/schedule/-/schedule-0.5.0.tgz", - "integrity": "sha512-HUcJicG5Ou8xfR//c2rPT0lPIRR09vVvN81T9fqfVgBmhERUbDEQoYKjpBxbueJnCPpSu2ujXzOnRQt6x9o/jw==", + "scheduler": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.10.0.tgz", + "integrity": "sha512-+TSTVTCBAA3h8Anei3haDc1IRwMeDmtI/y/o3iBe3Mjl2vwYF9DtPDt929HyRmV/e7au7CLu8sc4C4W0VOs29w==", "dev": true, "requires": { + "loose-envify": "1.4.0", "object-assign": "4.1.1" } }, @@ -11162,6 +11833,12 @@ } } }, + "sisteransi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-0.1.1.tgz", + "integrity": "sha512-PmGOd02bM9YO5ifxpw36nrNMBTptEtfRl4qUYl9SndkolplkrZZOW7PGHjrZL53QvMVj9nQ+TKqUnRsw4tJa4g==", + "dev": true + }, "slash": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", diff --git a/mp3/package.json b/mp3/package.json index eb5d375..ff78f66 100644 --- a/mp3/package.json +++ b/mp3/package.json @@ -24,6 +24,9 @@ "react-navigation": "^2.16.0" }, "devDependencies": { - "jest-expo": "30.0.0" + "babel-jest": "^23.6.0", + "jest": "^23.6.0", + "jest-expo": "30.0.0", + "react-test-renderer": "^16.6.0" } } diff --git a/mp3/screens/FollowerScreen.js b/mp3/screens/FollowerScreen.js index 87a6c70..cc5f556 100644 --- a/mp3/screens/FollowerScreen.js +++ b/mp3/screens/FollowerScreen.js @@ -1,14 +1,181 @@ import React from 'react'; -import { Text } from 'react-native'; +import axios from 'axios'; +import { AsyncStorage } from 'react-native'; +import { + StyleSheet, + Text, + View, + FlatList, + ActivityIndicator, +} from 'react-native'; +import { List, ListItem, Button } from 'react-native-elements'; +import { WebBrowser } from 'expo'; + export default class FollowerScreen extends React.Component { static navigationOptions = { title: 'Follower', }; + constructor(props){ + super(props); + + this.state = { + data: [], + pageNum: 1, + loading: false, + baseUser: 'cs242HW', + }; + this.makeRequest = this.makeRequest.bind(this); + } + + componentDidMount(){ + this.makeRequest(this.state.baseUser); + } + + _storeData = async (key, item) => { + try { + await AsyncStorage.setItem(key, JSON.stringify(item)); + } catch (e) { + console.log(e.message); + } + } + + _retrieveData = async (key) => { + try { + const data = await AsyncStorage.getItem(key+'Followers'); + console.log("followers key: "+key+'Followers'); + console.log("followers data: "+data); + if (data){ + this.setState({ + data: JSON.parse(data), + loading: false, + }); + } else { + axios.get('https://api.github.com/users/'+key+'/followers?page='+this.state.pageNum) + .then((res) => { + if (res.length != 0){ + var data = [] + for (var i=0; i<res.data.length; i++){ + const id = res.data[i].id; + const name = res.data[i].login; + const avatar_url = res.data[i].avatar_url; + const html_url = res.data[i].html_url; + const repo = res.data[i].repos_url; + const followers = res.data[i].followers_url; + const following = res.data[i].following_url; + data.push({id: id, name: name, avatar: avatar_url, url: html_url, repo: repo, followers: followers, following: following}); + } + this.setState({ + data: data, + loading: false, + }); + this._storeData(key+'Followers', data); + } + }) + .catch(err => { + console.log(err); + }) + } + } catch (e) { + console.log(e.message); + } + } + + makeRequest = (userName) => { + this.setState({ + loading: true, + }) + + this._retrieveData(userName); + } + + _handlePress = () => { + axios.get('https://api.github.com/users/'+this.state.baseUser+'/followers?page='+this.state.pageNum) + .then((res) => { + console.log("Refresh triggered!"); + if (res.length != 0){ + var data = [] + for (var i=0; i<res.data.length; i++){ + const id = res.data[i].id; + const name = res.data[i].login; + const avatar_url = res.data[i].avatar_url; + const html_url = res.data[i].html_url; + const repo = res.data[i].repos_url; + const followers = res.data[i].followers_url; + const following = res.data[i].following_url; + data.push({id: id, name: name, avatar: avatar_url, url: html_url, repo: repo, followers: followers, following: following}); + } + this.setState({ + data: data, + loading: false, + }); + this._storeData(this.state.baseUser+'Followers', data); + } + }) + .catch(err => { + console.log(err); + }) + } + + renderFooter = () => { + if (!this.state.loading) return null; + + return ( + <View + style={{ + paddingVertical: 20, + borderTopWidth: 1, + borderColor: "#CED0CE" + }} + > + <ActivityIndicator animating size="large" /> + </View> + ); + } + + renderSeparator = () => { + return ( + <View + style={{ + height: 1, + width: "86%", + backgroundColor: "#CED0CE", + marginLeft: "14%" + }} + /> + ); + }; + render() { - return( - <Text>Followers</Text> - ) + return ( + <View> + <List containerStyle={{marginTop: 0, borderTopWidth: 0, borderBottomWidth: 0}}> + <FlatList + data={this.state.data} + renderItem={({ item }) => ( + <ListItem + roundAvatar + avatar={{uri: item.avatar}} + title={item.name} + titleStyle={{fontWeight: 'bold'}} + underlayColor='#E5E8E8' + containerStyle={{ borderBottomWidth: 0 }} + onPress={() => this.props.navigation.navigate('Profile', { name: item.name })} + /> + )} + keyExtractor={item => item.id.toString()} + ListFooterComponent={this.renderFooter} + ItemSeparatorComponent={this.renderSeparator} + /> + </List> + <Button + buttonStyle={{marginTop: '2%', width: '50%', alignSelf: 'center'}} + title={'REFRESH'} + backgroundColor='#AF7AC5' + onPress={this._handlePress.bind(this)} + /> + </View> + ); } } diff --git a/mp3/screens/FollowingScreen.js b/mp3/screens/FollowingScreen.js index ca3f29e..79583b4 100644 --- a/mp3/screens/FollowingScreen.js +++ b/mp3/screens/FollowingScreen.js @@ -1,14 +1,246 @@ import React from 'react'; -import { Text } from 'react-native'; +import axios from 'axios'; +import { AsyncStorage } from 'react-native'; +import { + StyleSheet, + Text, + View, + FlatList, + ActivityIndicator, + TouchableOpacity, +} from 'react-native'; +import { List, ListItem, Button } from 'react-native-elements'; +import { WebBrowser } from 'expo'; + export default class FollowingScreen extends React.Component { static navigationOptions = { title: 'Following', }; + constructor(props){ + super(props); + + this.state = { + data: [], + pageNum: 1, + loading: false, + baseUser: 'cs242HW', + password: 'assignment3', + following: {}, + }; + this.makeRequest = this.makeRequest.bind(this); + } + + componentDidMount(){ + this.makeRequest(this.state.baseUser); + } + + // _handlePress = (url) => { + // WebBrowser.openBrowserAsync(url); + // } + + _storeData = async (key, item) => { + try { + await AsyncStorage.setItem(key, JSON.stringify(item)); + } catch (e) { + console.log(e.message); + } + } + + _retrieveData = async (key) => { + try { + const data = await AsyncStorage.getItem(key+'Following'); + console.log("following key: "+key+'Following'); + console.log("following data: "+data); + if (data){ + let following = JSON.parse(data); + var following_dict = []; + following.forEach(function(item) { + following_dict.push({ + key: item.name, + value: true, + }); + }.bind(this)); + + this.setState({ + data: following, + loading: false, + following: following_dict, + }); + } else { + axios.get('https://api.github.com/users/'+key+'/following?page='+this.state.pageNum) + .then((res) => { + if (res.length != 0){ + var data = [] + for (var i=0; i<res.data.length; i++){ + const id = res.data[i].id; + const name = res.data[i].login; + const avatar_url = res.data[i].avatar_url; + const html_url = res.data[i].html_url; + data.push({id: id, name: name, avatar: avatar_url, url: html_url}) + } + let following = data; + var following_dict = []; + following.forEach(function(item) { + following_dict.push({ + key: item.name, + value: true, + }); + }.bind(this)); + + this.setState({ + data: following, + loading: false, + following: following_dict, + }); + } + }) + .catch(err => { + console.log(err); + }) + } + } catch (e) { + console.log(e.message); + } + } + + makeRequest = (userName) => { + this.setState({ + loading: true, + }) + + this._retrieveData(userName); + } + + _handlePress = () => { + axios.get('https://api.github.com/users/'+this.state.baseUser+'/following?page='+this.state.pageNum) + .then((res) => { + console.log("Refresh triggered!"); + if (res.length != 0){ + var data = [] + for (var i=0; i<res.data.length; i++){ + const id = res.data[i].id; + const name = res.data[i].login; + const avatar_url = res.data[i].avatar_url; + const html_url = res.data[i].html_url; + data.push({id: id, name: name, avatar: avatar_url, url: html_url}) + } + this.setState({ + data: data, + loading: false, + }); + this._storeData(this.state.baseUser+'Following', data); + } + }) + .catch(err => { + console.log(err); + }) + } + + _changeFollow = (key) => { + const following = this.state.following[key]; + if (following){ + //axios.delete('https://api.github.com/users/'+this.state.baseUser+'/following/'+key) + fetch('http://api.github.com/user/following/'+key, { + method: 'DELETE', + headers: { + 'Authorization': 'Basic ' + new Buffer(this.state.baseUser + ':' + this.state.password).toString('base64') + }, + }) + .then((res) => { + var dict = this.state.following; + dict[key] = false; + this.setState({ + following: dict, + }); + }) + .catch(e => { + console.log(e.message); + }) + } else { + axios.put('https://api.github.com/users'+this.state.baseUser+'/following/'+key) + .then((res) => { + var dict = this.state.following; + dict[key] = true; + this.setState({ + following: dict, + }); + }) + .catch(e => { + console.log(e.message); + }) + } + } + + renderFooter = () => { + if (!this.state.loading) return null; + + return ( + <View + style={{ + paddingVertical: 20, + borderTopWidth: 1, + borderColor: "#CED0CE" + }} + > + <ActivityIndicator animating size="large" /> + </View> + ); + } + + renderSeparator = () => { + return ( + <View + style={{ + height: 1, + width: "86%", + backgroundColor: "#CED0CE", + marginLeft: "14%", + }} + /> + ); + }; + + // <TouchableOpacity style={{backgroundColor: 'green'}}> + // <Text style={{color: 'black'}} onPress={ () => this._changeFollow(item.name)}>{this.state.following[item.name]}</Text> + // </TouchableOpacity> + render() { - return( - <Text>Following</Text> - ) + return ( + <View> + <List containerStyle={{marginTop: 0, borderTopWidth: 0, borderBottomWidth: 0}}> + <FlatList + data={this.state.data} + renderItem={({ item }) => ( + <ListItem + roundAvatar + avatar={{uri: item.avatar}} + title={item.name} + titleStyle={{fontWeight: 'bold'}} + underlayColor='#E5E8E8' + containerStyle={{ borderBottomWidth: 0 }} + onPress={() => this.props.navigation.navigate('Profile', { name: item.name })} + rightIcon = {<Button + title={this.state.following[item.name]?'unfollow':'following'} + backgroundColor='#E8DAEF' + onPress={this._changeFollow.bind(this, item.name)} + /> + } + /> + )} + keyExtractor={item => item.id.toString()} + ListFooterComponent={this.renderFooter} + ItemSeparatorComponent={this.renderSeparator} + /> + </List> + <Button + buttonStyle={{marginTop: '2%', width: '50%', alignSelf: 'center'}} + title={'REFRESH'} + backgroundColor='#AF7AC5' + onPress={this._handlePress.bind(this)} + /> + </View> + ); } } diff --git a/mp3/screens/Profile/Detail.js b/mp3/screens/Profile/Detail.js index ab29f47..0a077e7 100644 --- a/mp3/screens/Profile/Detail.js +++ b/mp3/screens/Profile/Detail.js @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import { Button } from 'react-native-elements'; import PropTypes from 'prop-types'; +import { AsyncStorage } from 'react-native'; import { View, Text, @@ -10,34 +11,46 @@ import { export default class Detail extends Component { + _handlePress = (name) => { + this.props.navigation.navigate('Profile', {name: name}) + } + render(){ - const { repo, followers, following, navigation } = this.props; + const { baseUser, userName, repo, followers, following, navigation } = this.props; - if (repo != 0){ + if (repo != -1){ return( <View style={styles.detail}> <View style={styles.topContainer}> <Button - title={'REPO\n'+'# '+repo} + title={'REPO\n'+'# '+(repo == null ? 0:repo)} rounded={true} backgroundColor='#58D68D' onPress={() => {navigation.navigate('Repo');}} /> </View> - <View style={styles.bottomContainer}> + <View style={styles.middleContainer}> <Button - title={'FOLLOWERS\n'+'# '+followers} + title={'FOLLOWERS\n'+'# '+(followers == null ? 0:followers)} backgroundColor='#F4D03F' rounded={true} onPress={() => {navigation.navigate('Follower')}} /> <Button - title={'FOLLOWING\n'+'# '+following} + title={'FOLLOWING\n'+'# '+(following == null ? 0:following)} backgroundColor='#EC7063' rounded={true} onPress={() => {navigation.navigate('Following')}} /> </View> + <View style={styles.bottomContainer}> + <Button + title={'BACK TO ME'} + backgroundColor='#5DADE2' + rounded={true} + onPress={this._handlePress.bind(this, baseUser)} + /> + </View> </View> ); } else { @@ -46,12 +59,6 @@ export default class Detail extends Component { } } -Detail.propTypes = { - repo: PropTypes.number.isRequired, - followers: PropTypes.number.isRequired, - following: PropTypes.number.isRequired, -} - const styles = StyleSheet.create({ detail: { flex: 1, @@ -64,10 +71,14 @@ const styles = StyleSheet.create({ alignItems: 'center', paddingTop: '5%', }, - bottomContainer: { + middleContainer: { flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly', }, + bottomContainer: { + alignItems: 'center', + paddingVertical: '5%', + } }); diff --git a/mp3/screens/Profile/Header.js b/mp3/screens/Profile/Header.js index 1a8758a..1074bec 100644 --- a/mp3/screens/Profile/Header.js +++ b/mp3/screens/Profile/Header.js @@ -32,7 +32,7 @@ export default class Header extends Component { Header.propTypes = { profilePic: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, + // name: PropTypes.string.isRequired, // This is weird, but some people just don't "have" a name. userName: PropTypes.string.isRequired, createdAt: PropTypes.string.isRequired, } diff --git a/mp3/screens/Profile/Intro.js b/mp3/screens/Profile/Intro.js index d6b3c7b..1370ab6 100644 --- a/mp3/screens/Profile/Intro.js +++ b/mp3/screens/Profile/Intro.js @@ -1,9 +1,11 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; +import { WebBrowser } from 'expo'; import { View, Text, StyleSheet, + TouchableOpacity, } from 'react-native'; export default class Intro extends Component { @@ -18,7 +20,7 @@ export default class Intro extends Component { <Text style={styles.infoTitle}>Bio</Text> </View> <View style={styles.textContainer}> - <Text style={styles.infoText}>{this.props.bio}</Text> + <Text>{this.props.bio}</Text> </View> </View> <View style={styles.infoContainer}> @@ -26,7 +28,9 @@ export default class Intro extends Component { <Text style={styles.infoTitle}>Website</Text> </View> <View style={styles.textContainer}> - <Text style={styles.infoText}>{this.props.website}</Text> + <TouchableOpacity onPress={() => { WebBrowser.openBrowserAsync(this.props.website);}}> + <Text style={styles.infoText}>{this.props.website}</Text> + </TouchableOpacity> </View> </View> <View style={styles.infoContainer}> @@ -34,7 +38,7 @@ export default class Intro extends Component { <Text style={styles.infoTitle}>Email</Text> </View> <View style={styles.textContainer}> - <Text style={styles.infoText}>{this.props.email}</Text> + <Text>{this.props.email}</Text> </View> </View> </View> @@ -45,13 +49,6 @@ export default class Intro extends Component { } } - -Intro.propTypes = { - bio: PropTypes.string.isRequired, - website: PropTypes.string.isRequired, -} - - const styles = StyleSheet.create({ intro: { flex: 1, @@ -80,4 +77,7 @@ const styles = StyleSheet.create({ fontWeight: 'bold', paddingHorizontal: 50, }, + infoText: { + color: 'blue', + } }); diff --git a/mp3/screens/Profile/ProfileScreen.js b/mp3/screens/Profile/ProfileScreen.js index 2352d3b..373494d 100644 --- a/mp3/screens/Profile/ProfileScreen.js +++ b/mp3/screens/Profile/ProfileScreen.js @@ -1,5 +1,6 @@ import React from 'react'; import axios from 'axios'; +import { AsyncStorage } from 'react-native'; import { ScrollView, View, @@ -7,6 +8,7 @@ import { Image, StyleSheet, Alert, + Button, } from 'react-native'; import Header from './Header'; @@ -19,32 +21,256 @@ export default class ProfileScreen extends React.Component { title: 'Profile', } - state = { - profilePic: '', - name: '', - userName: '', - createdAt: '', - bio: '', - website: '', - email: 'curran@datavis.tech', - repo: 0, - followers: NaN, - following: NaN, + constructor(props){ + super(props); + this.state = { + data: { + profilePic: '', + name: '', + userName: '', + createdAt: '', + bio: '', + website: '', + email: 'cs242HW@info.com', + repo: -1, + followers: -1, + following: -1, + }, + baseUser: 'cs242HW', + } + // this.makeRequest = this.makeRequest.bind(this); } componentDidMount(){ - axios.get('https://api.github.com/users/curran') + this._retrieveData(this.state.baseUser); + } + + // makeRequest = (userName) => { + // try { + // const data = this._retrieveData(userName); + // if (data){ + // console.log("User data exist!"); + // } else { + // // First time fetching user data + // axios.get('https://api.github.com/users/'+userName) + // .then((res) => { + // this.setState({ + // data: { + // profilePic: res.data.avatar_url, + // name: res.data.name, + // userName: res.data.login, + // createdAt: res.data.created_at, + // bio: res.data.bio, + // website: res.data.html_url, + // repo: res.data.public_repos, + // followers: res.data.followers, + // following: res.data.following, + // } + // }, () => { + // this._storeData(userName, this.state.data); + // }); + // }) + // .catch(err => { + // console.log(err); + // Alert.alert("Error occured when making API call!"); + // }) + // + // // First time fetching user repo data + // axios.get('https://api.github.com/users/'+userName+'/repos') + // .then((res) => { + // if (res.length != 0){ + // var data = [] + // for (var i=0; i<res.data.length; i++){ + // const id = res.data[i].id; + // const name = res.data[i].name; + // const owner = res.data[i].owner.login; + // const description = res.data[i].description; + // const url = res.data[i].html_url; + // data.push({id: id, name: name, owner: owner, description: description, url: url}) + // } + // this._storeData(userName+'Repos', data); + // } + // }) + // .catch(err => { + // console.log(err); + // Alert.alert("Error occured when making API call!"); + // }) + // + // axios.get('https://api.github.com/users/'+userName+'/followers') + // .then((res) => { + // if (res.length != 0){ + // var data = [] + // for (var i=0; i<res.data.length; i++){ + // const id = res.data[i].id; + // const name = res.data[i].login; + // const avatar_url = res.data[i].avatar_url; + // const html_url = res.data[i].html_url; + // const repo = res.data[i].repos_url; + // const followers = res.data[i].followers_url; + // const following = res.data[i].following_url; + // data.push({id: id, name: name, avatar: avatar_url, url: html_url, repo: repo, followers: followers, following: following}); + // } + // this._storeData(userName+'Followers', data); + // } + // }) + // .catch(err => { + // console.log(err); + // }) + // + // axios.get('https://api.github.com/users/'+userName+'/following') + // .then((res) => { + // if (res.length != 0){ + // var data = [] + // for (var i=0; i<res.data.length; i++){ + // const id = res.data[i].id; + // const name = res.data[i].login; + // const avatar_url = res.data[i].avatar_url; + // const html_url = res.data[i].html_url; + // data.push({id: id, name: name, avatar: avatar_url, url: html_url}) + // } + // this._storeData(userName+'Following', data); + // } + // }) + // .catch(err => { + // console.log(err); + // }) + // } + // } catch (e) { + // console.log(e.message); + // } + // } + + _storeData = async (key, item) => { + try { + await AsyncStorage.setItem(key, JSON.stringify(item)); + } catch (e) { + console.log(e.message); + } + } + + _retrieveData = async (key) => { + try { + const data = await AsyncStorage.getItem(key); + console.log("db key: "+key); + console.log("db data: "+data); + if (data){ + this.setState({ + data: JSON.parse(data), + }); + } else { + console.log("first time fetching data !"); + // First time fetching user data + axios.get('https://api.github.com/users/'+key) + .then((res) => { + this.setState({ + data: { + profilePic: res.data.avatar_url, + name: res.data.name, + userName: res.data.login, + createdAt: res.data.created_at, + bio: res.data.bio, + website: res.data.html_url, + repo: res.data.public_repos, + followers: res.data.followers, + following: res.data.following, + } + }, () => { + this._storeData(key, this.state.data); + }); + }) + .catch(err => { + console.log(err); + Alert.alert("Error occured when making API call!"); + }) + + // First time fetching user repo data + axios.get('https://api.github.com/users/'+key+'/repos') + .then((res) => { + if (res.length != 0){ + var data = [] + for (var i=0; i<res.data.length; i++){ + const id = res.data[i].id; + const name = res.data[i].name; + const owner = res.data[i].owner.login; + const description = res.data[i].description; + const url = res.data[i].html_url; + data.push({id: id, name: name, owner: owner, description: description, url: url}) + } + this._storeData(key+'Repos', data); + } + }) + .catch(err => { + console.log(err); + Alert.alert("Error occured when making API call!"); + }) + + axios.get('https://api.github.com/users/'+key+'/followers') + .then((res) => { + if (res.length != 0){ + var data = [] + for (var i=0; i<res.data.length; i++){ + const id = res.data[i].id; + const name = res.data[i].login; + const avatar_url = res.data[i].avatar_url; + const html_url = res.data[i].html_url; + const repo = res.data[i].repos_url; + const followers = res.data[i].followers_url; + const following = res.data[i].following_url; + data.push({id: id, name: name, avatar: avatar_url, url: html_url, repo: repo, followers: followers, following: following}); + } + this._storeData(key+'Followers', data); + } + }) + .catch(err => { + console.log(err); + }) + + axios.get('https://api.github.com/users/'+key+'/following') + .then((res) => { + if (res.length != 0){ + var data = [] + for (var i=0; i<res.data.length; i++){ + const id = res.data[i].id; + const name = res.data[i].login; + const avatar_url = res.data[i].avatar_url; + const html_url = res.data[i].html_url; + data.push({id: id, name: name, avatar: avatar_url, url: html_url}) + } + this._storeData(key+'Following', data); + } + }) + .catch(err => { + console.log(err); + }) + } + } catch (e) { + console.log(e.message); + } + } + + componentWillReceiveProps(nextProps){ + const userName = nextProps.navigation.getParam('name'); + console.log('Received name: '+userName); + this._retrieveData(userName); + } + + _handleRefresh = () => { + axios.get('https://api.github.com/users/'+this.state.baseUser) .then((res) => { this.setState({ - profilePic: res.data.avatar_url, - name: res.data.name, - userName: res.data.login, - createdAt: res.data.created_at, - bio: res.data.bio, - website: res.data.html_url, - repo: res.data.public_repos, - followers: res.data.followers, - following: res.data.following, + data: { + profilePic: res.data.avatar_url, + name: res.data.name, + userName: res.data.login, + createdAt: res.data.created_at, + bio: res.data.bio, + website: res.data.html_url, + repo: res.data.public_repos, + followers: res.data.followers, + following: res.data.following, + } + }, () => { + this._storeData(this.state.baseUser, this.state.data); }); }) .catch(err => { @@ -57,22 +283,30 @@ export default class ProfileScreen extends React.Component { return( <ScrollView style={styles.profileContainer}> <Header - profilePic={this.state.profilePic} - name={this.state.name} - userName={this.state.userName} - createdAt={this.state.createdAt} + profilePic={this.state.data.profilePic} + name={this.state.data.name} + userName={this.state.data.userName} + createdAt={this.state.data.createdAt} /> <Intro - bio={this.state.bio} - website={this.state.website} - email={this.state.email} + bio={this.state.data.bio} + website={this.state.data.website} + email={this.state.data.email} /> <Detail - repo={this.state.repo} - followers={this.state.followers} - following={this.state.following} + baseUser={this.state.baseUser} + userName={this.state.userName} + repo={this.state.data.repo} + followers={this.state.data.followers} + following={this.state.data.following} navigation={this.props.navigation} /> + <Button + onPress={this._handleRefresh.bind(this)} + title="REFRESH" + color="#CCD1D1" + accessibilityLabel="Update My Profile Page" + /> </ScrollView> ); } diff --git a/mp3/screens/RepoScreen.js b/mp3/screens/RepoScreen.js index 6742420..2e6e783 100644 --- a/mp3/screens/RepoScreen.js +++ b/mp3/screens/RepoScreen.js @@ -1,5 +1,6 @@ import React from 'react'; import axios from 'axios'; +import { AsyncStorage } from 'react-native'; import { StyleSheet, Text, @@ -23,54 +24,72 @@ export default class RepoScreen extends React.Component { data: [], pageNum: 1, loading: false, + baseUser: 'cs242HW', }; this.makeRequest = this.makeRequest.bind(this); } componentDidMount(){ - this.makeRequest(); + this.makeRequest(this.state.baseUser); } _handlePress = (url) => { WebBrowser.openBrowserAsync(url); } - _handleLoadMore = () => { - let pageNum = this.state.pageNum; + _storeData = async (key, item) => { + try { + await AsyncStorage.setItem(key, JSON.stringify(item)); + } catch (e) { + console.log(e.message); + } + } - this.setState({ - pageNum: pageNum+1 - }, () => { - this.makeRequest(); - }); + _retrieveData = async (key) => { + try { + const data = await AsyncStorage.getItem(key+'Repos'); + console.log("repo key: "+key+'Repos'); + console.log("repo data: "+data); + if (data){ + this.setState({ + data: JSON.parse(data), + loading: false, + }); + } else { + axios.get('https://api.github.com/users/'+key+'/repos?page='+this.state.pageNum) + .then((res) => { + if (res.length != 0){ + var data = [] + for (var i=0; i<res.data.length; i++){ + const id = res.data[i].id; + const name = res.data[i].name; + const owner = res.data[i].owner.login; + const description = res.data[i].description; + const url = res.data[i].html_url; + data.push({id: id, name: name, owner: owner, description: description, url: url}) + } + this.setState({ + data: data, + loading: false, + }); + this._storeData(key+'Repos', data); + } + }) + .catch(err => { + console.log(err); + }) + } + } catch (e) { + console.log(e.message); + } } - makeRequest = () => { + makeRequest = (userName) => { this.setState({ loading: true, }) - axios.get('https://api.github.com/users/curran/repos?page='+this.state.pageNum) - .then((res) => { - if (res.length != 0){ - var data = [] - for (var i=0; i<res.data.length; i++){ - const id = res.data[i].id; - const name = res.data[i].name; - const owner = res.data[i].owner.login; - const description = res.data[i].description; - const url = res.data[i].html_url; - data.push({id: id, name: name, owner: owner, description: description, url: url}) - } - this.setState({ - data: data, - loading: false, - }); - } - }) - .catch(err => { - console.log(err); - }) + this._retrieveData(userName); } renderFooter = () => { @@ -89,6 +108,19 @@ export default class RepoScreen extends React.Component { ); } + renderSeparator = () => { + return ( + <View + style={{ + height: 1, + backgroundColor: "#CED0CE", + marginLeft: "2%", + marginRight: "2%", + }} + /> + ); + }; + render() { return ( <List containerStyle={{marginTop: 0, borderTopWidth: 0, borderBottomWidth: 0}}> @@ -108,6 +140,7 @@ export default class RepoScreen extends React.Component { )} keyExtractor={item => item.id.toString()} ListFooterComponent={this.renderFooter} + ItemSeparatorComponent={this.renderSeparator} /> </List> ); -- GitLab