From 4ec6b60398b96a8fafa26a0180b962911d60e715 Mon Sep 17 00:00:00 2001 From: Kevin Gorham Date: Wed, 5 Dec 2018 02:26:03 -0500 Subject: [PATCH] receive screen: qr code functional next step is to add the numbering to the address parts and then add the real values for the QR code and the address. After that, this screen is complete. --- zcash-android-wallet-app/app/build.gradle | 3 +- .../di/component/ApplicationComponent.kt | 8 +- .../wallet/di/module/ApplicationModule.kt | 10 +- .../wallet/ui/fragment/BaseFragment.kt | 24 +++++ .../wallet/ui/fragment/HomeFragment.kt | 16 ++- .../wallet/ui/fragment/ReceiveFragment.kt | 92 ++++-------------- .../src/main/res/drawable/empty_wallet.png | Bin 6156 -> 0 bytes .../src/main/res/drawable/ic_emptywallet.xml | 80 +++++++++++++++ .../src/main/res/drawable/ic_zcash_white.xml | 24 +++++ .../app/src/main/res/layout/fragment_home.xml | 2 +- .../src/main/res/layout/fragment_receive.xml | 21 +++- zcash-android-wallet-app/qrecycler/.gitignore | 1 + .../qrecycler/build.gradle | 37 +++++++ .../qrecycler/proguard-rules.pro | 21 ++++ .../qrecycler/ExampleInstrumentedTest.java | 26 +++++ .../qrecycler/src/main/AndroidManifest.xml | 2 + .../cash/z/android/qrecycler/QRecycler.kt | 46 +++++++++ .../qrecycler/src/main/res/values/strings.xml | 3 + .../z/android/qrecycler/ExampleUnitTest.java | 17 ++++ zcash-android-wallet-app/settings.gradle | 2 +- 20 files changed, 344 insertions(+), 91 deletions(-) create mode 100644 zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/ui/fragment/BaseFragment.kt delete mode 100755 zcash-android-wallet-app/app/src/main/res/drawable/empty_wallet.png create mode 100644 zcash-android-wallet-app/app/src/main/res/drawable/ic_emptywallet.xml create mode 100644 zcash-android-wallet-app/app/src/main/res/drawable/ic_zcash_white.xml create mode 100644 zcash-android-wallet-app/qrecycler/.gitignore create mode 100644 zcash-android-wallet-app/qrecycler/build.gradle create mode 100644 zcash-android-wallet-app/qrecycler/proguard-rules.pro create mode 100644 zcash-android-wallet-app/qrecycler/src/androidTest/java/cash/z/android/qrecycler/ExampleInstrumentedTest.java create mode 100644 zcash-android-wallet-app/qrecycler/src/main/AndroidManifest.xml create mode 100644 zcash-android-wallet-app/qrecycler/src/main/java/cash/z/android/qrecycler/QRecycler.kt create mode 100644 zcash-android-wallet-app/qrecycler/src/main/res/values/strings.xml create mode 100644 zcash-android-wallet-app/qrecycler/src/test/java/cash/z/android/qrecycler/ExampleUnitTest.java diff --git a/zcash-android-wallet-app/app/build.gradle b/zcash-android-wallet-app/app/build.gradle index 61793f3..a1f2c55 100644 --- a/zcash-android-wallet-app/app/build.gradle +++ b/zcash-android-wallet-app/app/build.gradle @@ -52,10 +52,11 @@ dependencies { kapt deps.dagger.android.processor kapt deps.dagger.compiler - // FAB speed dial + // Other implementation deps.speeddial testImplementation deps.junit androidTestImplementation deps.androidx.test.runner androidTestImplementation deps.androidx.test.espresso + compile project(path: ':qrecycler') } diff --git a/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/di/component/ApplicationComponent.kt b/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/di/component/ApplicationComponent.kt index 3c82a48..8f203d6 100644 --- a/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/di/component/ApplicationComponent.kt +++ b/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/di/component/ApplicationComponent.kt @@ -3,6 +3,8 @@ package cash.z.android.wallet.di.component import cash.z.android.wallet.ui.activity.MainActivityModule import cash.z.android.wallet.ZcashWalletApplication import cash.z.android.wallet.di.module.ApplicationModule +import cash.z.android.wallet.ui.fragment.HomeFragmentModule +import cash.z.android.wallet.ui.fragment.ReceiveFragmentModule import dagger.Component import dagger.android.AndroidInjector import dagger.android.support.AndroidSupportInjectionModule @@ -15,9 +17,11 @@ import javax.inject.Singleton @Singleton @Component( modules = [ - MainActivityModule::class, AndroidSupportInjectionModule::class, - ApplicationModule::class + ApplicationModule::class, + MainActivityModule::class, + HomeFragmentModule::class, + ReceiveFragmentModule::class ] ) interface ApplicationComponent : AndroidInjector { diff --git a/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/di/module/ApplicationModule.kt b/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/di/module/ApplicationModule.kt index 8b1e6aa..3ba5da3 100644 --- a/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/di/module/ApplicationModule.kt +++ b/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/di/module/ApplicationModule.kt @@ -1,15 +1,19 @@ package cash.z.android.wallet.di.module +import cash.z.android.qrecycler.QRecycler import dagger.Module import dagger.Provides -import javax.inject.Singleton /** * Module that contributes all the objects with application scope. Anything that should live globally belongs here. */ @Module -class ApplicationModule { - @Singleton +internal object ApplicationModule { + @JvmStatic @Provides fun provideSanity(): SanityCheck = SanityCheck(true) + + @JvmStatic + @Provides + fun provideQRecycler(): QRecycler = QRecycler() } \ No newline at end of file diff --git a/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/ui/fragment/BaseFragment.kt b/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/ui/fragment/BaseFragment.kt new file mode 100644 index 0000000..292a6e8 --- /dev/null +++ b/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/ui/fragment/BaseFragment.kt @@ -0,0 +1,24 @@ +package cash.z.android.wallet.ui.fragment + +import android.content.Context +import androidx.fragment.app.Fragment +import dagger.android.AndroidInjector +import dagger.android.DispatchingAndroidInjector +import dagger.android.support.AndroidSupportInjection +import dagger.android.support.HasSupportFragmentInjector +import javax.inject.Inject + +abstract class BaseFragment : Fragment(), HasSupportFragmentInjector { + + @Inject + internal lateinit var childFragmentInjector: DispatchingAndroidInjector + + override fun onAttach(context: Context) { + AndroidSupportInjection.inject(this) + super.onAttach(context) + } + + override fun supportFragmentInjector(): AndroidInjector? { + return childFragmentInjector + } +} diff --git a/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/ui/fragment/HomeFragment.kt b/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/ui/fragment/HomeFragment.kt index 7db26f6..a4ccfb3 100644 --- a/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/ui/fragment/HomeFragment.kt +++ b/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/ui/fragment/HomeFragment.kt @@ -10,20 +10,22 @@ import androidx.annotation.DrawableRes import androidx.annotation.IdRes import androidx.annotation.StringRes import androidx.core.content.res.ResourcesCompat -import androidx.fragment.app.Fragment +import androidx.core.view.doOnLayout import cash.z.android.wallet.R +import cash.z.android.wallet.di.module.SanityCheck import cash.z.android.wallet.ui.activity.MainActivity import cash.z.wallet.sdk.jni.JniConverter import com.leinardi.android.speeddial.SpeedDialActionItem +import dagger.Module +import dagger.android.ContributesAndroidInjector import kotlinx.android.synthetic.main.fragment_home.* - +import javax.inject.Inject /** * Fragment representing the home screen of the app. This is the screen most often seen by the user when launching the * application. */ -class HomeFragment : Fragment() { - +class HomeFragment : BaseFragment() { // TODO: remove this test object. it is currently just used to exercise the rust code var converter: JniConverter = JniConverter() @@ -120,3 +122,9 @@ class HomeFragment : Fragment() { } } + +@Module +abstract class HomeFragmentModule { + @ContributesAndroidInjector + abstract fun contributeHomeFragment(): HomeFragment +} \ No newline at end of file diff --git a/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/ui/fragment/ReceiveFragment.kt b/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/ui/fragment/ReceiveFragment.kt index d692a22..7c81c7a 100644 --- a/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/ui/fragment/ReceiveFragment.kt +++ b/zcash-android-wallet-app/app/src/main/java/cash/z/android/wallet/ui/fragment/ReceiveFragment.kt @@ -1,21 +1,18 @@ package cash.z.android.wallet.ui.fragment -import android.content.Context -import android.net.Uri import android.os.Bundle -import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.fragment.app.Fragment +import cash.z.android.qrecycler.QRecycler import cash.z.android.wallet.R import cash.z.android.wallet.ui.activity.MainActivity +import dagger.Module +import dagger.android.ContributesAndroidInjector import kotlinx.android.synthetic.main.fragment_home.* - - -// TODO: Rename parameter arguments, choose names that match -// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER -private const val ARG_PARAM1 = "param1" -private const val ARG_PARAM2 = "param2" +import kotlinx.android.synthetic.main.fragment_receive.* +import javax.inject.Inject /** * A simple [Fragment] subclass. @@ -26,19 +23,10 @@ private const val ARG_PARAM2 = "param2" * create an instance of this fragment. * */ -class ReceiveFragment : Fragment() { - // TODO: Rename and change types of parameters - private var param1: String? = null - private var param2: String? = null - private var listener: OnFragmentInteractionListener? = null +class ReceiveFragment : BaseFragment() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - arguments?.let { - param1 = it.getString(ARG_PARAM1) - param2 = it.getString(ARG_PARAM2) - } - } + @Inject + lateinit var qrecycler: QRecycler override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -52,60 +40,14 @@ class ReceiveFragment : Fragment() { super.onViewCreated(view, savedInstanceState) (activity as MainActivity).setSupportActionBar(toolbar) (activity as MainActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true) + + qrecycler.load("https://z.cash").into(receive_qr_code) } - // TODO: Rename method, update argument and hook method into UI event - fun onButtonPressed(uri: Uri) { - listener?.onFragmentInteraction(uri) - } - - override fun onAttach(context: Context) { - super.onAttach(context) - if (context is OnFragmentInteractionListener) { - listener = context - } else { -// throw RuntimeException(context.toString() + " must implement OnFragmentInteractionListener") - } - } - - override fun onDetach() { - super.onDetach() - listener = null - } - - /** - * This interface must be implemented by activities that contain this - * fragment to allow an interaction in this fragment to be communicated - * to the activity and potentially other fragments contained in that - * activity. - * - * - * See the Android Training lesson [Communicating with Other Fragments] - * (http://developer.android.com/training/basics/fragments/communicating.html) - * for more information. - */ - interface OnFragmentInteractionListener { - // TODO: Update argument type and name - fun onFragmentInteraction(uri: Uri) - } - - companion object { - /** - * Use this factory method to create a new instance of - * this fragment using the provided parameters. - * - * @param param1 Parameter 1. - * @param param2 Parameter 2. - * @return A new instance of fragment ReceiveFragment. - */ - // TODO: Rename and change types and number of parameters - @JvmStatic - fun newInstance(param1: String, param2: String) = - ReceiveFragment().apply { - arguments = Bundle().apply { - putString(ARG_PARAM1, param1) - putString(ARG_PARAM2, param2) - } - } - } +} + +@Module +abstract class ReceiveFragmentModule { + @ContributesAndroidInjector + abstract fun contributeReceiveFragment(): ReceiveFragment } diff --git a/zcash-android-wallet-app/app/src/main/res/drawable/empty_wallet.png b/zcash-android-wallet-app/app/src/main/res/drawable/empty_wallet.png deleted file mode 100755 index 6f0090e962a6d07a2824be11fa642f96b2be7f99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6156 zcmb7oRa6uVv^A-;Gj#XRA>A?3E!|y`G7McGB8`A_s36@9BaAeIbmtI5cb6i0{r{Ky zd>_uf{cz&mYO4_9QRAVZp%JR7D(d~?+JBXZ^Wq=!34{Iq5tcJp3yg-= zkc|Iei;adx(Wj;eHV8mJvBdvuFqiXmR<$P7HyS>84%jXs;;XHf7Pb3a&ciDIiNLMc zNQqRecocI)5ShMHJYU>+%I3CdU!*Hw1k8w=jW;3~a&?NUAX^xSC?t4|gDHf8DU+Oc z+8LUE|GWxy4hn+D9OQ+qoXYwij<@|;37+^n;oo`x=f9_5dfIwkXB=9YAfFGVF3S>0 zU*hj)pu3}ijLtb3ro9$98De$)GCup0=%eTA-1@9%hi%ZkPTOxyuc27CqYREZRygRa zhwZn)#1mU}4O`a$8-&)Yy5>_+E$ASBt}Ug)_>B6eRcS1AH(-01uW zH$$9;`)L^$f|R})V2}R$N+P){bLaxu7i1{b{FICkZL6$qc4gmQ3u!jB*YZy zjHsVxQ2cUUc-!hucP0JY)Y_aBES+Zw*|V2DK0OV?+Q|pz13GE%&zmmoFCZlW7Dk9~ z63|^>H6nk&nAIo*v=k{9pFA=z;8*z8?T!S9qT!RpNaLN2yWiB%xkfxa+qt8V!un>vF-pV?(i znee%M)nP0{+EK*~&f78H*?|a5U+?ub; zYzByRIE_@n!wzrI#NYL`Kkoy_vRaQ`edCX%b#ZVF-pqCS2w1whP(a&#EXA!A9{%My zhJ{WP6tGTz`LJ3BqX*i#ZRXZ27~kXx|Hj=&YRj2L4`zd6i4(zsjl$r_T1z&M zZz zf0i!pv})ysfody<@qM+n;QgHI?Ey@xb4}oLO*8;)ltR_0cd01$xK7JlQa|iulJ1%o z2P@kpn=$AY<|L|%%9Zkys@Q%?-n(~-UWhhRQA`V7%1aXO74^~mrw0eoI}3NU6@|L- znr`M|ck# zMKcgDy&Xi@@U`i7=VX{uLWIHvoa_Ro5a$@TY%2Pb1en_QER$h;1Sj8G?H9@F%Zxf9 zzXMyn?I1t#sUSj(o{cJsc`=+@t5bA*3I9NFqbQAxM|pt=+cL()sh(Ex&NB zJGn9&D!+K$LPO<+x`H*MCVpnugcP{iB02zXBs%$UX=inSMfbcK_Br1!kIu(8aN6&z zaJ2JAo?a4X89ea6VDU_f%Tc@3cf~U4LSTw*)y7DICH~-Ef!NVpmOT@3y)$<>1NjFD z_wu|6V;>n*hlyiZqnr?081buxH9P9U}pzo~Jhi?Z1&cD6l zWcp*x70J{~KiWS?qs?~jbp9Km!VH+g)&mJqQ9=?vwX)Wl1gZhmzgec_Nb&p(*aeA9 z!@;%G!V;f#!{~Kis&Smw`F?7pG7Q~d2-@wIUc7*PO<|NX38S62MCD91`31)2;Q3X= z3GZYZSfUJ#Q6)NQJbv(wCG-C;evpvNq$}}U<=TsS=0-M*oLsTJ_~1UL39DjroG%|? zt+SBni~Yjw0R4KJKCC(=R{sk_H|Kf%6Sm}UcP5|>f|vD<=j;=(o(w`mO&y7C4huke zRMBNY;ub%es)Qd#9M))YY4noy5e#JMfqLxsU7?@N&rSuWT$DB4$oQgTm-PD1Y0o26ff{ z);5I)nYFex2;8$slX#7BLbCYZllG-e1V7xHTgu;w?Dea0&`FKaU^E|t<j*`}_L90KnD|=cmuZRWuR`L(hfHM4BC!cw%=~*Xbr+ zGov_-$dmH&^Jbq4&r(Z$V?)X>LT50pbJH>+Nh6oUtdCWt8n3qsrv>l(m{3tDoCS*0 zb|DK2oXAGC^=be`nfV@hZO1?;sX-m8WO|YV1_CnzMAwJph9|F+2yA@=R8G0e;_E$H zUXqVBvWaV@ssfd<-=@%!h1O!b!LZhr9}UE55}p$OVq%H3Kl$}p&T&!iJM57%)dm9p zV!19vs|2q{$ra^G;<~8e}gnh`11qTh0mNyDw{_qmAb z8t%!La)0NDZo4w)-_36Qhtt=RCAHoN|5Q1sJ`XFf#t-zYG^i@@yof5c0` zQZRNvyG?vEBA1ou4!T9ef9u|`CQr*!n;6~BLcGAtdqwS_9XG=ED)oG3Lc4ot##u$v zeeHve{G1&_?x7bBoIB~3MK-%C;p3TQtv6*VAH+j=TT9J?`Q+?3LlqyEOQ0-NYzRQ= z?j`8*6%F4BA&vQ>7VG(p|AGAO%@DD!9p*rk(IyiKs^GaMhD3IlQ_5@ zp7@{fm+1qEB_$_RO3oRb#X=j-wc=IdlR**@u8gLa;((X>B8#b#xOJvKkOR2l)CKZ1 zItkGklYVnPKzcY5|GAx;^09j|td!(w2TAcE1TGy!OzQhiMThxs9}U;~CPeK<-6{oF z3Gci2y@o2?LR>5SOeLT%_AaFB(@| z;|)E(TIRCZdFcIu+Y?J{KwTm+DWYcjpWvFNxF=(0S) zed`u(*sbv%39b$E+&o-s@Q~ly1USU~0-93b(G^-3Y!7INH<0OWZMiEg$(zJ%Ig`mR zXUb+`t=+mG>fn!I59hb4(Y82HO}3uO_J}pd*{tf-zdnrFK&svplgV@I{f@SKLKTY@ z1Jxdx4URLFAEOKZ zdP>YpuM>~oWqxQzg4MC=izX_HpS2gIh1NG7QnOKXFT{P-c2$1q| zG}LIR9ecByqisc5;Pb-TmY|W$iyv$LAI~p$}L%jgxyf06o*3#Es zIuefQVT`kP$o#tfwn1kvGo{LH-|#EpUIysZ-N-ndGDmz2Yq;tgwS$u_!hCj%8 zirYU8lr)fJyt{-tx2rP4DmRNl7-BZV6i!_+P3W<%psYw#z$qZEK#)u=uI@zP>R|k7 zw9rB0?0W|{^TagJS;<&YNbjgZT0{8Papz58taa);hLyYy%MQN?9rK;-jHu{Z&4p&w zC|gQh5w~pR+4g!(f*|$v{xIUSoDKA{WqfQ}0zs3{wkj*(HFC##aVh}ke#yON9Bnu2 z+a4_mjNq%fl8$#5oAlh9*F%-J=UlCjujU=P+p}Gw!j8G6!=87aRGGg=M|*JqR(Vrm zTgSr^kL7;*qXH#-2=&%p$zLPQ0y?TcnsZS)*O&VViSBTj_L#)xgnV zh?X(iQSNa)b=c7MXI2$Wmb9FyHMH%^#k7+&Kj`WL!&O(BCQL7hL~-iDW)HeoX!gQ6 zskT@xK%=euAk$-}Mg7G1u&sq&w~dJAznk(LcGt?(#v^ugPBlJZp|>o5&bE>3-s?l% z6o(IMay$8J-YYymbz(h}na-9Qip1`M#k6vGxA3?=wL*?joePk#d#lAHAB4>O?R{Cx zFesrk$BphQ{F6||$Yh#;)r>tamY_J9VbWmdIq* zh}m^oBo%{3W2w!Ts!RRf^65%9@Ym^P2P)9=P4%2 zy>xM$9#?e*)6yPPx#5-n%O3p>6y1EjO9;}`uNdT2M0=tVD8Dr=QA=*(ScabVC`caq zRv&bg97gC_enTaO^PNxr#|kKyEm)J~#z23HNki3}S<++Q+NgK8Rb~Ep`mf0pW-1t+ zb&4*q>)?R?Xo?9@(s0DPJunY<&)E}ag?$gWTu9aAuZML-`SO9EJuL`@x(y?Jvu?12o zR_E~>Yj-Vf1RT)y>x2poe;+L3veU|#Tz+`CQYdw1P_|IV&4N{PTnlR!aRGl;Yy-x&U3$;AJ)K(@qleX6%pY_XepF-pyiUmY(_c@S>IQwY1r$-ysnC7?kT z-Gqyz7q1%ZqvdOXjHketX(^eP+DO9swl-w@edZTtkG+pXbCYSr(hI#!*CQn8hp^Ve z;e%E22B^A}90-Cd$b4o=GcRzN$^IXno-6ao@LdHQuA4F%b!-ltV2iGduhSr#W&&Z zrdF8|XD4A?(&W8n2aeT{8Y~W0FzUaPgGrwKEB&L_Pt;OQH~{uo8bpfw=S;v@{4cHQ z-00{R1!EiMjS%;^!Sn@*#8+QRIeJP!>oVAoNHiqP|#4{S7R=P(@VX9#B@sl#tYesD&~ha!wlKK z`bIX(vb!zz7YY5gceM#rw06L-C_Y~K`#HBJ8OuJ4#}`ityrOuaM&lpUk$N~V^zto( zP!lt-AZ6lUFF!fE(!jo)Bmz8FYvx<5M+$2ycwYv$z|0NBTZZA5NW4>YgnWVxDM|t$PxtW&)Fk^Vq^d#Y2Z()@O&@8t@as2 zmbiL1q81vGXwefzC(~XUAfa@)6*z-%t>po30 Us|2Bc?|n2iC2hspH#QOf1H2H(umAu6 diff --git a/zcash-android-wallet-app/app/src/main/res/drawable/ic_emptywallet.xml b/zcash-android-wallet-app/app/src/main/res/drawable/ic_emptywallet.xml new file mode 100644 index 0000000..473ad84 --- /dev/null +++ b/zcash-android-wallet-app/app/src/main/res/drawable/ic_emptywallet.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + diff --git a/zcash-android-wallet-app/app/src/main/res/drawable/ic_zcash_white.xml b/zcash-android-wallet-app/app/src/main/res/drawable/ic_zcash_white.xml new file mode 100644 index 0000000..1e8c526 --- /dev/null +++ b/zcash-android-wallet-app/app/src/main/res/drawable/ic_zcash_white.xml @@ -0,0 +1,24 @@ + + + + + diff --git a/zcash-android-wallet-app/app/src/main/res/layout/fragment_home.xml b/zcash-android-wallet-app/app/src/main/res/layout/fragment_home.xml index 20c0e40..8a56186 100644 --- a/zcash-android-wallet-app/app/src/main/res/layout/fragment_home.xml +++ b/zcash-android-wallet-app/app/src/main/res/layout/fragment_home.xml @@ -28,7 +28,7 @@ android:id="@+id/image_empty_wallet" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:src="@drawable/empty_wallet" + app:srcCompat="@drawable/ic_emptywallet" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/zcash-android-wallet-app/app/src/main/res/layout/fragment_receive.xml b/zcash-android-wallet-app/app/src/main/res/layout/fragment_receive.xml index eba135c..3cf3938 100644 --- a/zcash-android-wallet-app/app/src/main/res/layout/fragment_receive.xml +++ b/zcash-android-wallet-app/app/src/main/res/layout/fragment_receive.xml @@ -3,7 +3,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:fillViewport="true"> + + Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("cash.z.android.qrecycler.test", appContext.getPackageName()); + } +} diff --git a/zcash-android-wallet-app/qrecycler/src/main/AndroidManifest.xml b/zcash-android-wallet-app/qrecycler/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2cbf62f --- /dev/null +++ b/zcash-android-wallet-app/qrecycler/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/zcash-android-wallet-app/qrecycler/src/main/java/cash/z/android/qrecycler/QRecycler.kt b/zcash-android-wallet-app/qrecycler/src/main/java/cash/z/android/qrecycler/QRecycler.kt new file mode 100644 index 0000000..e025dd5 --- /dev/null +++ b/zcash-android-wallet-app/qrecycler/src/main/java/cash/z/android/qrecycler/QRecycler.kt @@ -0,0 +1,46 @@ +package cash.z.android.qrecycler + +import android.graphics.Bitmap +import android.graphics.Color +import android.widget.ImageView +import androidx.core.view.doOnLayout +import com.google.zxing.BarcodeFormat +import com.google.zxing.EncodeHintType.ERROR_CORRECTION +import com.google.zxing.EncodeHintType.MARGIN +import com.google.zxing.qrcode.QRCodeWriter +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.Q + + +class QRecycler { + fun load(content: String): Builder { + return Builder(content) + } + + fun encode(builder: Builder) { + builder.target.doOnLayout { measuredView -> + val w = measuredView.width + val h = measuredView.height + val hints = mapOf(ERROR_CORRECTION to Q, MARGIN to 2) + val bitMatrix = QRCodeWriter().encode(builder.content, BarcodeFormat.QR_CODE, w, h, hints) + val pixels = IntArray(w * h) + for (y in 0 until h) { + val offset = y * w + for (x in 0 until w) { + pixels[offset + x] = if (bitMatrix.get(x, y)) Color.TRANSPARENT else Color.WHITE + } + } + // TODO: RECYCLE THIS BITMAP MEMORY!!! Do it in a way that is lifecycle-aware and disposes of the memory when the fragment is off-screen + val bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888) + bitmap.setPixels(pixels, 0, w, 0, 0, w, h) + (measuredView as ImageView).setImageBitmap(bitmap) + } + } + + inner class Builder(val content: String) { + lateinit var target: ImageView + fun into(imageView: ImageView) { + target = imageView + encode(this) + } + } +} diff --git a/zcash-android-wallet-app/qrecycler/src/main/res/values/strings.xml b/zcash-android-wallet-app/qrecycler/src/main/res/values/strings.xml new file mode 100644 index 0000000..2ec784d --- /dev/null +++ b/zcash-android-wallet-app/qrecycler/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + QRecycler + diff --git a/zcash-android-wallet-app/qrecycler/src/test/java/cash/z/android/qrecycler/ExampleUnitTest.java b/zcash-android-wallet-app/qrecycler/src/test/java/cash/z/android/qrecycler/ExampleUnitTest.java new file mode 100644 index 0000000..a8d3b97 --- /dev/null +++ b/zcash-android-wallet-app/qrecycler/src/test/java/cash/z/android/qrecycler/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package cash.z.android.qrecycler; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/zcash-android-wallet-app/settings.gradle b/zcash-android-wallet-app/settings.gradle index e7b4def..74e3e50 100644 --- a/zcash-android-wallet-app/settings.gradle +++ b/zcash-android-wallet-app/settings.gradle @@ -1 +1 @@ -include ':app' +include ':app', ':qrecycler'