From afa65c8239cf54d1d6ee6aa61480cdbc2a6a18cd Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Wed, 16 Feb 2022 12:09:20 +0100 Subject: [PATCH] Show certificates QrCode --- .idea/misc.xml | 1 + .../communiquons/dccaggregator/Constants.kt | 5 +- .../dccaggregator/activities/BaseActivity.kt | 8 +++ .../dccaggregator/activities/CertsManager.kt | 28 +++++++--- .../dccaggregator/activities/MainActivity.kt | 2 +- .../adapters/CertificatesAdapter.kt | 36 +++++++++++++ .../communiquons/dccaggregator/ext/IntExt.kt | 14 +++++ .../dccaggregator/helper/CertificatesList.kt | 30 ++++++++++- .../dccaggregator/models/Certificate.kt | 7 ++- app/src/main/res/drawable-anydpi/ic_qr.xml | 41 +++++++++++++++ app/src/main/res/drawable-hdpi/ic_qr.png | Bin 0 -> 298 bytes app/src/main/res/drawable-mdpi/ic_qr.png | Bin 0 -> 177 bytes app/src/main/res/drawable-xhdpi/ic_qr.png | Bin 0 -> 299 bytes app/src/main/res/drawable-xxhdpi/ic_qr.png | Bin 0 -> 633 bytes .../res/layout/activity_certs_manager.xml | 9 ++++ app/src/main/res/layout/qr_entry.xml | 48 ++++++++++++++++++ app/src/main/res/values/dimens.xml | 5 ++ app/src/main/res/values/strings.xml | 1 + 18 files changed, 224 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/org/communiquons/dccaggregator/activities/BaseActivity.kt create mode 100644 app/src/main/java/org/communiquons/dccaggregator/adapters/CertificatesAdapter.kt create mode 100644 app/src/main/java/org/communiquons/dccaggregator/ext/IntExt.kt create mode 100644 app/src/main/res/drawable-anydpi/ic_qr.xml create mode 100644 app/src/main/res/drawable-hdpi/ic_qr.png create mode 100644 app/src/main/res/drawable-mdpi/ic_qr.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_qr.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_qr.png create mode 100644 app/src/main/res/layout/qr_entry.xml create mode 100644 app/src/main/res/values/dimens.xml diff --git a/.idea/misc.xml b/.idea/misc.xml index 59d5363..a07ad20 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -12,6 +12,7 @@ + diff --git a/app/src/main/java/org/communiquons/dccaggregator/Constants.kt b/app/src/main/java/org/communiquons/dccaggregator/Constants.kt index 35f0f2c..6bd7607 100644 --- a/app/src/main/java/org/communiquons/dccaggregator/Constants.kt +++ b/app/src/main/java/org/communiquons/dccaggregator/Constants.kt @@ -1,4 +1,7 @@ package org.communiquons.dccaggregator // Official URL provided to add certificate to wallet -const val WALLET_URL = "https://bonjour.tousanticovid.gouv.fr/app/walletdcc#" \ No newline at end of file +const val WALLET_URL = "https://bonjour.tousanticovid.gouv.fr/app/walletdcc#" + +// Name of the preferences file holding certificates list +const val PREF_CERTS_LIST = "certs_list" \ No newline at end of file diff --git a/app/src/main/java/org/communiquons/dccaggregator/activities/BaseActivity.kt b/app/src/main/java/org/communiquons/dccaggregator/activities/BaseActivity.kt new file mode 100644 index 0000000..7c332a5 --- /dev/null +++ b/app/src/main/java/org/communiquons/dccaggregator/activities/BaseActivity.kt @@ -0,0 +1,8 @@ +package org.communiquons.dccaggregator.activities + +import androidx.appcompat.app.AppCompatActivity +import org.communiquons.dccaggregator.DCCAggregator + +abstract class BaseActivity : AppCompatActivity() { + val certsManager get() = (application as DCCAggregator).certManager +} \ No newline at end of file diff --git a/app/src/main/java/org/communiquons/dccaggregator/activities/CertsManager.kt b/app/src/main/java/org/communiquons/dccaggregator/activities/CertsManager.kt index ef0d699..f03130d 100644 --- a/app/src/main/java/org/communiquons/dccaggregator/activities/CertsManager.kt +++ b/app/src/main/java/org/communiquons/dccaggregator/activities/CertsManager.kt @@ -1,23 +1,30 @@ package org.communiquons.dccaggregator.activities import android.os.Bundle -import android.util.Log import android.view.MenuItem import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity import com.journeyapps.barcodescanner.ScanContract import com.journeyapps.barcodescanner.ScanOptions import org.communiquons.dccaggregator.R import org.communiquons.dccaggregator.WALLET_URL +import org.communiquons.dccaggregator.adapters.CertificatesAdapter import org.communiquons.dccaggregator.databinding.ActivityCertsManagerBinding import org.communiquons.dccaggregator.models.Certificate import java.net.URLDecoder import java.nio.charset.StandardCharsets -class CertsManager : AppCompatActivity() { +class CertsManager : BaseActivity() { private lateinit var binding: ActivityCertsManagerBinding + private val certsList by lazy { + ArrayList(certsManager.certsList) + } + + private val listAdapter by lazy { + CertificatesAdapter(this, certsList) + } + private val TAG = CertsManager::class.java.canonicalName override fun onCreate(savedInstanceState: Bundle?) { @@ -27,15 +34,19 @@ class CertsManager : AppCompatActivity() { supportActionBar?.setDisplayHomeAsUpEnabled(true) + // Initialize certificates list + binding.certsList.adapter = listAdapter + binding.scanCertButton.setOnClickListener { addNewCertificate() } - intent?.dataString.toString().apply { if (this.startsWith(WALLET_URL)) processGivenCertificate(this) } + + refreshList() } override fun onOptionsItemSelected(item: MenuItem): Boolean { @@ -71,14 +82,17 @@ class CertsManager : AppCompatActivity() { } try { - val cert = Certificate(decoded) - - Log.v(TAG, cert.fullName) + certsManager.addCertificate(Certificate(decoded)) + refreshList() } catch (e: Exception) { e.printStackTrace() Toast.makeText(this, R.string.invalid_certificate, Toast.LENGTH_SHORT).show() return } } + + private fun refreshList() { + + } } \ No newline at end of file diff --git a/app/src/main/java/org/communiquons/dccaggregator/activities/MainActivity.kt b/app/src/main/java/org/communiquons/dccaggregator/activities/MainActivity.kt index 4ccedf3..dff62fb 100644 --- a/app/src/main/java/org/communiquons/dccaggregator/activities/MainActivity.kt +++ b/app/src/main/java/org/communiquons/dccaggregator/activities/MainActivity.kt @@ -7,7 +7,7 @@ import androidx.appcompat.app.AppCompatDelegate import org.communiquons.dccaggregator.DCCAggregator import org.communiquons.dccaggregator.R -class MainActivity : AppCompatActivity() { +class MainActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setTheme(R.style.Theme_DCCAggregator) diff --git a/app/src/main/java/org/communiquons/dccaggregator/adapters/CertificatesAdapter.kt b/app/src/main/java/org/communiquons/dccaggregator/adapters/CertificatesAdapter.kt new file mode 100644 index 0000000..455410d --- /dev/null +++ b/app/src/main/java/org/communiquons/dccaggregator/adapters/CertificatesAdapter.kt @@ -0,0 +1,36 @@ +package org.communiquons.dccaggregator.adapters + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter +import android.widget.ImageView +import com.google.zxing.BarcodeFormat +import com.journeyapps.barcodescanner.BarcodeEncoder +import org.communiquons.dccaggregator.R +import org.communiquons.dccaggregator.ext.toDimensSize +import org.communiquons.dccaggregator.models.Certificate + +class CertificatesAdapter(cxt: Context, list: ArrayList) : + ArrayAdapter(cxt, 0, list) { + + private val qrSize by lazy { + R.dimen.qr_code_widget_size.toDimensSize(context).toInt() + } + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + val view = + convertView ?: LayoutInflater.from(context).inflate(R.layout.qr_entry, parent, false) + + val cert = getItem(position) as Certificate + + // Generate Qr code + val bitmap = + BarcodeEncoder().encodeBitmap(cert.encoded, BarcodeFormat.QR_CODE, qrSize, qrSize) + view.findViewById(R.id.certQrCode).setImageBitmap(bitmap) + + + return view + } +} \ No newline at end of file diff --git a/app/src/main/java/org/communiquons/dccaggregator/ext/IntExt.kt b/app/src/main/java/org/communiquons/dccaggregator/ext/IntExt.kt new file mode 100644 index 0000000..5b6c19f --- /dev/null +++ b/app/src/main/java/org/communiquons/dccaggregator/ext/IntExt.kt @@ -0,0 +1,14 @@ +package org.communiquons.dccaggregator.ext + +import android.content.Context +import androidx.annotation.DimenRes +import androidx.annotation.Dimension + +/** + * Return the dimension corresponding to the current theme of the receiver id. + * + * @param context context where the theme is. + * @return Resource dimension value multiplied by the appropriate metric. + */ +@Dimension +fun @receiver:DimenRes Int.toDimensSize(context: Context): Float = context.resources.getDimension(this) \ No newline at end of file diff --git a/app/src/main/java/org/communiquons/dccaggregator/helper/CertificatesList.kt b/app/src/main/java/org/communiquons/dccaggregator/helper/CertificatesList.kt index 7aa8387..78d354a 100644 --- a/app/src/main/java/org/communiquons/dccaggregator/helper/CertificatesList.kt +++ b/app/src/main/java/org/communiquons/dccaggregator/helper/CertificatesList.kt @@ -2,9 +2,37 @@ package org.communiquons.dccaggregator.helper import android.content.Context import androidx.preference.PreferenceManager +import org.communiquons.dccaggregator.PREF_CERTS_LIST +import org.communiquons.dccaggregator.models.Certificate class CertificatesList(context: Context) { private val prefsManager = PreferenceManager.getDefaultSharedPreferences(context) val hasGeneratedCertificate get() = false -} \ No newline at end of file + + /** + * The list of certificates, as a strings list + */ + private var listString + get() = prefsManager.getStringSet(PREF_CERTS_LIST, HashSet())!! + set(v) = prefsManager.edit().putStringSet(PREF_CERTS_LIST, v).apply() + + /** + * The list of decoded certificates + */ + val certsList get() = listString.map { t -> Certificate(t) } + + /** + * Check if a certificate is already present in the list or not + */ + fun hasCertificate(cert: Certificate): Boolean { + return certsList.any { it.id == cert.id } + } + + /** + * Add a certificate to the list + */ + fun addCertificate(cert: Certificate) { + listString = listString.apply { add(cert.encoded) } + } +} diff --git a/app/src/main/java/org/communiquons/dccaggregator/models/Certificate.kt b/app/src/main/java/org/communiquons/dccaggregator/models/Certificate.kt index f6a241c..203d03b 100644 --- a/app/src/main/java/org/communiquons/dccaggregator/models/Certificate.kt +++ b/app/src/main/java/org/communiquons/dccaggregator/models/Certificate.kt @@ -9,7 +9,7 @@ import dgca.verifier.app.decoder.model.GreenCertificate class Certificate(val encoded: String) { // Decoded green certificate - val decoded: GreenCertificate; + val decoded: GreenCertificate init { val res = DefaultCertificateDecoder(Base45Decoder()).decodeCertificate(encoded) @@ -24,4 +24,9 @@ class Certificate(val encoded: String) { * Get person full name */ val fullName get() = "${decoded.person.standardisedGivenName} ${decoded.person.standardisedFamilyName}" + + /** + * Get certificate id + */ + val id get() = decoded.getDgci() } \ No newline at end of file diff --git a/app/src/main/res/drawable-anydpi/ic_qr.xml b/app/src/main/res/drawable-anydpi/ic_qr.xml new file mode 100644 index 0000000..4452eac --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_qr.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable-hdpi/ic_qr.png b/app/src/main/res/drawable-hdpi/ic_qr.png new file mode 100644 index 0000000000000000000000000000000000000000..40aed5e119d3dde784930e402eb18c7bb144e68e GIT binary patch literal 298 zcmV+_0oDGAP)*Z=?k07*qoM6N<$g6V^R)&Kwi literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_qr.png b/app/src/main/res/drawable-mdpi/ic_qr.png new file mode 100644 index 0000000000000000000000000000000000000000..471053aeeae4f2e94cc8e14e15f2fbac511b5043 GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gj6`n4RAr*0N`wh7c81NkV^nd$T z|92w%Mynogb$Rfxg(GF{>6VU)eR;P;B|a^SJ;+q`?wq>Vh2nC%jScg5f9_=ca%Zl8 zS%UdnE}qKE@7h1Cwkg{tYIhwzaWpdo>sH*Szl{Y_IOV<2|hKq4QPb`gf9SuhGbvQZ{dIue)*}^M2V< zHoxE7v`q_cZI4~a___SM5AUq~yVJ8S{JCoz-2Ci4Nb^SbGuvYm7syo~sktr6_6nKX eo+z>Jp!^5X%y4yo6+WQv89ZJ6T-G@yGywpu9E_d- literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_qr.png b/app/src/main/res/drawable-xxhdpi/ic_qr.png new file mode 100644 index 0000000000000000000000000000000000000000..4ae498820c2e02073f55427133863a1443bdc9bd GIT binary patch literal 633 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@Zgyv2U~=$uaSW-5dwX?bZ-gTc^TpTu z&AylPnN=QWifH`TY1*(!QS#OE^vG$cAhhhyzkmOJPJe#SaeeK(-i2d3-beuX5M_c|O8M*5H3AFv#YE zg6rRExxG*9lRuUm_!Dkhb+Z20qn8aouPna)E!)CE)@**&ms>y^f#w0j`1bmT4@z#- zytzopr E09nakvH$=8 literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/activity_certs_manager.xml b/app/src/main/res/layout/activity_certs_manager.xml index 418e593..ef7f61d 100644 --- a/app/src/main/res/layout/activity_certs_manager.xml +++ b/app/src/main/res/layout/activity_certs_manager.xml @@ -18,4 +18,13 @@ android:src="@android:drawable/ic_input_add" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/qr_entry.xml b/app/src/main/res/layout/qr_entry.xml new file mode 100644 index 0000000..a1f9cdb --- /dev/null +++ b/app/src/main/res/layout/qr_entry.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..5865630 --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ + + + 200dp + 110dp + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8904fd6..dd889b4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,4 +5,5 @@ Please present the QrCode of the certificate you want to add Import certificate The given certificate could not be decoded! + Certificate QR Code \ No newline at end of file