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.
This commit is contained in:
parent
7b16819a26
commit
4ec6b60398
|
@ -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')
|
||||
}
|
||||
|
|
|
@ -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<ZcashWalletApplication> {
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -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<Fragment>
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
AndroidSupportInjection.inject(this)
|
||||
super.onAttach(context)
|
||||
}
|
||||
|
||||
override fun supportFragmentInjector(): AndroidInjector<Fragment>? {
|
||||
return childFragmentInjector
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 6.0 KiB |
|
@ -0,0 +1,80 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="174dp"
|
||||
android:height="141dp"
|
||||
android:viewportWidth="174"
|
||||
android:viewportHeight="141">
|
||||
<path
|
||||
android:pathData="M0,100.5a87,40.5 0,1 0,174 0a87,40.5 0,1 0,-174 0z"
|
||||
android:strokeAlpha="0.09"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#2A4E5D"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillAlpha="0.09"/>
|
||||
<path
|
||||
android:pathData="M89.232,0L89.232,0A2.232,2.232 0,0 1,91.464 2.232L91.464,11.161A2.232,2.232 0,0 1,89.232 13.393L89.232,13.393A2.232,2.232 0,0 1,87 11.161L87,2.232A2.232,2.232 0,0 1,89.232 0z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#D8D8D8"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M116.875,8.391L116.875,8.391C117.897,9.08 118.167,10.468 117.478,11.49L112.485,18.892C111.796,19.914 110.408,20.184 109.386,19.494L109.386,19.494C108.364,18.805 108.095,17.418 108.784,16.396L113.777,8.993C114.466,7.971 115.853,7.702 116.875,8.391Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#D8D8D8"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M59.877,8.039L59.877,8.039C60.945,7.423 62.31,7.789 62.927,8.856L67.391,16.589C68.007,17.656 67.641,19.022 66.574,19.638L66.574,19.638C65.506,20.254 64.141,19.889 63.525,18.821L59.06,11.089C58.444,10.021 58.81,8.656 59.877,8.039Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#D8D8D8"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M45.893,32.143L126.303,32.143A8,8 0,0 1,134.303 40.143L134.303,86.643A8,8 0,0 1,126.303 94.643L45.893,94.643A8,8 0,0 1,37.893 86.643L37.893,40.143A8,8 0,0 1,45.893 32.143z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#CC9B1F"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M45.893,30.143L126.303,30.143A8,8 0,0 1,134.303 38.143L134.303,81.643A8,8 0,0 1,126.303 89.643L45.893,89.643A8,8 0,0 1,37.893 81.643L37.893,38.143A8,8 0,0 1,45.893 30.143z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#FFD970"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M45.893,32.143L126.303,32.143A8,8 0,0 1,134.303 40.143L134.303,83.643A8,8 0,0 1,126.303 91.643L45.893,91.643A8,8 0,0 1,37.893 83.643L37.893,40.143A8,8 0,0 1,45.893 32.143z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#F4B728"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M60,46.429h63.393v4.464h-63.393z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#2A4E5D"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M60,58.929h63.393v4.464h-63.393z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#2A4E5D"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M44.939,37.629L99.76,49.681C103.561,50.434 106.326,51.926 108.054,54.156C109.782,56.386 110.646,58.912 110.646,61.735L110.646,104.856C110.025,108.213 108.895,110.422 107.257,111.483C105.618,112.544 103.119,113.077 99.76,113.081L48.539,102.492C45.358,101.713 42.694,100.36 40.545,98.432C38.397,96.504 37.608,94.713 38.18,93.061L37.668,38.822C38.322,37.151 38.84,36.058 39.222,35.544C39.604,35.029 40.33,34.336 41.399,33.466C42.571,32.731 42.859,32.582 42.263,33.02C41.369,33.676 41.017,34.208 41.017,35.242C41.017,35.931 42.325,36.727 44.939,37.629Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#FFD970"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M38.954,37L40.545,90C40.545,94.667 42.027,97.333 44.99,98C62.321,101.9 104,111.483 108,109.302C111.245,107.532 107.518,111.314 107.257,111.483C105.618,112.544 103.119,113.077 99.76,113.081L48.539,102.492C44.912,101.947 42.131,100.783 40.196,99C38.261,97.217 37.414,95.088 37.657,92.612L37.657,38.734C37.694,36.455 38.126,34.826 38.954,33.845C40.196,32.374 40.79,31.843 39.96,33.239C39.406,34.169 39.071,35.423 38.954,37Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#F5C642"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M97.141,85.556C99.87,85.995 102.371,84 102.727,81.099C103.083,78.198 101.16,75.49 98.43,75.051C95.701,74.612 93.2,76.608 92.844,79.509C92.488,82.41 94.412,85.117 97.141,85.556Z"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#E7EAEB"
|
||||
android:strokeColor="#607D89"
|
||||
android:fillType="nonZero"/>
|
||||
</vector>
|
|
@ -0,0 +1,24 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="451dp"
|
||||
android:height="451dp"
|
||||
android:viewportWidth="451"
|
||||
android:viewportHeight="451">
|
||||
<path
|
||||
android:pathData="M225.4,0C101.11,0 0,101.11 0,225.39C0,349.67 101.11,450.79 225.4,450.79C349.69,450.79 450.79,349.68 450.79,225.39C450.79,101.1 349.68,0 225.4,0ZM225.4,401.79C128.131,401.79 49,322.659 49,225.39C49,128.122 128.131,49 225.4,49C322.668,49 401.79,128.131 401.79,225.39C401.79,322.65 322.659,401.79 225.4,401.79Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#231F20"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M225.4,225.39m-177.65,0a177.65,177.65 0,1 1,355.3 0a177.65,177.65 0,1 1,-355.3 0"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M305.78,155.13l0,-34.38l-61.5,0l0,-37.73l-37.77,0l0,37.73l-61.49,0l0,45.54l95.33,0l-77.96,107.29l-17.37,22.08l0,34.38l61.49,0l0,37.61l4.53,0l0,0.16l28.71,0l0,-0.16l4.53,0l0,-37.61l61.5,0l0,-45.54l-95.34,0l77.96,-107.29z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#231F20"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
</vector>
|
|
@ -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"
|
||||
|
|
|
@ -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">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/layout_receive_fragment"
|
||||
|
@ -38,17 +39,29 @@
|
|||
android:id="@+id/receive_qr_code"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@color/zcashWhite"
|
||||
android:scaleType="centerInside"
|
||||
android:scaleType="fitCenter"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="H,1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/include_toolbar"
|
||||
app:layout_constraintVertical_bias="0.172"
|
||||
app:layout_constraintVertical_bias="0.198"
|
||||
app:layout_constraintWidth_default="percent"
|
||||
app:layout_constraintWidth_percent="0.58111" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:srcCompat="@drawable/ic_zcash_white"
|
||||
app:layout_constraintDimensionRatio="H,1:1"
|
||||
app:layout_constraintWidth_default="percent"
|
||||
app:layout_constraintWidth_percent="0.12"
|
||||
app:layout_constraintStart_toStartOf="@id/receive_qr_code"
|
||||
app:layout_constraintEnd_toEndOf="@id/receive_qr_code"
|
||||
app:layout_constraintTop_toTopOf="@id/receive_qr_code"
|
||||
app:layout_constraintBottom_toBottomOf="@id/receive_qr_code"
|
||||
/>
|
||||
|
||||
<View
|
||||
android:id="@+id/receive_address_background"
|
||||
android:layout_width="0dp"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/build
|
|
@ -0,0 +1,37 @@
|
|||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 28
|
||||
versionCode 3
|
||||
versionName "1.0.1"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation deps.androidx.coreKtx
|
||||
implementation deps.kotlin.stdlib
|
||||
|
||||
implementation 'com.google.zxing:core:3.2.1'
|
||||
|
||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
|
@ -0,0 +1,26 @@
|
|||
package cash.z.android.qrecycler;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="cash.z.android.qrecycler" />
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">QRecycler</string>
|
||||
</resources>
|
|
@ -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 <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
include ':app'
|
||||
include ':app', ':qrecycler'
|
||||
|
|
Loading…
Reference in New Issue