From 23e876f0b3d43a7d58439422ebebd1b38e57267b Mon Sep 17 00:00:00 2001 From: Greg Wilson Date: Mon, 27 Jun 2016 18:46:23 -0400 Subject: [PATCH] creating example app demonstrating interaction with body measurement healthkit data --- examples/BodyMeasurements/app/app.js | 56 ++++ .../app/assets/images/arrow-right.png | Bin 0 -> 18110 bytes .../app/assets/images/bmi.png | Bin 0 -> 15038 bytes .../app/assets/images/bodyfat.png | Bin 0 -> 6431 bytes .../app/assets/images/dumbbell.png | Bin 0 -> 5961 bytes .../app/assets/images/heartbeat.png | Bin 0 -> 858 bytes .../app/assets/images/measuring-tape.png | Bin 0 -> 1531 bytes .../app/assets/images/muscle-mass.png | Bin 0 -> 3767 bytes .../app/assets/images/ruler.png | Bin 0 -> 841 bytes .../app/assets/images/scale.png | Bin 0 -> 19411 bytes .../app/assets/images/scale_purple.png | Bin 0 -> 4982 bytes .../app/assets/images/steps.png | Bin 0 -> 1021 bytes .../app/assets/images/strength.png | Bin 0 -> 4126 bytes .../bodyFatPercentage/bodyFatPercentage.js | 97 ++++++ .../components/bodyMassIndex/bodyMassIndex.js | 97 ++++++ .../app/components/dashboard/dashboard.js | 127 ++++++++ .../app/components/dashboard/item.js | 87 +++++ .../app/components/height/height.js | 97 ++++++ .../components/leanBodyMass/leanBodyMass.js | 98 ++++++ .../app/components/weight/weight.js | 97 ++++++ examples/BodyMeasurements/app/stores/body.js | 308 ++++++++++++++++++ .../BodyMeasurements/app/styles/styles.js | 186 +++++++++++ examples/BodyMeasurements/index.ios.js | 59 +--- .../project.pbxproj | 46 +++ .../BodyMeasurements.entitlements | 8 + .../ios/BodyMeasurements/Info.plist | 10 +- examples/BodyMeasurements/package.json | 5 +- 27 files changed, 1316 insertions(+), 62 deletions(-) create mode 100644 examples/BodyMeasurements/app/app.js create mode 100755 examples/BodyMeasurements/app/assets/images/arrow-right.png create mode 100644 examples/BodyMeasurements/app/assets/images/bmi.png create mode 100644 examples/BodyMeasurements/app/assets/images/bodyfat.png create mode 100644 examples/BodyMeasurements/app/assets/images/dumbbell.png create mode 100755 examples/BodyMeasurements/app/assets/images/heartbeat.png create mode 100644 examples/BodyMeasurements/app/assets/images/measuring-tape.png create mode 100644 examples/BodyMeasurements/app/assets/images/muscle-mass.png create mode 100644 examples/BodyMeasurements/app/assets/images/ruler.png create mode 100755 examples/BodyMeasurements/app/assets/images/scale.png create mode 100755 examples/BodyMeasurements/app/assets/images/scale_purple.png create mode 100755 examples/BodyMeasurements/app/assets/images/steps.png create mode 100644 examples/BodyMeasurements/app/assets/images/strength.png create mode 100644 examples/BodyMeasurements/app/components/bodyFatPercentage/bodyFatPercentage.js create mode 100644 examples/BodyMeasurements/app/components/bodyMassIndex/bodyMassIndex.js create mode 100644 examples/BodyMeasurements/app/components/dashboard/dashboard.js create mode 100644 examples/BodyMeasurements/app/components/dashboard/item.js create mode 100644 examples/BodyMeasurements/app/components/height/height.js create mode 100644 examples/BodyMeasurements/app/components/leanBodyMass/leanBodyMass.js create mode 100644 examples/BodyMeasurements/app/components/weight/weight.js create mode 100644 examples/BodyMeasurements/app/stores/body.js create mode 100644 examples/BodyMeasurements/app/styles/styles.js create mode 100644 examples/BodyMeasurements/ios/BodyMeasurements/BodyMeasurements.entitlements diff --git a/examples/BodyMeasurements/app/app.js b/examples/BodyMeasurements/app/app.js new file mode 100644 index 0000000..7fde17c --- /dev/null +++ b/examples/BodyMeasurements/app/app.js @@ -0,0 +1,56 @@ +/** + * Created by greg on 2016-06-27. + */ + +import React, { Component } from 'react'; +import { + AppRegistry, + StyleSheet, + Navigator, + Text, + View +} from 'react-native'; + + +let Dashboard = require('./components/dashboard/dashboard'); +let Weight = require('./components/weight/weight'); +let Height = require('./components/height/height'); +let BodyMassIndex = require('./components/bodyMassIndex/bodyMassIndex'); +let BodyFatPercentage = require('./components/bodyFatPercentage/bodyFatPercentage'); +let LeanBodyMass = require('./components/leanBodyMass/leanBodyMass'); + + +class BodyMeasurementsApp extends Component { + render() { + return ( + + ); + } + + renderScene(route, navigator) { + if(route.name == 'Dashboard') { + return + } + if(route.name == 'Weight') { + return + } + if(route.name == 'Height') { + return + } + if(route.name == 'BodyMassIndex') { + return + } + if(route.name == 'BodyFatPercentage') { + return + } + if(route.name == 'LeanBodyMass') { + return + } + } +} + +module.exports = BodyMeasurementsApp; +export default BodyMeasurementsApp; diff --git a/examples/BodyMeasurements/app/assets/images/arrow-right.png b/examples/BodyMeasurements/app/assets/images/arrow-right.png new file mode 100755 index 0000000000000000000000000000000000000000..3d3b577f21fbd604d49b166d41395979b05cac9d GIT binary patch literal 18110 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 OncTUj@WhwyIQlP^NV2g2 literal 0 HcmV?d00001 diff --git a/examples/BodyMeasurements/app/assets/images/bmi.png b/examples/BodyMeasurements/app/assets/images/bmi.png new file mode 100644 index 0000000000000000000000000000000000000000..562966ac36733b57013950dd01367954a338e91d GIT binary patch literal 15038 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 U1k7J&+W-In07*qoM6N<$g1%Fr9{>OV literal 0 HcmV?d00001 diff --git a/examples/BodyMeasurements/app/assets/images/bodyfat.png b/examples/BodyMeasurements/app/assets/images/bodyfat.png new file mode 100644 index 0000000000000000000000000000000000000000..d1b2a37eb3f8df8b9c08a414b112bc19e706b941 GIT binary patch literal 6431 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 W!!dsQh!prL1JKbhRIgWciuym=Y#by2 literal 0 HcmV?d00001 diff --git a/examples/BodyMeasurements/app/assets/images/dumbbell.png b/examples/BodyMeasurements/app/assets/images/dumbbell.png new file mode 100644 index 0000000000000000000000000000000000000000..f4660f46943b93ab23cd432582d983fb520fec07 GIT binary patch literal 5961 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 literal 0 HcmV?d00001 diff --git a/examples/BodyMeasurements/app/assets/images/heartbeat.png b/examples/BodyMeasurements/app/assets/images/heartbeat.png new file mode 100755 index 0000000000000000000000000000000000000000..b724ae73c69d98c595751a4c76ec37bd3031a735 GIT binary patch literal 858 zcmV-g1Eu_lP)u z#GY#G*x31bel82LgUrwOX1@7mLU`j3y>Wi51;DoZDP-&eTw|a~L?aHvzV#ej)2KJr zf#!Ov7QU+3820)3G=CXnqMpfi4#|jL3FAC zI8w|V^1J=SCIt}Kt|V?7wq&G2e4#(yKCjhn$Z8c^*R@3<|1r6sEMBj}9GA=CNI|=rj z6Day&x}m&&v4Jg%&D#+`baH8-7d+M~1(L`I$$t-H6x`(de=6L({cXPKfdBvi07*qoM6N<$f&@5>mjD0& literal 0 HcmV?d00001 diff --git a/examples/BodyMeasurements/app/assets/images/measuring-tape.png b/examples/BodyMeasurements/app/assets/images/measuring-tape.png new file mode 100644 index 0000000000000000000000000000000000000000..9151edd8b84e983f23e312e5d8301aa7adcf3768 GIT binary patch literal 1531 zcmV(#m;D8D_MD(ztphAR*f*uqM1oRMzf}(;44+?@S z3VKjbjG!1{0}3lBMDVcUiX%i+*gyou2}JaLRu$8!sjjZ->7Ln5`iGyL9j2=L{Z;SP z>#EnAq#0~hZnNB~yj;0OIj8K|-|+wW34I+`4(;E8{ky9CPPwA|tD$@TADe2nyF$5J zxl?(gHGEn)rd(DYQGPP1AUOhDq};2#Pq|}?2FEb8A}lHoEB|RjfGd?xS;H@!wZ#$O zCeJ9}Y)XLhln1Qw>)CK0Ux*p3pC=LEGUW$i{5utEG740`$tZxifCm0lo+xQgAf30L zdol{71XW_p4a$oX?}h94mEYG9;9BL9y@41o3cn*55tM$(5UVb(787_0z-YF_7_SkMa21mw~pID4!FP8>D1-sbD#~re@pF zATBB&s1o1>G1J=zf#&1D_ctlull`9eK7W6p4YP&i zZeG&Cv|hD;ArX3L4R%W;pIO6`*6#oawghlLEq_tDKPJGwC+@*|Ou%v*r9Cl;R_gOS7>HR}29_(UKE-IJm7a0uU*4@{-d6*s6C45+nfkayqCZfRBNUGQL$AZHBHjAdZU}^VTr8 zN$NIAvy5#^fGQva8!N>}-x!=x7~SS_IyC{-H97%00XhLX0XhL@eG{DkodBHxodBHx zodBHxodBHx>qr1LFQ~a;r-wtxJvp5wf@>_<&wZKE!Ah9`>;k`5`2Q_2bwW)V&&H+O zV5LUk$Sg!afL~?2I)ua0;^D(B_6C~*o2s{a--V9pry@Y;!hZc=SrtiLEXsJ@&KqJ* zb*C;ssIcg45P)NN3OzW_*kNrPE9%0~P>Eb!0q7@XH+LEW_*E`JH+F{l7ta-dt#3|Y zsL157f`iqC76jlhhQm=-rmYpf?aTNn)>yzV7D{rcG3R}sDgXzlFBSergp&;mP#n?C z_I_e7Ze$4n9ul+m*AXC8iuRL~pWNgMz`+VxKs6yKUQ2s{dN^KH5S3DySr?Sdr+Z2GeI4DTmE~5e`NJ@J+B7k30 hv}Og^Uwz4Z{0A?|lq*^E+YbN$002ovPDHLkV1nUhuhjqm literal 0 HcmV?d00001 diff --git a/examples/BodyMeasurements/app/assets/images/muscle-mass.png b/examples/BodyMeasurements/app/assets/images/muscle-mass.png new file mode 100644 index 0000000000000000000000000000000000000000..fe14c4b2a8034a96f475dc1a428c649fa859ef0b GIT binary patch literal 3767 zcmbVPX*iVq9v+Rdq*7XJF~*W@_A$mp!i+*=--=|I!DP&gSr|%)UX|k5D@$c5q3K1o zR49`*l{HId+EmhFKbCYxZ*|Ux_j*5^=enNfzy0p}{%!vc&lyMieH&zzWdQ)d2AlnO zXYt4ozjWz!;;-ICqCh+-aR{Cq7e)XloW!C4EXWK$3dkme6i9KVkjN3CZ4^@g09ZwJ z_2hUG58(V6AyCq)4U`wc6r%wEQ*$1Z;Shf~1`fg?pa>M&*x1+*goGpDFgOy1Ktd44I1~~Ghl74TV6hsD z9DsAiTmRG&ugt(f91ar)gN28OL&H%}1}hMTFflP%(!q)@+V5<-gAVEkD~ef=PinQ`ihH%U@i@0L}lA`e&h4!=EwWh$L1pMO;N| z5{*syaX=*E9K_C3=_DGS;m-}B&^b1EGq4x}B~!^b0tx}Q!eTKf3xW{=fk2p8A_xQw z3T2H#qtQl4i(ednhqW?6z)^ThYb(65H3C6EV=+cX1Pin^0*)qNQE<#JtPP#bA<_LQ zzjUc$-Je*(KVorKEDDLkV7W3Fv|kP77{uT(*g*^?$jZeCL?roB>8tD2YKvnMM~kPh zs9_YcHH#4f`jL1X^>6gySS%cYFh;|Tk#GzafxyDCC`%+9g(VontNp;xEBZ<2WN`z})G;?l9iH*FcnmjM7|FWBHMTzNwixk83&-?o-7 zWdoDR*g1Zvs>+UIF6}TGKd%SW&05u0Wg28d4>c)(tD9ZaPfzdAS^zq>+NtYXeiMGdnlfGZHkom^TcEz-Rwo8~sQkF8%`g8H$ z>uL9^>r1Wzyxr#8@$s0(_J=;1wg(cF)ufDdn*^Q_O10e@8<}X%SF$Cm@LaEZ>)u!? zOQ1vbt)v&t<&W(QN6vq;*2L4Ntbp_ki|LmqO>e}>B&(17$;m)G3_jm<;kYj9vu_>o zgd-s2DV#;NQZ%|sX*{*#%I}YFvs5h!xKWVABl;O8i`G%xsd6n>Rz8LgD^!`rd`#u$ z=t(glZ8db`Q^%XNv4F777|rr{Rj-N*;qe!{WQu0n>g>I1^c2#q0*+^R)};MA&_q(| z=u&TOhp)i=I=yGcps%HYBy3MJYDIKvmKO6#+%vm9znSHhRaZs5ooA=%&Aspl95fW3 z%Lu!i88)aLRs<{aO~bSZ(*2Q_O(maB+@iA;*Q*xa z>s}HYIc8AEj&Nv=sIvWWY?jQ5*ULgQ~%sUdQ`39Sn0hGRB6L&pR@^u64;?D z{OMehUwxhWF6hynbwkw~hlQ{cSpkW{CnfEs3UwY|to2-_%K0nMjf@DTx5ZaS>se#z zNXPs$jU5@6`okn{x>A8(Pt<-j%2qNbZrC#Quc+#;EPlo`1>B_(3(Ph-W-Wu(r7G9Z zD3cJgS3>&@qDKN@$hH?(JJcH-`g|32rIR%v!7;pqqT0k=EA89)-e9Q#ro%3nU0B8b zw>aU;HNCjW8e_dAl`UC(T8E)I>4V_873Hv*EEXH*78BRyVE6sY@wg5*za{=V+dE## z)q%w7GjEZCCSx=%Qaz?_F*#YO(%m?+advqrBP$(UETKwpm!sEwnhY%Vey3bBcpZ5x zE_282`;uj_mW6|toIY;x$dRpz71T#t9qQUU!5AM*%B5*n91N5krr?qiYr@_X4x?yv zur|g`1S+82iB|b0^9s2TdIM5#=ke9tOEzSG;K<~+}JO_Z11D<@dDEyMS2Nk1mM}(GO${p zJGZJ-VX%nX-F#QDc0M;L;j;7Co?AutNgd{p?&5O>oh4X^x^!1c73aPU zT&^ryP@gQ_tj}97v|m_}11Q3rffz=#+y>R!h}NxyN3E!RhD;^iW6iFPsv*Ph1RMKXh>d<1-bcz8 z8wz!Vk-7Xc50M_E)SS=`JM*i@x9h?NqE3!`*W2k91_z_`UyJZtENMNLbEdp8CX2S| z$-WntV59qtCy}7x*ie*tbv`o4LqkVHyW!ZlYIbDujES;;p^!{kM2;TJ>}llNjT}5g zdCGS#u2`-RnKSO%-pl4}S8IFGN+QZ$YZB;)kn15wJbSjf7go4wwx^{{N1r%Th;9|S zRd;FDtzQ@sOy^6eT8zK4S}L7Qxjs;GuHGs|?``u z;)6fByXs(!b}pwL1u|uO14{31?Nbwt0X)C1>D}sMW2-Y7NhJ3x)6SvCWO(lyri`Bs zhPheAJ?GT7c-Jqs*&G(p8w-vzfwifpE*j*y>I}L43-LhmdY(yTKG$%@&`4>749d+; zO1Z(9>p;BIe@#c6*7s6icI7>*TY5%Ip!C6tU-=-U7l<#f-01Ae-aC&k$n8uBPwf^+ z$6)jeXtFMYGap<^P8P`m`${k26xzYNWJ+A3Z)X=}=8R{N#42 zWnsnfrMcevJ8m@(bp77h-IzFgR}EISj+-0M7rPT8$%wzBAOV!O23A>E@CQ@tYM9<@ zlZUt`n*c#!yYu9Rjwr96GJ^KlN0gFnG9r8;zwnA1V_O`bGob+qi4R_n$E6T6+kCOO zew%Nfon3(o3hz>!EmGQj_v-c|M+-%b8^^xq%bW6sn3ooVoTC?9d?nV&d3W=_)7Cra zKoi`^ObbcrV23r5UGCicmrn0rT&U55QvM|0d%a+OHdw$_&cUbc^4T=h_GSemDCx~| z1C=d3&1l}cPR=&YU;2uQy8euMJLB<@cE4ORT2Gh6)kl7Dhn0e7?!hi3+a+J_H-Wv= zdN?sJ>97VLt!u3Zgsaq;>+fAt9DIXKgU+7kJ%*(>^{shdlIi6Uv*S)n`*N@3()S6p z*M&=3hvgE3M%B-z0Oj+t23pSP5uLHMK*6YpvnOCb;e+plbt<^SXiO!qY+}5_a$F*9{ z-AkRG1&4;HIn!$$)~F%?P9d$IP~Bz^J8XQdJ8KJKrqiVteUduY^LTj^S4bkIoIr^y zW!lDozBsG6KtPGqJA<*o=0=UQW^9+f6Km~^9rKMQauZ_Oo4cF&&8Nba@>OeZ?SlRR zO>H?8slaC(3lVQPsx>#oBBjEg5<3j!zn)Xs_KC02UYgW)>sD%0U3SL6IY~79j$V_V zlTV(kRG}=R-&6X}Ig*ZcY-|>AvtQ$Ac58+Xg{IOn^(?9sghMW^UiRn{n-}O{gzW>rnUHJDaJUrXc(o z)Ev|u)EXC|C4lMh{bD1u0x%R_1fc~0EIb>*IzTM^U#KMs1j_)i@CQ(PP?u1zxCmAO zu<)NIzb{K5SOlPi?-v`v8bB=kf2dWcp99CR5G(0F+Uuf?xq47XHX} zPy08T2(A^daQZtx~@-(-YZ06C*BMDXD^pso{-K|-hj5DR|- zwS^qFFgb3I5T1-MHUQS`vDYJ={we!_9Q)pNukGsLO94{d{>pVt z>w$camBN<*P)D5>f@t_$0PIYT4;yZ4r4hu#=K!P{-b>e=bx z+)*cupc*~}fL*cKMvjw0P!Ep*VBMY)go`jr_!t0X)RiLmU7g?IslB)70$|tY=a~p< zTUsdqtl=HI@~5;%ICtI7&s6wn07|!yy{>(@w~5D@b;4(IBmr_pU5G%vP>HQ-;d_8v zsMo>m{&RT#{M*outw&gFJ$w&P^3f8H;IFgYxbjs!d=KCX5je|4_-TMK5zK@S0meWu z6@Can6Tw{g7=Q+X$?zC}B!b!SDF6us)8Q!q90c>>sQ@JiO@z+@$U$f(d@cY5;d4vj zO8_v0p)WF-4qpm@Av6`91CT;!B0Lu$hR{rS34joxsqj(&J;FEFeXYHj@P0i5uBDZY T@-YQP00000NkvXXu0mjf>*sBY literal 0 HcmV?d00001 diff --git a/examples/BodyMeasurements/app/assets/images/scale.png b/examples/BodyMeasurements/app/assets/images/scale.png new file mode 100755 index 0000000000000000000000000000000000000000..37f5710ac52f39f948d198c8bc417e40b2f829c8 GIT binary patch literal 19411 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 D8L<3< literal 0 HcmV?d00001 diff --git a/examples/BodyMeasurements/app/assets/images/steps.png b/examples/BodyMeasurements/app/assets/images/steps.png new file mode 100755 index 0000000000000000000000000000000000000000..a32c9940fe139b7d11f60be169ea8614e8139731 GIT binary patch literal 1021 zcmVpPeuz5uUW^DvKnfSL{m`yas8 zAbfuVUsK4~-y&>?u6>D-h-!a8O~msNHp|z1M7cY}`mc!H0(13eUf8y8AqNQi2n;!X z-f84Eqs$fU#Mh*?x!|sfxVMGVKeQgoJb= zGDqych(HH2V?V2^zPMOhgAxETkMh z4uT>dDpemCm78G*ZsJzNQ=ydKG23qpVMUev{D%4~LkJ6vT&G`7$^1&Ed_^J`6( z{ym8`TopcU5QNPduY`ZYl}D$6&_7CwORjKZLDN5Qv4*Qg1f_rcSNY*-N53LioAod} zQb8~_>yZ@?_h^L8TA05uii>S_PMhLisT#^ z9gyFcrpo0ivRhk<%8PC(uSI!-b+_xIgp12H+8pB|IWJB{L7qeFDmjLCJ>SSfmNm&a zIo6Tpf`K8G^*RLuLlNbXTFW4qJ~BjvWkHkXl*D7+*H%79MI?uDMuPhFyLrebMt{Gn zf?{Iq{oyGcUyS{v_;+f<7RO{a}4QpyGx*J(3JakN9l?;kN}; zzb&AgcNsq^%vYjXgPhI({}phW*24%14aqv!V2b(#&8ukrcjN<$&68GZ0^Yz)3_wRCwC#T}yJ~I1&XNvv2hYiatTp zC$Jnbv$k{sOUqeVK7s5LNM6lS@(HY3&qSC$fmtUo>jbSn!Hm+AD5uh(MB+z~LPjX; zc9-}89^T6YkO?88MT-_KTC`}R3(RcXS7j{ZI4jSmV2?8fQ zAT7C+7MK1CK2JuNFFWu|0H&v|`%g(nfipzVOb#&26Z#=Vi_bYAQaVD`Qpw!I?m5>H zKz@KTuaFA~8jy!F(B}sbT~`1fSm|;1S$0X@l8ysMO2K2BOryz60HRxk^ltHe?jwNg z_!KJza7tvGW!IfiWTo4RcMM+Il7L6(3|Xf){(>gUf|Gq0D#Ip$Hsp#?dnf$^gZE!3 zBDjYTWi1J);RZMYXY7BiaRl~$R+qKM1c5YQfxXG?C>tNg#D%60YzoBJdpnKHL7x(F@$O z$iN49WJJQ}MzrpW067P+U?)feW?Jp;_kw^8(Wc@vQDA`2JLm*}Py*&QIm0HJhozo+!n zM%U!`2VYwon17Tj*k}=$Q~k>y!XPIo2BOln@$3sw_F1+t!b>7+l#OP)j(Q70(vXp- zOv=(A0K_C@>&pK)U_tmCIB3p^T*&C>J%n%{pKrqkeY*f6dv>Xp?|ZtR%Ezqjk&e+H zm5c#~`;)+=Y-qz*Gi9I|VSv1)+1V#X&5Hm=`x@tAs2{j$8$>v`AIP5;tpNzx=axFK zEp}GUe2-B8AS%$oE*OYbEkDM|q#n1*KCGjP3csjz5bZuw2BLYJa)yIFx4}ZX3`D`R?$Taj%>k2<%4E8oHf6wG zwH%#2*kGYEjm8YZ_fZ%HacU7fAUCj{^n$bPrcz6p@};eLB3mq^!$7psR!GI1UTJh; z${65?!nYjbLweE|6$6>^m9ZS0UxDvuBg6qyz9O@PR+`yM^b3 z>(ku>t)+6aHfy~3?yTX>GIFyrz`_T70XIc3H2qZBz=q#~?e@T&>a2?_)KtRg4IV>t zc5(Dvv5?-x){5&5Ej{Z!bE@0g3bJJGiBkZLSmTNSK?I$`*QA=5oUMfffGJ*&4wf6s zj9C)4T(!_%Thdm8rjxL>0fZN(&U3ISE@VwgPU3BAfCl~@>?Qgg*ntHHOR>KlBDL6g zRCY%eB0U}Zt{W&M4FE*bMW$V=Q;3dhD!vx6D(g6o7|zRxY>o3eww{ew+_>;rvIV8{ zPn|%a34o}#{`(1*oP&3NCyZq^$Bhlp5<#@}_;tBA%~Xkxl>TVd26nmM}1AqKj10ialZ_bUqt7ZDS>3KXa- z*GnC2@-(#tAd18?!e=k+rnA#C2OUbYN>fk%P;MJQ12!t6eTLn1jcjh)p;k!Q$V0+F zN&MfT4FF|PzA8aw0A9KKUL(R1t9jIv4VUxLkO1)!BUr8hxSF2NbDE` zMF;wL=jLL6>xip@Qyi$SqOwLr(PTf+UlA^~9BS}`T+9uXo}w}epg(K^C|do_bv19Z zmsKhp)B<3E(!dlz!x+Lh3b_lH457$vcNO_Lk+2A$W`2q*DOl=2|2%XDR5&ps)%6I%XDUmX(y9T@)z z{6(RVGTRkvfrVCtg<3gXC`#CI@WAZyi!jRvvo2){UuY5;=y+#l*pX5~vIC)JfpZ$K zLgQ#ljG&$sz**xpOBU{C_*}z^XR5-R4|Ip4gH5f(*;=s&8^rk z>QKirE-kxj71-!?ibC*;^zhyBf$wd|ec)Md#C{^C3n^O@0DU9{`mUCLOv1L7m;*Wj zQevRkna%=9dYEF4luD?Zwwk>0S8371b zVfR2bUJ`(DP8ddZWX3y^eHB1p<=6ytUcqNrlNyh=L>gxbrm|A^8n1DVtmt9^bVDTf z(vabX6$GL!VWs%2vttWP@VQ61cvi?uiNMJnG`8%}dt@DYY<9+^Yi;?yPTmJ4ePU6@ zY6Ix3$weG24wec>^W!8OAH}Ok6%Q3qLaF^&mw{A1jE-H}22f$~;i}l+3OfwK4N zFuq{)wiG=y9K{zMeg&FUs_SYr-okuVqhWKG5*E#g!>c>xGOPfkkq<=aENy!ST(nBF z;Wu7dXCTGJhOw`DYqD=^S7E6OpjQj@7|pE>RFPBz2YOU7Enp5HHZ?wqePze+5SJHA z$3JBi{*aD*y;=njL*>9zsgb^e2Uy|_Wy1!m-xvaDr0{vI0_c0i!$#Ayxh)462Q+1% zhlby$MO2F>YmYh%6lKhueW1f9av#g5Vw z>UbMY^NaYp->B4i9y|Lf3FeDuK`@mDhZEO0M3_$@!s@Ax%yixG`X^SP`D zIPS0*L(>k=@OdbB)&{2?&P^TpL~~@)gE?9|uF(?H=seKKIU8Ke;AQAjzc0Ytei?5ZLL_K(glIYqEjSkz33G*FL@~F?ax) z?%Qh?IxvVNnD{aRd}Ky!p_>$d5z>OO&c_Z;lZv^v*vAw=C&xlZSRzBPY%PIvA-?Xv z+USJpuGq&2KnfPp*5hbhaxLHLMyS)b zWifM`k?vmPWtwwm1RzX2ToMNlX!j~miIGubtLNS0vrzv@72UZ2j?DQVl6x5MZ%-^W z$U7N5T5}wZJMCF9A48p8nHE#pEYd{ggrL*D9RQ3p0QQrM1C7b{5!p{;87JfLb&FIXe&ZQ#Lw^+(aIGkXmFgUr;J*={HGBX}7lD9h zsE~&`oja`f-PE=S&hOZfrH3})(q%30&1QL*sranU1zR=m1DPA5o&Rg(kwOQ+7QYeJ zu$j74piKTSof9&YQMzBqYAwaY^21Uov!=6#&-6w>QG50leTKBAEbXNhhmsbJ{wXah zBMV=NAOVCAy&zGU@vNx@$MKy!%Slakvf!aa-_+{+Td&f}4vhWSedqe9#sjvOs&ZoB zS+MtaQnbQVncpixj)P>f=F@J;?@uQLo{89Be4V;d0Ve<=C0itjhPeLXvk~bQjIvAR zS}cHvw)N7*ypn4Ml9kBl+StT1h>SN&br3um1JBy^`lQoJ^@#kbZxG=q%!u>6J`wP| zuqg!Ri`&kRI`9o5MV{2-32b&7A$SG^JXb#6+sj!Qo*gh@d}^{5Pj(Ov11P!S}s28OBX!`&x%QP?i)N{NlP!!GYn)_ z>p}&^Fi-fwb)@a3<*Mq+OBoB;dxZDvKi5 zwjTS!NC$wE3rpvvog9GJyvJOqkF^FMJ$2DXA_GKql4EClzobJAeh5f1HD(>Uyy0BV zb;Wy>LbF&@1WX~ztI0w(Aqr4|3Iz|MI^Ky5ue zo2(^NRiRA!avKCrXD3ZN3m`>@-5wa>6j1Q_iNM+#*4dGHWbpZhKZi%YCK<99oBVqL zAjK4bl#8^%S99iz(32Wv;-R#(!L?~7YVR^bdIundza*t36MhcNE0N`-Z1#Fhuh#%N zz)+Gw{y@oV!YG`vWZ?z)@8Z;|w4EG)8u(P)mnu%RgkQ91(V|6*7A;z|XwjlYix#aH c_CEmz0FRf~cs8$?3;+NC07*qoM6N<$g3}D1tN;K2 literal 0 HcmV?d00001 diff --git a/examples/BodyMeasurements/app/components/bodyFatPercentage/bodyFatPercentage.js b/examples/BodyMeasurements/app/components/bodyFatPercentage/bodyFatPercentage.js new file mode 100644 index 0000000..68c7c0a --- /dev/null +++ b/examples/BodyMeasurements/app/components/bodyFatPercentage/bodyFatPercentage.js @@ -0,0 +1,97 @@ +/** + * Created by greg on 2016-06-27. + */ + +import React, { Component } from 'react'; +import { + Navigator, + TouchableOpacity, + Text, + View +} from 'react-native'; + +import styles from '../../styles/styles'; +import BodyStore from '../../stores/body'; + + +class BodyFatPercentage extends Component { + + constructor(props) { + super(props); + this.state = this._getStateObject(); + } + + componentDidMount() { + this.unsub = BodyStore.listen(this._onBodyStoreEvent.bind(this)); + } + + componentWillUnmount() { + this.unsub(); + } + + _onBodyStoreEvent(evt) { + this.setState(this._getStateObject()) + } + + _getStateObject() { + return { + bodyFatFormatted: BodyStore.GetBodyFatPercentageFormatted(), + }; + } + + render() { + return ( + + }/> + ); + } + + renderScene(route, navigator) { + return ( + + + + {this.state.bodyFatFormatted} + + + + + + + + ); + } +} + +var NavigationBarRouteMapper = { + LeftButton(route, navigator, index, nextState) { + return ( + {navigator.parentNavigator.pop()}}> + + Back + + + ); + }, + RightButton(route, navigator, index, nextState) { + return null; + }, + Title(route, navigator, index, nextState) { + return ( + + + Body Fat Percentage + + + ); + } +}; + + +module.exports = BodyFatPercentage; +export default BodyFatPercentage; diff --git a/examples/BodyMeasurements/app/components/bodyMassIndex/bodyMassIndex.js b/examples/BodyMeasurements/app/components/bodyMassIndex/bodyMassIndex.js new file mode 100644 index 0000000..0c862f9 --- /dev/null +++ b/examples/BodyMeasurements/app/components/bodyMassIndex/bodyMassIndex.js @@ -0,0 +1,97 @@ +/** + * Created by greg on 2016-06-27. + */ + +import React, { Component } from 'react'; +import { + Navigator, + TouchableOpacity, + Text, + View +} from 'react-native'; + +import styles from '../../styles/styles'; +import BodyStore from '../../stores/body'; + + +class BodyMassIndex extends Component { + + constructor(props) { + super(props); + this.state = this._getStateObject(); + } + + componentDidMount() { + this.unsub = BodyStore.listen(this._onBodyStoreEvent.bind(this)); + } + + componentWillUnmount() { + this.unsub(); + } + + _onBodyStoreEvent(evt) { + this.setState(this._getStateObject()) + } + + _getStateObject() { + return { + bmiFormatted: BodyStore.GetBMIFormatted(), + }; + } + + render() { + return ( + + }/> + ); + } + + renderScene(route, navigator) { + return ( + + + + {this.state.bmiFormatted} + + + + + + + + ); + } +} + +var NavigationBarRouteMapper = { + LeftButton(route, navigator, index, nextState) { + return ( + {navigator.parentNavigator.pop()}}> + + Back + + + ); + }, + RightButton(route, navigator, index, nextState) { + return null; + }, + Title(route, navigator, index, nextState) { + return ( + + + Body Mass Index + + + ); + } +}; + + +module.exports = BodyMassIndex; +export default BodyMassIndex; diff --git a/examples/BodyMeasurements/app/components/dashboard/dashboard.js b/examples/BodyMeasurements/app/components/dashboard/dashboard.js new file mode 100644 index 0000000..6065754 --- /dev/null +++ b/examples/BodyMeasurements/app/components/dashboard/dashboard.js @@ -0,0 +1,127 @@ +/** + * Created by greg on 2016-06-27. + */ + +import React, { Component } from 'react'; +import { + Navigator, + TouchableOpacity, + ScrollView, + Text, + View +} from 'react-native'; +import TimerMixin from 'react-timer-mixin'; +var reactMixin = require('react-mixin'); + +import styles from '../../styles/styles'; +import BodyStore from '../../stores/body'; +import DashboardItem from './item'; + + +class Dashboard extends Component { + + constructor(props) { + super(props); + this.state = this._getStateObject(); + } + + componentDidMount() { + this.unsub = BodyStore.listen(this._onBodyStoreEvent.bind(this)); + } + + componentWillUnmount() { + this.unsub(); + } + + _onBodyStoreEvent(evt) { + this.setState(this._getStateObject()) + } + + _getStateObject() { + return { + weightFormatted: BodyStore.GetWeightFormatted(), + heightFormatted: BodyStore.GetHeightFormatted(), + bmiFormatted: BodyStore.GetBMIFormatted(), + bodyFatFormatted: BodyStore.GetBodyFatPercentageFormatted(), + leanBodyMassFormatted: BodyStore.GetLeanBodyMassFormatted(), + }; + } + + _onPressItem(key) { + console.log('_onPressItem() ==> ', key); + let self = this; + this.requestAnimationFrame(() => { + this.props.navigator.push({ + name: key + }); + }) + } + + + render() { + return ( + + }/> + ); + } + + renderScene(route, navigator) { + return ( + + + + + + + + + + + + ); + } +} + +reactMixin(Dashboard.prototype, TimerMixin); + +var NavigationBarRouteMapper = { + LeftButton(route, navigator, index, nextState) { + return null; + }, + RightButton(route, navigator, index, nextState) { + return null; + }, + Title(route, navigator, index, nextState) { + return ( + + + HealthKit Body Measurements + + + ); + } +}; + + +module.exports = Dashboard; +export default Dashboard; diff --git a/examples/BodyMeasurements/app/components/dashboard/item.js b/examples/BodyMeasurements/app/components/dashboard/item.js new file mode 100644 index 0000000..694d838 --- /dev/null +++ b/examples/BodyMeasurements/app/components/dashboard/item.js @@ -0,0 +1,87 @@ +/** + * Created by greg on 2016-06-27. + */ + +import React, { Component } from 'react'; +import { + AppRegistry, + StyleSheet, + Navigator, + TouchableOpacity, + TouchableHighlight, + ScrollView, + Image, + Text, + View +} from 'react-native'; +import styles from '../../styles/styles'; + +const ICONS = { + "scale": require("../../assets/images/scale.png"), + "ruler": require("../../assets/images/ruler.png"), + "bmi": require("../../assets/images/bmi.png"), + "bodyfat": require("../../assets/images/bodyfat.png"), + "musclemass": require("../../assets/images/muscle-mass.png"), + "arrowright": require('../../assets/images/arrow-right.png'), + "heartbeat": require('../../assets/images/heartbeat.png') +}; + + +class DashboardItem extends Component { + + constructor(props) { + super(props); + this.state = this._getStateObject(this.props); + } + + componentWillReceiveProps(newProps) { + this.setState(this._getStateObject(newProps)); + } + + _getStateObject(props) { + let label = props.label ? props.label : 'Label'; + let value = props.value ? props.value : 'Value'; + let iconSource = (props.icon && ICONS.hasOwnProperty(props.icon)) ? ICONS[props.icon] : ICONS.heartbeat; + return {label,value,iconSource}; + } + + render() { + return ( + + + + + + + {this.state.label} + + + + {this.state.value} + + + + + + + ) + } +} + +DashboardItem.propTypes = { + icon: React.PropTypes.string, + label: React.PropTypes.string, + value: React.PropTypes.string, + onPress: React.PropTypes.func +}; + +DashboardItem.defaultProps = { + onPress: function(){ + console.log('default onPress()'); + } +}; + +module.exports = DashboardItem; +export default DashboardItem; diff --git a/examples/BodyMeasurements/app/components/height/height.js b/examples/BodyMeasurements/app/components/height/height.js new file mode 100644 index 0000000..1d416fe --- /dev/null +++ b/examples/BodyMeasurements/app/components/height/height.js @@ -0,0 +1,97 @@ +/** + * Created by greg on 2016-06-27. + */ + +import React, { Component } from 'react'; +import { + Navigator, + TouchableOpacity, + Text, + View +} from 'react-native'; + +import styles from '../../styles/styles'; +import BodyStore from '../../stores/body'; + + +class Height extends Component { + + constructor(props) { + super(props); + this.state = this._getStateObject(); + } + + componentDidMount() { + this.unsub = BodyStore.listen(this._onBodyStoreEvent.bind(this)); + } + + componentWillUnmount() { + this.unsub(); + } + + _onBodyStoreEvent(evt) { + this.setState(this._getStateObject()) + } + + _getStateObject() { + return { + heightFormatted: BodyStore.GetHeightFormatted(), + }; + } + + render() { + return ( + + }/> + ); + } + + renderScene(route, navigator) { + return ( + + + + {this.state.heightFormatted} + + + + + + + + ); + } +} + +var NavigationBarRouteMapper = { + LeftButton(route, navigator, index, nextState) { + return ( + {navigator.parentNavigator.pop()}}> + + Back + + + ); + }, + RightButton(route, navigator, index, nextState) { + return null; + }, + Title(route, navigator, index, nextState) { + return ( + + + Height + + + ); + } +}; + + +module.exports = Height; +export default Height; diff --git a/examples/BodyMeasurements/app/components/leanBodyMass/leanBodyMass.js b/examples/BodyMeasurements/app/components/leanBodyMass/leanBodyMass.js new file mode 100644 index 0000000..f1a7ff1 --- /dev/null +++ b/examples/BodyMeasurements/app/components/leanBodyMass/leanBodyMass.js @@ -0,0 +1,98 @@ +/** + * Created by greg on 2016-06-27. + */ + + +import React, { Component } from 'react'; +import { + Navigator, + TouchableOpacity, + Text, + View +} from 'react-native'; + +import styles from '../../styles/styles'; +import BodyStore from '../../stores/body'; + + +class LeanBodyMass extends Component { + + constructor(props) { + super(props); + this.state = this._getStateObject(); + } + + componentDidMount() { + this.unsub = BodyStore.listen(this._onBodyStoreEvent.bind(this)); + } + + componentWillUnmount() { + this.unsub(); + } + + _onBodyStoreEvent(evt) { + this.setState(this._getStateObject()) + } + + _getStateObject() { + return { + leanBodyMassFormatted: BodyStore.GetLeanBodyMassFormatted(), + }; + } + + render() { + return ( + + }/> + ); + } + + renderScene(route, navigator) { + return ( + + + + {this.state.leanBodyMassFormatted} + + + + + + + + ); + } +} + +var NavigationBarRouteMapper = { + LeftButton(route, navigator, index, nextState) { + return ( + {navigator.parentNavigator.pop()}}> + + Back + + + ); + }, + RightButton(route, navigator, index, nextState) { + return null; + }, + Title(route, navigator, index, nextState) { + return ( + + + Lean Body Mass + + + ); + } +}; + + +module.exports = LeanBodyMass; +export default LeanBodyMass; diff --git a/examples/BodyMeasurements/app/components/weight/weight.js b/examples/BodyMeasurements/app/components/weight/weight.js new file mode 100644 index 0000000..b5b6eb8 --- /dev/null +++ b/examples/BodyMeasurements/app/components/weight/weight.js @@ -0,0 +1,97 @@ +/** + * Created by greg on 2016-06-27. + */ + +import React, { Component } from 'react'; +import { + Navigator, + TouchableOpacity, + Text, + View +} from 'react-native'; + +import styles from '../../styles/styles'; +import BodyStore from '../../stores/body'; + + +class Weight extends Component { + + constructor(props) { + super(props); + this.state = this._getStateObject(); + } + + componentDidMount() { + this.unsub = BodyStore.listen(this._onBodyStoreEvent.bind(this)); + } + + componentWillUnmount() { + this.unsub(); + } + + _onBodyStoreEvent(evt) { + this.setState(this._getStateObject()) + } + + _getStateObject() { + return { + weightFormatted: BodyStore.GetWeightFormatted(), + }; + } + + render() { + return ( + + }/> + ); + } + + renderScene(route, navigator) { + return ( + + + + {this.state.weightFormatted} + + + + + + + + ); + } +} + +var NavigationBarRouteMapper = { + LeftButton(route, navigator, index, nextState) { + return ( + {navigator.parentNavigator.pop()}}> + + Back + + + ); + }, + RightButton(route, navigator, index, nextState) { + return null; + }, + Title(route, navigator, index, nextState) { + return ( + + + Weight + + + ); + } +}; + + +module.exports = Weight; +export default Weight; diff --git a/examples/BodyMeasurements/app/stores/body.js b/examples/BodyMeasurements/app/stores/body.js new file mode 100644 index 0000000..fac6402 --- /dev/null +++ b/examples/BodyMeasurements/app/stores/body.js @@ -0,0 +1,308 @@ +/** + * Created by greg on 2016-06-27. + */ + + +var airflux = require( 'airflux' ); +var _ = require('lodash'); +var moment = require('moment'); +var Immutable = require('immutable'); +//var actions = require('../actions/actions'); + +var AppleHealthKit = require('react-native-apple-healthkit'); + +var DATA = { + weight: 0, + height: 0, + bmi: 0, + bodyFatPercentage: 0, + leanBodyMass: 0, + steps: 0, +}; + +/** + * @namespace Stores + */ + +/** + * @class WeightStore + * @classdesc Airflux store to handle data, actions, and events relating to the WeightStore + * @memberof Stores + */ +class BodyStore extends airflux.Store { + + /** + * Initialize the WeightStore, optionally with 'props' object + * @constructs Stores.TestingEventService + * @param {object} props - an optional properties object to initialize the store with + * + */ + constructor(props) { + //console.log("WeightStore props --> ", props); + super(props); + let self = this; + + //this.listenTo(actions.addWeight, this._onactn_addWeight) + + this._initHealthKit = this._initHealthKit.bind(this); + this._fetchHealthKitUserWeight = this._fetchHealthKitUserWeight.bind(this); + this._fetchHealthKitUserHeight = this._fetchHealthKitUserHeight.bind(this); + this._fetchHealthKitUserBmi = this._fetchHealthKitUserBmi.bind(this); + this._fetchHealthKitStepCountToday = this._fetchHealthKitStepCountToday.bind(this); + this._fetchHealthKitBodyFatPercentage = this._fetchHealthKitBodyFatPercentage.bind(this); + this._fetchHealthKitLeanBodyMass = this._fetchHealthKitLeanBodyMass.bind(this); + this.GetWeightValue = this.GetWeightValue.bind(this); + this.GetWeightFormatted = this.GetWeightFormatted.bind(this); + this.GetSteps = this.GetSteps.bind(this); + this.GetHeightFormatted = this.GetHeightFormatted.bind(this); + this.GetHeightValue = this.GetHeightValue.bind(this); + this.GetBMIValue = this.GetBMIValue.bind(this); + this.GetBMIFormatted = this.GetBMIFormatted.bind(this); + this.GetBodyFatPercentageValue = this.GetBodyFatPercentageValue.bind(this); + this.GetBodyFatPercentageFormatted = this.GetBodyFatPercentageFormatted.bind(this); + this.GetLeanBodyMassValue = this.GetLeanBodyMassValue.bind(this); + this.GetLeanBodyMassFormatted = this.GetLeanBodyMassFormatted.bind(this); + + AppleHealthKit.isAvailable((err,available) => { + console.log('AppleHealthKit.isAvailable(): ', available); + if(available){ + self._initHealthKit(); + } + }); + + //AppleHealthKit.getInfo({init:"true"}, (err,res) => { + // if(err) { + // console.log("ERROR GETTING HEALTHKIT MODULE INFO"); + // console.log(err); + // return; + // } + // console.log("HEALTHKIT MODULE INFO: ", res); + //}); + } + + + _initHealthKit() { + let self = this; + + let healthKitOptions = { + permissions: { + read: ["Height", "Weight", "Steps", "DateOfBirth", "BodyMassIndex", "LeanBodyMass", "BodyFatPercentage"], + write: ["Weight"] + } + }; + + AppleHealthKit.initHealthKit(healthKitOptions, (err, res) => { + if(this._handleHealthKitError(err, 'initHealthKit')){ + return; + } + console.log("HEALTHKIT INITIALIZED!! ", res); + + self._fetchHealthKitUserWeight(); + self._fetchHealthKitUserBmi(); + self._fetchHealthKitStepCountToday(); + self._fetchHealthKitUserHeight(); + self._fetchHealthKitBodyFatPercentage(); + self._fetchHealthKitLeanBodyMass(); + }); + } + + + _handleHealthKitError(err, method) : boolean { + if(err){ + let errStr = 'HealthKit_ERROR['+method+'] : '; + if(typeof err === 'string'){ + errStr += err; + } else if (typeof err === 'object' && err.message){ + errStr += err.message; + } + console.log(errStr); + return true; + } + return false; + } + + _onactn_addWeight(options) { + console.log('_onactn_addWeight() --> ', options); + if(options && options.weight){ + let weightVal = parseFloat(options.weight); + let self = this; + AppleHealthKit.saveWeight({weight:weightVal}, (err, res) => { + if(this._handleHealthKitError(err, 'saveWeight')){ + return; + } + DATA.weight = weightVal; + self.trigger({ + name: 'change:weight', + target: null, + data: DATA.weight + }); + }); + } + } + + + _fetchHealthKitUserWeight() { + let self = this; + AppleHealthKit.getCurrentWeight(null, (err, weight) => { + if(this._handleHealthKitError(err, 'getCurrentWeight')){ + return; + } + weight = _.round(weight,1); + + DATA.weight = weight; + self.trigger({ + name: 'change:weight', + target: null, + data: weight + }); + }); + } + + + _fetchHealthKitUserHeight() { + let self = this; + AppleHealthKit.getMostRecentHeight(null, (err, height) => { + if(this._handleHealthKitError(err, 'getMostRecentHeight')){ + return; + } + console.log("HEIGHT: ", height); + + if(typeof height === "number" && height > 0){ + DATA.height = height; + self.trigger({ + name: 'change:height', + target: null, + data: height + }); + } + }); + } + + + _fetchHealthKitUserBmi() { + let self = this; + AppleHealthKit.getLatestBmi({blah:true}, (err, bmi) => { + if(this._handleHealthKitError(err, 'getLatestBmi')){ + return; + } + console.log("LATEST BMI: ", bmi); + if(bmi && bmi.value){ + DATA.bmi = _.round(bmi.value,1); + self.trigger({ + name: 'change:bmi', + target: null, + data: DATA.bmi + }); + } + }); + } + + + _fetchHealthKitBodyFatPercentage() { + let self = this; + AppleHealthKit.getMostRecentBodyFatPercentage({blah:true}, (err, fatPercentage) => { + if(this._handleHealthKitError(err, 'getMostRecentBodyFatPercentage')){ + return; + } + console.log("BODY FAT PERCENTAGE: ", fatPercentage); + DATA.bodyFatPercentage = fatPercentage; + self.trigger({ + name: 'change:body_fat_percentage', + target: null, + data: DATA.bodyFatPercentage + }); + }); + } + + + _fetchHealthKitLeanBodyMass() { + let self = this; + AppleHealthKit.getMostRecentLeanBodyMass({blah:true}, (err, leanMass) => { + if(this._handleHealthKitError(err, 'getMostRecentLeanBodyMass')){ + return; + } + console.log("LEAN BODY MASS: ", leanMass); + DATA.leanBodyMass = _.round(leanMass,0); + self.trigger({ + name: 'change:lean_body_mass', + target: null, + data: DATA.leanBodyMass + }); + }); + } + + + + _fetchHealthKitStepCountToday() { + let self = this; + AppleHealthKit.getStepCountForToday({options:"true"}, (err, steps) => { + if(this._handleHealthKitError(err, 'getStepCountForToday')){ + return; + } + console.log("STEPS : ", steps); + steps = _.round(steps,0); + + DATA.steps = steps; + self.trigger({ + name: 'change:steps', + target: null, + data: steps + }); + }); + } + + + GetHeightValue() { + return DATA.height; + } + + GetHeightFormatted() { + let feet = _.floor((DATA.height / 12)); + let inches = DATA.height % 12; + let formatted = '' + feet + '\'' + inches + '"'; + return formatted; + } + + GetWeightValue() { + return DATA.weight; + } + + GetWeightFormatted() { + return DATA.weight + ' lbs'; + } + + GetBMIValue() { + return DATA.bmi; + } + + GetBMIFormatted() { + return '' + DATA.bmi; + } + + GetBodyFatPercentageValue() { + return DATA.bodyFatPercentage; + } + + GetBodyFatPercentageFormatted() { + return '' + DATA.bodyFatPercentage + '%'; + } + + GetLeanBodyMassValue() { + return DATA.leanBodyMass; + } + + GetLeanBodyMassFormatted() { + return '' + DATA.leanBodyMass + ' lbs'; + } + + + GetSteps() { + return DATA.steps; + } + +} + + +let storeInstance = new BodyStore(); +export default storeInstance; +module.exports = storeInstance; \ No newline at end of file diff --git a/examples/BodyMeasurements/app/styles/styles.js b/examples/BodyMeasurements/app/styles/styles.js new file mode 100644 index 0000000..d96fb7f --- /dev/null +++ b/examples/BodyMeasurements/app/styles/styles.js @@ -0,0 +1,186 @@ +/** + * Created by greg on 2016-06-27. + */ + +import { + Platform, + StyleSheet +} from 'react-native'; + + + +const styles = StyleSheet.create({ + + sceneContainerNavbar: { + flex: 1, + flexDirection: 'column', + //justifyContent: 'flex-start', + //alignItems: 'flex-start', + marginTop: (Platform.OS === 'ios') ? 64 : 54, + backgroundColor: '#FFFFFF' + }, + + navigationBar: { + borderBottomWidth: 1, + borderBottomColor: '#cccccc', + backgroundColor: '#f5f5f5' + }, + + navbarTitleTouchable: { + flex: 1, + justifyContent: 'center' + }, + navbarTitle: { + color: '#FD2D55', + margin: 10, + fontSize: 18 + }, + + + row_1_3: { + flex: 0.33, + flexDirection:'column', + padding:10, + //backgroundColor: '#FF8000' + }, + + row_2_3: { + flex: 0.66, + flexDirection:'column', + padding:10, + //backgroundColor: '#0088cc' + }, + + borderTopLightGrey: { + borderTopColor: '#CCCCCC', + borderTopWidth: 1, + }, + + largeCenteredText: { + textAlign: 'center', + flexDirection:'row', + fontSize:34, + marginTop:60, + }, + + dashboardListItemLabel: { + fontSize:12, + color: '#FD2D55', + position:'absolute', + left: 70, + top:0, + }, + + dashboardListItemValue: { + fontSize:22, + color: '#47a292', + position:'absolute', + left: 70, + top:15, + }, + + sceneContainerFull: { + flex: 1, + flexDirection: 'column', + //justifyContent: 'flex-start', + //alignItems: 'flex-start', + marginTop: 0, + backgroundColor: '#FFFFFF' + }, + + + dashboardToday: { + height: 30, + alignItems: 'stretch', + justifyContent: 'center', + alignItems: 'center', + backgroundColor: 'rgba(162, 162, 162, 0.2)', + }, + dashboardTodayText: { + + color: '#a2a2a2', + }, + + dashboardListItemHighlight: { + flexDirection: 'row', + alignSelf: 'stretch', + justifyContent: 'center', + //flex:1, + //alignSelf: 'stretch', + //overflow: 'hidden', + }, + + dashboardListItemView: { + flex: 1, + //backgroundColor: '#FDFDFD', + backgroundColor: '#FDFDFD', + //paddingTop:74, + //flexDirection: 'row', + flexDirection: 'column', + alignSelf: 'stretch', + justifyContent: 'flex-start', + alignItems: 'flex-start', + paddingTop:15, + paddingBottom: 15, + + //flexWrap: 'wrap', + + borderBottomColor: '#AAAAAA', + borderBottomWidth: 1, + }, + + dashboardListItemViewTransparent: { + flex: 1, + //backgroundColor: '#FDFDFD', + backgroundColor: 'transparent', + //paddingTop:74, + //flexDirection: 'row', + flexDirection: 'column', + alignSelf: 'stretch', + justifyContent: 'flex-start', + alignItems: 'flex-start', + paddingTop:15, + paddingBottom: 15, + + //flexWrap: 'wrap', + + borderBottomColor: '#AAAAAA', + borderBottomWidth: 1, + }, + + dashboardListItem: { + flexDirection: 'row', + alignSelf: 'stretch', + justifyContent: 'space-between', + flex:1, + backgroundColor: 'transparent', + }, + + + dashboardListItemIcon: { + width: 40, + height: 40, + marginLeft: 10, + opacity:0.7, + //marginTop: 50, + //backgroundColor: 'transparent', + alignSelf: 'flex-start', + }, + + dashboardListItemText: { + flex: 1, + flexDirection: 'column', + alignSelf: 'flex-start', + marginLeft: 20, + fontSize: 29, + color: '#47a292', + //color: '#98CA3F', + //color: '#644496', + flexWrap: 'wrap', + backgroundColor:'transparent', + }, + +}); + +module.exports = styles; +export default styles; diff --git a/examples/BodyMeasurements/index.ios.js b/examples/BodyMeasurements/index.ios.js index 3ca7816..4c771b7 100644 --- a/examples/BodyMeasurements/index.ios.js +++ b/examples/BodyMeasurements/index.ios.js @@ -13,67 +13,14 @@ import { View } from 'react-native'; - -let Index = require('./src/components/Index'); - +let App = require('./app/app'); class BodyMeasurements extends Component { render() { return ( - - ); - - // - // - //return ( - // - // - // Welcome to React Native! - // - // - // To get started, edit index.ios.js - // - // - // Press Cmd+R to reload,{'\n'} - // Cmd+D or shake for dev menu - // - // - //); + + ) } - - - renderScene(route, navigator) { - if(route.name == 'Index') { - return - } - //if(route.name == 'Home') { - // return - //} - } - - } -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - backgroundColor: '#F5FCFF', - }, - welcome: { - fontSize: 20, - textAlign: 'center', - margin: 10, - }, - instructions: { - textAlign: 'center', - color: '#333333', - marginBottom: 5, - }, -}); - AppRegistry.registerComponent('BodyMeasurements', () => BodyMeasurements); diff --git a/examples/BodyMeasurements/ios/BodyMeasurements.xcodeproj/project.pbxproj b/examples/BodyMeasurements/ios/BodyMeasurements.xcodeproj/project.pbxproj index 5ad2d79..49b92db 100644 --- a/examples/BodyMeasurements/ios/BodyMeasurements.xcodeproj/project.pbxproj +++ b/examples/BodyMeasurements/ios/BodyMeasurements.xcodeproj/project.pbxproj @@ -22,6 +22,8 @@ 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; + 37E9B8741D21B52F0090B19B /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 37E9B8731D21B52F0090B19B /* HealthKit.framework */; }; + 37E9B89D1D21C63C0090B19B /* libRCTAppleHealthKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 37E9B89C1D21C6380090B19B /* libRCTAppleHealthKit.a */; }; 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; /* End PBXBuildFile section */ @@ -89,6 +91,13 @@ remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; remoteInfo = React; }; + 37E9B89B1D21C6380090B19B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 37E9B8971D21C6380090B19B /* RCTAppleHealthKit.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3774C88D1D2092F20000B3F3; + remoteInfo = RCTAppleHealthKit; + }; 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; @@ -125,6 +134,9 @@ 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = BodyMeasurements/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = BodyMeasurements/main.m; sourceTree = ""; }; 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; + 37E9B8731D21B52F0090B19B /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; }; + 37E9B8751D21B52F0090B19B /* BodyMeasurements.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = BodyMeasurements.entitlements; path = BodyMeasurements/BodyMeasurements.entitlements; sourceTree = ""; }; + 37E9B8971D21C6380090B19B /* RCTAppleHealthKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAppleHealthKit.xcodeproj; path = "../node_modules/react-native-apple-healthkit/RCTAppleHealthKit.xcodeproj"; sourceTree = ""; }; 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -142,8 +154,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 37E9B89D1D21C63C0090B19B /* libRCTAppleHealthKit.a in Frameworks */, 146834051AC3E58100842450 /* libReact.a in Frameworks */, 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, + 37E9B8741D21B52F0090B19B /* HealthKit.framework in Frameworks */, 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */, 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */, 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */, @@ -234,6 +248,7 @@ 13B07FAE1A68108700A75B9A /* BodyMeasurements */ = { isa = PBXGroup; children = ( + 37E9B8751D21B52F0090B19B /* BodyMeasurements.entitlements */, 008F07F21AC5B25A0029DE68 /* main.jsbundle */, 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 13B07FB01A68108700A75B9A /* AppDelegate.m */, @@ -253,6 +268,14 @@ name = Products; sourceTree = ""; }; + 37E9B8981D21C6380090B19B /* Products */ = { + isa = PBXGroup; + children = ( + 37E9B89C1D21C6380090B19B /* libRCTAppleHealthKit.a */, + ); + name = Products; + sourceTree = ""; + }; 78C398B11ACF4ADC00677621 /* Products */ = { isa = PBXGroup; children = ( @@ -264,6 +287,7 @@ 832341AE1AAA6A7D00B99B32 /* Libraries */ = { isa = PBXGroup; children = ( + 37E9B8971D21C6380090B19B /* RCTAppleHealthKit.xcodeproj */, 146833FF1AC3E56700842450 /* React.xcodeproj */, 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */, 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */, @@ -289,6 +313,7 @@ 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( + 37E9B8731D21B52F0090B19B /* HealthKit.framework */, 13B07FAE1A68108700A75B9A /* BodyMeasurements */, 832341AE1AAA6A7D00B99B32 /* Libraries */, 00E356EF1AD99517003FC87E /* BodyMeasurementsTests */, @@ -359,6 +384,14 @@ CreatedOnToolsVersion = 6.2; TestTargetID = 13B07F861A680F5B00A75B9A; }; + 13B07F861A680F5B00A75B9A = { + DevelopmentTeam = 95ZTJFHCUG; + SystemCapabilities = { + com.apple.HealthKit = { + enabled = 1; + }; + }; + }; }; }; buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "BodyMeasurements" */; @@ -377,6 +410,10 @@ ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */; ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; }, + { + ProductGroup = 37E9B8981D21C6380090B19B /* Products */; + ProjectRef = 37E9B8971D21C6380090B19B /* RCTAppleHealthKit.xcodeproj */; + }, { ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */; ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; @@ -479,6 +516,13 @@ remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 37E9B89C1D21C6380090B19B /* libRCTAppleHealthKit.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTAppleHealthKit.a; + remoteRef = 37E9B89B1D21C6380090B19B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -605,6 +649,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = BodyMeasurements/BodyMeasurements.entitlements; DEAD_CODE_STRIPPING = NO; HEADER_SEARCH_PATHS = ( "$(inherited)", @@ -625,6 +670,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = BodyMeasurements/BodyMeasurements.entitlements; HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, diff --git a/examples/BodyMeasurements/ios/BodyMeasurements/BodyMeasurements.entitlements b/examples/BodyMeasurements/ios/BodyMeasurements/BodyMeasurements.entitlements new file mode 100644 index 0000000..e10f430 --- /dev/null +++ b/examples/BodyMeasurements/ios/BodyMeasurements/BodyMeasurements.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.developer.healthkit + + + diff --git a/examples/BodyMeasurements/ios/BodyMeasurements/Info.plist b/examples/BodyMeasurements/ios/BodyMeasurements/Info.plist index 970fc6a..1680bf7 100644 --- a/examples/BodyMeasurements/ios/BodyMeasurements/Info.plist +++ b/examples/BodyMeasurements/ios/BodyMeasurements/Info.plist @@ -23,11 +23,10 @@ LSRequiresIPhoneOS NSAppTransportSecurity - - - NSAllowsArbitraryLoads - - + + NSAllowsArbitraryLoads + + NSLocationWhenInUseUsageDescription UILaunchStoryboardName @@ -35,6 +34,7 @@ UIRequiredDeviceCapabilities armv7 + healthkit UISupportedInterfaceOrientations diff --git a/examples/BodyMeasurements/package.json b/examples/BodyMeasurements/package.json index 66c304e..42c0e99 100644 --- a/examples/BodyMeasurements/package.json +++ b/examples/BodyMeasurements/package.json @@ -6,7 +6,10 @@ "start": "node node_modules/react-native/local-cli/cli.js start" }, "dependencies": { + "airflux": "^0.5.1", "react": "15.1.0", - "react-native": "^0.28.0" + "react-mixin": "^2.0.2", + "react-native": "^0.28.0", + "react-native-apple-healthkit": "file:///Users/greg/Dev/experimental/RCTAppleHealthKit" } } -- 2.26.2