Show certificates QrCode

This commit is contained in:
Pierre HUBERT 2022-02-16 12:09:20 +01:00
parent 2b6fe21792
commit afa65c8239
18 changed files with 224 additions and 11 deletions

View File

@ -12,6 +12,7 @@
<entry key="app/src/main/res/layout/content_certs.xml" value="0.29483695652173914" />
<entry key="app/src/main/res/layout/fragment_first.xml" value="0.29483695652173914" />
<entry key="app/src/main/res/layout/fragment_second.xml" value="0.29483695652173914" />
<entry key="app/src/main/res/layout/qr_entry.xml" value="0.28125" />
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.3859375" />
</map>
</option>

View File

@ -2,3 +2,6 @@ package org.communiquons.dccaggregator
// Official URL provided to add certificate to wallet
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"

View File

@ -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
}

View File

@ -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() {
}
}

View File

@ -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)

View File

@ -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<Certificate>) :
ArrayAdapter<Certificate>(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<ImageView>(R.id.certQrCode).setImageBitmap(bitmap)
return view
}
}

View File

@ -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)

View File

@ -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
/**
* 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) }
}
}

View File

@ -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()
}

View File

@ -0,0 +1,41 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF"
android:alpha="0.8">
<path
android:fillColor="@android:color/white"
android:pathData="M3,11h8V3H3V11zM5,5h4v4H5V5z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M3,21h8v-8H3V21zM5,15h4v4H5V15z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M13,3v8h8V3H13zM19,9h-4V5h4V9z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M19,19h2v2h-2z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M13,13h2v2h-2z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M15,15h2v2h-2z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M13,17h2v2h-2z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M15,19h2v2h-2z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M17,17h2v2h-2z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M17,13h2v2h-2z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M19,15h2v2h-2z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

View File

@ -18,4 +18,13 @@
android:src="@android:drawable/ic_input_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<ListView
android:id="@+id/certsList"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="150dp"
android:orientation="horizontal"
android:padding="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="1dp">
<ImageView
android:id="@+id/certQrCode"
android:layout_width="110dp"
android:layout_height="match_parent"
android:contentDescription="@string/certificate_qr_code"
app:srcCompat="@drawable/ic_qr" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="20dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/user_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
tools:text="John Doe" />
<TextView
android:id="@+id/date_of_birth"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="italic"
tools:text="01/01/1995" />
<TextView
android:id="@+id/certificate_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="A long long text about the certificate that explains what kind of certificate it is" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="qr_code_widget_dcc_size">200dp</dimen>
<dimen name="qr_code_widget_size">110dp</dimen>
</resources>

View File

@ -5,4 +5,5 @@
<string name="scan_qr_prompt">Please present the QrCode of the certificate you want to add</string>
<string name="action_import_certificate">Import certificate</string>
<string name="invalid_certificate">The given certificate could not be decoded!</string>
<string name="certificate_qr_code">Certificate QR Code</string>
</resources>