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 6f0090e..0000000 Binary files a/zcash-android-wallet-app/app/src/main/res/drawable/empty_wallet.png and /dev/null differ 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'