Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

Commit

Permalink
feat: vaccination exemption
Browse files Browse the repository at this point in the history
  • Loading branch information
astagi authored Jan 21, 2022
2 parents 24475f1 + 22772f0 commit 945cf47
Show file tree
Hide file tree
Showing 25 changed files with 412 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ data class ConfigurationSettings(
@field:Json(name = "dummy_analytics_waiting_time") val dummyAnalyticsWaitingTime: Int,
@field:Json(name = "countries") val countries: Map<String, Map<String, String>>,
@field:Json(name = "eudcc_expiration") val eudcc_expiration: Map<String, Map<String, String>>

)

@JsonClass(generateAdapter = true)
Expand Down Expand Up @@ -191,38 +190,44 @@ private fun eudccMap(): Map<String, Map<String, String>> {
"rapid_test" to "Certificazione valida 48 ore dall'ora del prelievo",
"vaccine_first_dose" to "Certificazione valida fino alla prossima dose",
"vaccine_fully_completed" to "Certificazione valida 365 giorni (12 mesi) dalla data dell'ultima somministrazione",
"healing_certificate" to "Certificazione valida in Unione Europea fino alla data di fine validità e valida solo in Italia fino a 6 mesi dalla data di inizio validità"
"healing_certificate" to "Certificazione valida in Unione Europea fino alla data di fine validità e valida solo in Italia fino a 6 mesi dalla data di inizio validità",
"exemption_certificate" to "Certificato esenzione (illimitata)"
),
"de" to mapOf(
"molecular_test" to "Bescheinigung gültig für 72 Stunden ab dem Zeitpunkt der Abholung",
"rapid_test" to "Bescheinigung gültig für 48 Stunden ab dem Zeitpunkt der Abholung",
"vaccine_first_dose" to "Zertifizierung gültig bis zur nächsten Dosis",
"vaccine_fully_completed" to "Zertifizierung gültig für 365 Tage (12 Monate) ab dem Datum der letzten Verabreichung",
"healing_certificate" to "Zertifizierung gültig in der Europäischen Union bis zum Gültigkeitsende und nur in Italien bis zu 6 Monate ab Gültigkeitsbeginn gültig"
"healing_certificate" to "Zertifizierung gültig in der Europäischen Union bis zum Gültigkeitsende und nur in Italien bis zu 6 Monate ab Gültigkeitsbeginn gültig",
"exemption_certificate" to "Befreiungsbescheinigung (unbefristet)"
),
"en" to mapOf(
"molecular_test" to "Certification valid for 72 hours from the time of collection",
"rapid_test" to "Certification valid for 48 hours from the time of collection",
"vaccine_first_dose" to "Certification valid until next dose",
"vaccine_fully_completed" to "Certification valid for 365 days (12 months) from the date of the last administration",
"healing_certificate" to "Certification valid in the European Union until the end of validity date and valid only in Italy up to 6 months from the start of validity date"
"healing_certificate" to "Certification valid in the European Union until the end of validity date and valid only in Italy up to 6 months from the start of validity date",
"exemption_certificate" to "Certificate of exemption (unlimited)"
),
"es" to mapOf(
"molecular_test" to "Certificación válida por 72 horas desde el momento de la recogida.",
"rapid_test" to "Certificación válida por 48 horas desde el momento de la recogida.",
"vaccine_first_dose" to "Certificación válida hasta la próxima dosis",
"vaccine_fully_completed" to "Certificación válida por 365 días (12 meses) a partir de la fecha de la última administración.",
"healing_certificate" to "Certificación válida en la Unión Europea hasta el final de la fecha de validez y válida solo en Italia hasta 6 meses desde el inicio de la fecha de validez"
"healing_certificate" to "Certificación válida en la Unión Europea hasta el final de la fecha de validez y válida solo en Italia hasta 6 meses desde el inicio de la fecha de validez",
"exemption_certificate" to "Certificado de exención (ilimitado)"
),
"fr" to mapOf(
"molecular_test" to "Attestation valable 72h à compter de la collecte",
"rapid_test" to "Attestation valable 48h à compter de la collecte",
"vaccine_first_dose" to "Certification valable jusqu'à la prochaine dose",
"vaccine_fully_completed" to "Certification valable 365 jours (12 mois) à compter de la date de la dernière administration",
"healing_certificate" to "Certification valable dans l'Union européenne jusqu'à la date de fin de validité et valable uniquement en Italie jusqu'à 6 mois à compter de la date de début de validité"
"healing_certificate" to "Certification valable dans l'Union européenne jusqu'à la date de fin de validité et valable uniquement en Italie jusqu'à 6 mois à compter de la date de début de validité",
"exemption_certificate" to "Certificat d'exonération (illimité)"
)
)
}

val defaultSettings = ConfigurationSettings(
minimumBuildVersion = 0,
faqUrls = languageMap { "https://get.immuni.gov.it/docs/faq-${it.code}.json" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,12 @@ class UserManager(
fun provinces(region: Region) = regionRepository.provinces(region = region)

// endregion

// DGC
val showModalDGC = userRepository.showModalDGC

fun setShowModalDGC(show: Boolean) {
userRepository.setShowModalDGC(show)
}
// END DGC
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class UserRepository(
private val setupCompleteKey = KVStorage.Key<Boolean>("SetupComplete")
private val welcomeCompleteKey = KVStorage.Key<Boolean>("WelcomeComplete")
private val onboardingCompleteKey = KVStorage.Key<Boolean>("OnboardingComplete")
private val showModalDGCKey = KVStorage.Key<Boolean>("showModalDGC")
}

val user = storage.stateFlow(userKey)
Expand All @@ -51,4 +52,10 @@ class UserRepository(
fun setOnboardingComplete(complete: Boolean) {
storage[onboardingCompleteKey] = complete
}

val showModalDGC = storage.stateFlow(showModalDGCKey, defaultValue = true)

fun setShowModalDGC(show: Boolean) {
storage[showModalDGCKey] = show
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ import android.provider.Settings
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.get
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.tabs.TabLayoutMediator
Expand All @@ -40,6 +42,7 @@ import it.ministerodellasalute.immuni.ui.dialog.openConfirmationDialog
import it.ministerodellasalute.immuni.util.ImageUtils
import kotlin.math.abs
import kotlinx.android.synthetic.main.green_certificate.*
import kotlinx.android.synthetic.main.green_certificate_tab.*
import org.koin.android.ext.android.get
import org.koin.androidx.viewmodel.ext.android.getViewModel

Expand All @@ -58,6 +61,7 @@ class GreenCertificateFragment : Fragment(R.layout.green_certificate), Confirmat
companion object {
const val DELETE_QR = 200
const val GO_TO_SETTINGS = 201
const val INFORMATION_ORDER = 202
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
Expand Down Expand Up @@ -86,14 +90,28 @@ class GreenCertificateFragment : Fragment(R.layout.green_certificate), Confirmat
positionOffsetPixels: Int
) {
}

override fun onPageSelected(position: Int) {
super.onPageSelected(position)
val currentView = (viewpager[0] as RecyclerView).layoutManager?.findViewByPosition(position)
currentView?.post {
val wMeasureSpec = View.MeasureSpec.makeMeasureSpec(currentView.width, View.MeasureSpec.EXACTLY)
val hMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
currentView.measure(wMeasureSpec, hMeasureSpec)

if (viewpager.layoutParams.height != currentView.measuredHeight) {
viewpager.layoutParams = (viewpager.layoutParams).also { lp -> lp.height = currentView.measuredHeight }
}
}
}
}

greenPassAdapter = GreenPassAdapter(
context = requireContext(),
fragment = this@GreenCertificateFragment,
viewModel = viewModel
)
greenPassAdapter.data = userManager.user.value?.greenPass!!
greenPassAdapter.data = userManager.user.value?.greenPass!!.asReversed()

with(viewpager) {
adapter = greenPassAdapter
Expand All @@ -116,36 +134,56 @@ class GreenCertificateFragment : Fragment(R.layout.green_certificate), Confirmat
findNavController().navigate(action)
}
setVisibilityLayout()
informationOrder()
}

override fun onDialogPositive(requestCode: Int) {
if (requestCode == DELETE_QR) {
val user = userManager.user
user.value?.greenPass!!.removeAt(positionToDelete!!)
userManager.save(
User(
region = user.value?.region!!,
province = user.value?.province!!,
greenPass = user.value?.greenPass!!
when (requestCode) {
DELETE_QR -> {
val user = userManager.user
user.value?.greenPass!!.asReversed().removeAt(positionToDelete!!)
userManager.save(
User(
region = user.value?.region!!,
province = user.value?.province!!,
greenPass = user.value?.greenPass!!
)
)
)
greenPassAdapter.notifyItemRemoved(positionToDelete!!)
greenPassAdapter.notifyItemRangeChanged(positionToDelete!!, greenPassAdapter.itemCount)
setVisibilityLayout()
positionToDelete = null
} else {
val intent =
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
val uri: Uri = Uri.fromParts("package", requireContext().packageName, null)
intent.data = uri
startActivity(intent)
greenPassAdapter.notifyItemRemoved(positionToDelete!!)
greenPassAdapter.notifyItemRangeChanged(positionToDelete!!, greenPassAdapter.itemCount)
setVisibilityLayout()
positionToDelete = null
}
INFORMATION_ORDER -> {
userManager.setShowModalDGC(show = false)
}
GO_TO_SETTINGS -> {
val intent =
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
val uri: Uri = Uri.fromParts("package", requireContext().packageName, null)
intent.data = uri
startActivity(intent)
}
}
}

override fun onDialogNegative(requestCode: Int) {
// Pass
}

private fun informationOrder() {
if (userManager.showModalDGC.value && userManager.user.value!!.greenPass.size > 1) {
openConfirmationDialog(
positiveButton = getString(R.string.green_certificate_modal_order_button),
negativeButton = null,
message = getString(R.string.green_certificate_modal_order_message),
title = getString(R.string.green_certificate_modal_order_title),
cancelable = false,
requestCode = INFORMATION_ORDER
)
}
}

private fun setVisibilityLayout() {
if (userManager.user.value?.greenPass!!.isEmpty()) {
noQrCodeLayout.visibility = View.VISIBLE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,9 @@ class GreenCertificateViewModel(
greenCertificate.recoveryStatements != null -> {
greenCertificate.recoveryStatements!![0].certificateIdentifier
}
greenCertificate.exemptions != null -> {
greenCertificate.exemptions!![0].certificateIdentifier
}
else -> null
}

Expand All @@ -310,6 +313,10 @@ class GreenCertificateViewModel(
if (greenPass.data?.recoveryStatements!![0].certificateIdentifier == issuerID) saved =
true
}
greenPass.data?.exemptions != null -> {
if (greenPass.data?.exemptions!![0].certificateIdentifier == issuerID) saved =
true
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ class GreenPassAdapter(
greenCertificate.data?.vaccinations != null -> {
greenCertificate.data!!.vaccinations!![0].certificateIdentifier
}
greenCertificate.data?.exemptions != null -> {
greenCertificate.data!!.exemptions!![0].certificateIdentifier
}
else -> null
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@ import it.ministerodellasalute.immuni.ui.dialog.PopupDialogFragment
import java.text.SimpleDateFormat
import java.util.*
import kotlinx.android.synthetic.main.green_certificate_more_details.*
import kotlinx.android.synthetic.main.green_certificate_more_details_exemption.*
import kotlinx.android.synthetic.main.green_certificate_more_details_recovery.*
import kotlinx.android.synthetic.main.green_certificate_more_details_test.*
import kotlinx.android.synthetic.main.green_certificate_more_details_vaccination.*
import kotlinx.android.synthetic.main.green_certificate_more_details_vaccination.countryVaccination
import kotlinx.android.synthetic.main.green_certificate_more_details_vaccination.validityVaccine
import org.koin.android.ext.android.get
import org.koin.core.KoinComponent

Expand Down Expand Up @@ -64,16 +67,19 @@ class MoreDetailGreenCertificate : PopupDialogFragment(), KoinComponent {
val rapidTest = settingsManager.settings.value.eudcc_expiration[Locale.getDefault().language]!!["rapid_test"]
val molecularTest = settingsManager.settings.value.eudcc_expiration[Locale.getDefault().language]!!["molecular_test"]
val healing_certificate = settingsManager.settings.value.eudcc_expiration[Locale.getDefault().language]!!["healing_certificate"]
val exemptionCertificate = settingsManager.settings.value.eudcc_expiration[Locale.getDefault().language]!!["exemption_certificate"]
setUI(
vaccineFullyCompleted,
vaccineFirstDose,
molecularTest,
rapidTest,
healing_certificate
healing_certificate,
exemptionCertificate
)
}

private fun setUI(validUntilCompleteVaccine: String?, validUntilnotCompleteVaccine: String?, validUntilMolecularTest: String?, validUntilQuickTest: String?, healing_certificate: String?) {
private fun setUI(validUntilCompleteVaccine: String?, validUntilnotCompleteVaccine: String?, validUntilMolecularTest: String?, validUntilQuickTest: String?, healing_certificate: String?, exemptionCertificate: String?) {
var isExemption = false
when (true) {
greenCertificateDetail.data?.vaccinations != null -> {
// Inflate layout dynamically
Expand Down Expand Up @@ -128,6 +134,7 @@ class MoreDetailGreenCertificate : PopupDialogFragment(), KoinComponent {
setTextOrDefault(greenCertificateDetail.data?.vaccinations?.get(0)!!.countryOfVaccination)
certificateIssuerLabel.text =
getText(R.string.green_certificate_certificate_issuer_vaccination)
certificateIssuerLabelExemption.visibility = View.GONE
}
greenCertificateDetail.data?.tests != null -> {
// Inflate layout dynamically
Expand Down Expand Up @@ -175,6 +182,7 @@ class MoreDetailGreenCertificate : PopupDialogFragment(), KoinComponent {
countryTest.text =
setTextOrDefault(greenCertificateDetail.data?.tests?.get(0)!!.countryOfVaccination)
certificateIssuerLabel.text = getText(R.string.green_certificate_certificate_issuer)
certificateIssuerLabelExemption.visibility = View.GONE
}
greenCertificateDetail.data?.recoveryStatements != null -> {
// Inflate layout dynamically
Expand Down Expand Up @@ -202,31 +210,57 @@ class MoreDetailGreenCertificate : PopupDialogFragment(), KoinComponent {
certificateIssuerLabel.visibility = View.GONE
entityIssuedCertificate.visibility = View.GONE
validityHealing.text = healing_certificate ?: getString(R.string.green_certificate_validity_healing)
certificateIssuerLabelExemption.visibility = View.GONE
}
greenCertificateDetail.data?.exemptions != null -> {
isExemption = true
flagEsenzione.visibility = View.VISIBLE
question.text = getString(R.string.green_certificate_exemption_title)
// Inflate layout dynamically
includeDynamicView(R.layout.green_certificate_more_details_exemption)

subHeadingExemption.text = getString(R.string.green_certificate_subHeading_exemption)
certifying_physician_exemption.text = greenCertificateDetail.data?.exemptions?.get(0)!!.fiscalCode
exemptionValidFrom.text = greenCertificateDetail.data?.exemptions?.get(0)!!.certificateValidFrom
exemptionValidUntil.text = setTextOrDefault(greenCertificateDetail.data?.exemptions?.get(0)!!.certificateValidUntil)
uniqueCodeExemption.text = greenCertificateDetail.data?.exemptions?.get(0)!!.uniqueVaccinationExemptionIdentifier
}
}

entityIssuedCertificate.text =
getString(R.string.green_certificate_certificate_issuer_const)

val europeRestrictionUrl =
getString(R.string.green_certificate_more_details_europe_restriction_url)
europeRestrictionSite.text = "{$europeRestrictionUrl}".coloredClickable(
color = requireContext().getColorCompat(R.color.colorPrimary),
bold = true
) {
ExternalLinksHelper.openLink(
requireContext(),
europeRestrictionUrl
)
if (isExemption) {
certificateIssuerLabel.visibility = View.GONE
certificateIssuerLabelExemption.visibility = View.VISIBLE
certificateIssuerLabel.text = getString(R.string.green_certificate_certificate_issuer_exemption)
setTitle(getString(R.string.green_certificate_exemption_title))
textFooter.visibility = View.GONE
europeRestrictionSite.visibility = View.GONE
textFooterExemption.visibility = View.VISIBLE
subHeading.visibility = View.GONE
subHeadingExemption.visibility = View.VISIBLE
} else {
val europeRestrictionUrl =
getString(R.string.green_certificate_more_details_europe_restriction_url)
europeRestrictionSite.text = "{$europeRestrictionUrl}".coloredClickable(
color = requireContext().getColorCompat(R.color.colorPrimary),
bold = true
) {
ExternalLinksHelper.openLink(
requireContext(),
europeRestrictionUrl
)
}
europeRestrictionSite.movementMethod = LinkMovementMethod.getInstance()
}
europeRestrictionSite.movementMethod = LinkMovementMethod.getInstance()
}

private fun includeDynamicView(layout: Int) {
val v = layoutInflater.inflate(layout, null)
container.addView(
v,
4,
5,
ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
Expand Down
Loading

0 comments on commit 945cf47

Please sign in to comment.