Commit 485e1740 authored by stopcovid@lunabee.com's avatar stopcovid@lunabee.com
Browse files

Update to 2.3.2

- Declaration token
- New filtering when reporting
- Update zip-geoloc.json
- New Signal image
parent 33067557
......@@ -102,6 +102,10 @@ internal class ApiConfiguration(
val vaccinationCentersCount: Int,
@SerializedName("ble.scanReportDelay")
val scanReportDelay: Int,
@SerializedName("app.contagiousSpan")
val contagiousSpan: Int,
@SerializedName("app.ameliUrl")
val ameliUrl: String?
)
internal fun ApiConfiguration.toDomain(gson: Gson) = Configuration(
......@@ -154,4 +158,6 @@ internal fun ApiConfiguration.toDomain(gson: Gson) = Configuration(
),
vaccinationCentersCount = vaccinationCentersCount,
scanReportDelay = scanReportDelay,
contagiousSpan = contagiousSpan,
ameliUrl = ameliUrl,
)
\ No newline at end of file
......@@ -18,4 +18,6 @@
<item name="item_clickable_row" type="id" />
<item name="item_switch" type="id" />
<item name="item_card_with_actions" type="id" />
<!--Attempt to fix crash with notification on App upgrade-->
<item name="ic_notification_bar" type="drawable" />
</resources>
\ No newline at end of file
......@@ -54,4 +54,6 @@ class Configuration(
val unsupportedDevices: List<String>?,
val vaccinationCentersCount: Int,
val scanReportDelay: Int,
val contagiousSpan: Int,
val ameliUrl: String?,
)
\ No newline at end of file
......@@ -56,7 +56,7 @@ class SecureFileLocalProximityDataSourceTest {
delay(250)
}
val getList = secureFileLocalProximityDataSource.getUntilTime(0)
val getList = secureFileLocalProximityDataSource.getBetweenTime(0, Long.MAX_VALUE)
assertThat(getList).isEqualTo(list)
}
......@@ -71,7 +71,7 @@ class SecureFileLocalProximityDataSourceTest {
secureFileLocalProximityDataSource.removeAll()
val removedList = secureFileLocalProximityDataSource.getUntilTime(0)
val removedList = secureFileLocalProximityDataSource.getBetweenTime(0, Long.MAX_VALUE)
assertThat(removedList).isEmpty()
}
......@@ -84,13 +84,13 @@ class SecureFileLocalProximityDataSourceTest {
delay(250)
}
val getList = secureFileLocalProximityDataSource.getUntilTime(0)
val getList = secureFileLocalProximityDataSource.getBetweenTime(0, Long.MAX_VALUE)
assertThat(getList).isEmpty()
}
@Test
fun get_until() {
fun get_between() {
val proximityNumber = 10L
val dayNumber = 10
val sessionNumber = 10
......@@ -105,10 +105,55 @@ class SecureFileLocalProximityDataSourceTest {
}
}
assertThat(secureFileLocalProximityDataSource.getUntilTime(5 * 60 * 60 * 24)).hasSize(5 * dayNumber * sessionNumber)
assertThat(secureFileLocalProximityDataSource.getUntilTime(9 * 60 * 60 * 24)).hasSize(dayNumber * sessionNumber)
assertThat(secureFileLocalProximityDataSource.getUntilTime(10 * 60 * 60 * 24)).hasSize(0)
assertThat(secureFileLocalProximityDataSource.getUntilTime(0L)).hasSize((proximityNumber * dayNumber * sessionNumber).toInt())
assertThat(
secureFileLocalProximityDataSource.getBetweenTime(
ntpStartTimeS = 5 * 60 * 60 * 24,
ntpEndTimeS = Long.MAX_VALUE,
)
).hasSize(5 * dayNumber * sessionNumber)
assertThat(
secureFileLocalProximityDataSource.getBetweenTime(
ntpStartTimeS = 9 * 60 * 60 * 24,
ntpEndTimeS = Long.MAX_VALUE,
)
).hasSize(dayNumber * sessionNumber)
assertThat(
secureFileLocalProximityDataSource.getBetweenTime(
ntpStartTimeS = 10 * 60 * 60 * 24,
ntpEndTimeS = Long.MAX_VALUE,
)
).hasSize(0)
assertThat(
secureFileLocalProximityDataSource.getBetweenTime(
ntpStartTimeS = 0L,
ntpEndTimeS = Long.MAX_VALUE,
)
).hasSize((proximityNumber * dayNumber * sessionNumber).toInt())
assertThat(
secureFileLocalProximityDataSource.getBetweenTime(
ntpStartTimeS = 0L,
ntpEndTimeS = 0L,
)
).hasSize(dayNumber * sessionNumber)
assertThat(
secureFileLocalProximityDataSource.getBetweenTime(
ntpStartTimeS = 0L,
ntpEndTimeS = 60 * 60 * 24,
)
).hasSize(2 * dayNumber * sessionNumber)
assertThat(
secureFileLocalProximityDataSource.getBetweenTime(
ntpStartTimeS = 0L,
ntpEndTimeS = 4 * 60 * 60 * 24,
)
).hasSize(5 * dayNumber * sessionNumber)
assertThat(
secureFileLocalProximityDataSource.getBetweenTime(
ntpStartTimeS = 0L,
ntpEndTimeS = 9 * 60 * 60 * 24,
)
).hasSize((proximityNumber * dayNumber * sessionNumber).toInt())
}
@Test
......
......@@ -55,12 +55,12 @@ open class SecureFileLocalProximityDataSource(
private var dumpJob: Job? = null
override fun getUntilTime(ntpTimeS: Long): List<LocalProximity> {
override fun getBetweenTime(ntpStartTimeS: Long, ntpEndTimeS: Long): List<LocalProximity> {
return storageDir.listFiles { file ->
file.isDirectory && file.name.toIntOrNull() != null
}?.mapNotNull { file ->
val dirDay = file.name.toInt()
if (dirDay >= ntpTimeS / (60 * 60 * 24)) {
if (dirDay >= ntpStartTimeS / (60 * 60 * 24) && dirDay <= ntpEndTimeS / (60 * 60 * 24)) {
file
} else {
null
......
......@@ -138,9 +138,13 @@ class SecureKeystoreDataSource(context: Context, private val cryptoManager: Loca
get() = getEncryptedValue(SHARED_PREF_KEY_SAVE_DATA_VENUES_QR_CODE, object : TypeToken<List<VenueQrCode>>() {}.type)
set(value) = setEncryptedValue(SHARED_PREF_KEY_SAVE_DATA_VENUES_QR_CODE, value)
override var reportToSendTime: Long?
get() = getEncryptedValue(SHARED_PREF_KEY_REPORT_TO_SEND_TIME, Long::class.java)
set(value) = setEncryptedValue(SHARED_PREF_KEY_REPORT_TO_SEND_TIME, value)
override var reportToSendStartTime: Long?
get() = getEncryptedValue(SHARED_PREF_KEY_REPORT_TO_SEND_START_TIME, Long::class.java)
set(value) = setEncryptedValue(SHARED_PREF_KEY_REPORT_TO_SEND_START_TIME, value)
override var reportToSendEndTime: Long?
get() = getEncryptedValue(SHARED_PREF_KEY_REPORT_TO_SEND_END_TIME, Long::class.java)
set(value) = setEncryptedValue(SHARED_PREF_KEY_REPORT_TO_SEND_END_TIME, value)
override var reportPositiveTestDate: Long?
get() = getEncryptedValue(SHARED_PREF_KEY_REPORT_POSITIVE_TEST_DATE, Long::class.java)
......@@ -329,7 +333,8 @@ class SecureKeystoreDataSource(context: Context, private val cryptoManager: Loca
private const val SHARED_PREF_KEY_REPORT_DATE_ENCRYPTED = "shared.pref.report_date_encrypted"
private const val SHARED_PREF_KEY_SAVE_DATA_VENUES_QR_CODE = "shared.pref.venues_qr_code"
private const val SHARED_PREF_KEY_REPORT_VALIDATION_TOKEN = "shared.pref.report_validation_token"
private const val SHARED_PREF_KEY_REPORT_TO_SEND_TIME = "shared.pref.report_to_send_time"
private const val SHARED_PREF_KEY_REPORT_TO_SEND_START_TIME = "shared.pref.report_to_send_start_time"
private const val SHARED_PREF_KEY_REPORT_TO_SEND_END_TIME = "shared.pref.report_to_send_end_time"
private const val SHARED_PREF_KEY_DECLARATION_TOKEN = "shared.pref.declaration_token"
// Add on to ROBERT for isolation
......
......@@ -21,6 +21,6 @@ interface RobertApplication {
fun alertAtRiskLevelChange()
suspend fun sendClockNotAlignedNotification()
fun refreshInfoCenter()
fun getVenueQrCodeList(startTime: Long?): List<VenueQrCode>?
fun getVenueQrCodeList(startTime: Long?, endTime: Long?): List<VenueQrCode>?
fun clearVenueQrCodeList()
}
\ No newline at end of file
......@@ -49,6 +49,8 @@ interface RobertManager {
val filteringMode: LocalProximityFilter.Mode
val declarationToken: String?
suspend fun refreshConfig(application: RobertApplication): RobertResult
suspend fun generateCaptcha(type: String, local: String): RobertResultData<String>
......
......@@ -62,6 +62,7 @@ import timber.log.Timber
import java.util.Calendar
import java.util.concurrent.TimeUnit
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
import kotlin.random.Random
import kotlin.time.Duration
......@@ -151,6 +152,9 @@ class RobertManagerImpl(
override val reportPositiveTestDate: Long?
get() = keystoreRepository.reportPositiveTestDate
override val declarationToken: String?
get() = keystoreRepository.declarationToken
init {
if (isRegistered) {
startStatusWorker(application.getAppContext())
......@@ -406,7 +410,7 @@ class RobertManagerImpl(
@OptIn(ExperimentalTime::class)
private suspend fun wstatus(robertApplication: RobertApplication): RobertResultData<AtRiskStatus> {
val venueQrCodeList: List<VenueQrCode>? = robertApplication.getVenueQrCodeList(null)
val venueQrCodeList: List<VenueQrCode>? = robertApplication.getVenueQrCodeList(null, null)
return if (!venueQrCodeList.isNullOrEmpty()) {
val wResult = remoteServiceRepository.wstatus(configuration.warningApiVersion, venueQrCodeList)
when (wResult) {
......@@ -501,22 +505,31 @@ class RobertManagerImpl(
): RobertResult {
// Max take hello 14 days from now
var originDayInPast = configuration.dataRetentionPeriod.toLong()
// Min take hello before now
var endDayInPast = 0L
when {
firstSymptoms != null -> {
// if symptoms take `preSymptomsSpan` days before first symptoms
val preSymptomsSpan = configuration.preSymptomsSpan.toLong()
originDayInPast = min(originDayInPast, firstSymptoms.toLong() + preSymptomsSpan)
// to `contagiousSpan` days after first symptoms
endDayInPast = abs(min(endDayInPast, -firstSymptoms.toLong() + configuration.contagiousSpan))
}
positiveTest != null -> {
// if positive test take `positiveSampleSpan` days before positive test
val positiveSampleSpan = configuration.positiveSampleSpan.toLong()
originDayInPast = min(originDayInPast, positiveTest.toLong() + positiveSampleSpan)
// to `contagiousSpan` days after positive test
endDayInPast = abs(min(endDayInPast, -positiveTest.toLong() + configuration.contagiousSpan))
}
}
Timber.d("Will report data from $originDayInPast days to $endDayInPast days from now")
val reportStartTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(originDayInPast)
val reportEndTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(endDayInPast)
val firstProximityToSendTime = reportStartTime.unixTimeMsToNtpTimeS()
val lastProximityToSendTime = reportEndTime.unixTimeMsToNtpTimeS()
val localProximityList = localProximityRepository.getUntilTime(firstProximityToSendTime)
val localProximityList = localProximityRepository.getBetweenTime(firstProximityToSendTime, lastProximityToSendTime)
val filteredLocalProximityList = localProximityFilter.filter(
localProximityList,
filteringMode,
......@@ -534,7 +547,8 @@ class RobertManagerImpl(
keystoreRepository.reportSymptomsStartDate = firstSymptoms?.let { System.currentTimeMillis() - TimeUnit.DAYS.toMillis(it.toLong()) }
keystoreRepository.reportPositiveTestDate = positiveTest?.let { System.currentTimeMillis() - TimeUnit.DAYS.toMillis(it.toLong()) }
keystoreRepository.reportValidationToken = result.data.reportValidationToken
keystoreRepository.reportToSendTime = firstProximityToSendTime
keystoreRepository.reportToSendStartTime = firstProximityToSendTime
keystoreRepository.reportToSendEndTime = lastProximityToSendTime
wreportIfNeeded(application, true)
RobertResult.Success()
}
......@@ -544,22 +558,25 @@ class RobertManagerImpl(
override suspend fun wreportIfNeeded(application: RobertApplication, shouldRetry: Boolean) {
val wToken = keystoreRepository.reportValidationToken
val reportToSendTime = keystoreRepository.reportToSendTime
if (wToken != null && reportToSendTime != null) {
val venueQrCodeList = application.getVenueQrCodeList(reportToSendTime)
val reportToSendStartTime = keystoreRepository.reportToSendStartTime
val reportToSendEndTime = keystoreRepository.reportToSendEndTime
if (wToken != null && reportToSendStartTime != null && reportToSendEndTime != null) {
val venueQrCodeList = application.getVenueQrCodeList(reportToSendStartTime, reportToSendEndTime)
if (!venueQrCodeList.isNullOrEmpty()) {
val result = remoteServiceRepository.wreport(configuration.warningApiVersion, wToken, venueQrCodeList)
when (result) {
is RobertResult.Success -> {
keystoreRepository.reportValidationToken = null
keystoreRepository.reportToSendTime = null
keystoreRepository.reportToSendStartTime = null
keystoreRepository.reportToSendEndTime = null
application.clearVenueQrCodeList()
}
is RobertResult.Failure -> {
// 403 means token invalid, erase token
if (result.error is ForbiddenException) {
keystoreRepository.reportValidationToken = null
keystoreRepository.reportToSendTime = null
keystoreRepository.reportToSendStartTime = null
keystoreRepository.reportToSendEndTime = null
application.clearVenueQrCodeList()
} else if (shouldRetry) {
wreportIfNeeded(application, false)
......@@ -568,7 +585,8 @@ class RobertManagerImpl(
}
} else {
keystoreRepository.reportValidationToken = null
keystoreRepository.reportToSendTime = null
keystoreRepository.reportToSendStartTime = null
keystoreRepository.reportToSendEndTime = null
application.clearVenueQrCodeList()
}
}
......@@ -677,7 +695,8 @@ class RobertManagerImpl(
keystoreRepository.reportPositiveTestDate = null
keystoreRepository.reportSymptomsStartDate = null
keystoreRepository.reportValidationToken = null
keystoreRepository.reportToSendTime = null
keystoreRepository.reportToSendStartTime = null
keystoreRepository.reportToSendEndTime = null
keystoreRepository.declarationToken = null
keystoreRepository.atRiskModelVersion = AT_RISK_MODEL_VERSION
}
......
......@@ -41,7 +41,8 @@ interface LocalKeystoreDataSource {
var saveAttestationData: Boolean?
var reportDate: Long?
var reportValidationToken: String?
var reportToSendTime: Long?
var reportToSendStartTime: Long?
var reportToSendEndTime: Long?
var venuesQrCode: List<VenueQrCode>?
var declarationToken: String?
......
......@@ -13,7 +13,7 @@ package com.lunabeestudio.robert.datasource
import com.lunabeestudio.domain.model.LocalProximity
interface LocalLocalProximityDataSource {
fun getUntilTime(ntpTimeS: Long): List<LocalProximity>
fun getBetweenTime(ntpStartTimeS: Long, ntpEndTimeS: Long): List<LocalProximity>
suspend fun saveAll(vararg localProximity: LocalProximity)
fun removeUntilTime(ntpTimeS: Long)
fun removeAll()
......
......@@ -153,10 +153,16 @@ internal class KeystoreRepository(
keystoreDataSource.reportValidationToken = value
}
var reportToSendTime: Long?
get() = keystoreDataSource.reportToSendTime
var reportToSendStartTime: Long?
get() = keystoreDataSource.reportToSendStartTime
set(value) {
keystoreDataSource.reportToSendTime = value
keystoreDataSource.reportToSendStartTime = value
}
var reportToSendEndTime: Long?
get() = keystoreDataSource.reportToSendEndTime
set(value) {
keystoreDataSource.reportToSendEndTime = value
}
var declarationToken: String?
......
......@@ -19,8 +19,8 @@ internal class LocalProximityRepository(private val localLocalProximityDataSourc
localLocalProximityDataSource.saveAll(*localProximity)
}
fun getUntilTime(ntpTimeS: Long): List<LocalProximity> {
return localLocalProximityDataSource.getUntilTime(ntpTimeS)
fun getBetweenTime(startNtpTimeS: Long, endNtpTimeS: Long): List<LocalProximity> {
return localLocalProximityDataSource.getBetweenTime(startNtpTimeS, endNtpTimeS)
}
fun removeUntilTime(ntpTimeS: Long) {
......
......@@ -43,8 +43,8 @@ android {
applicationId "fr.gouv.android.stopcovid"
minSdkVersion 21
targetSdkVersion 30
versionCode 180
versionName "2.3.1"
versionCode 184
versionName "2.3.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
......
......@@ -122,17 +122,34 @@ class VenuesManagerTest {
saveVenueMethod.invoke(VenuesManager, *parameters)
parameters[1] = venue4
saveVenueMethod.invoke(VenuesManager, *parameters)
assert(VenuesManager.getVenuesQrCode(keystoreDataSource)?.count() == 2)
assert(
VenuesManager.getVenuesQrCode(
keystoreDataSource,
endNtpTimestamp = System.currentTimeMillis().unixTimeMsToNtpTimeS(),
)?.count() == 2
)
assert(VenuesManager.getVenuesQrCode(keystoreDataSource)?.get(0) == venue1)
assert(VenuesManager.getVenuesQrCode(keystoreDataSource)?.get(1) == venue2)
assert(VenuesManager.getVenuesQrCode(keystoreDataSource, 0L)?.count() == 2)
assert(VenuesManager.getVenuesQrCode(keystoreDataSource, 2L)?.count() == 1)
assert(VenuesManager.getVenuesQrCode(keystoreDataSource, includingFuture = true)?.count() == 3)
assert(VenuesManager.getVenuesQrCode(keystoreDataSource, 2L, true)?.count() == 2)
assert(
VenuesManager.getVenuesQrCode(
keystoreDataSource,
startNtpTimestamp = 0L,
endNtpTimestamp = System.currentTimeMillis().unixTimeMsToNtpTimeS(),
)?.count() == 2
)
assert(
VenuesManager.getVenuesQrCode(
keystoreDataSource,
startNtpTimestamp = 2L,
endNtpTimestamp = System.currentTimeMillis().unixTimeMsToNtpTimeS(),
)?.count() == 1
)
assert(VenuesManager.getVenuesQrCode(keystoreDataSource)?.count() == 3)
assert(VenuesManager.getVenuesQrCode(keystoreDataSource, 2L)?.count() == 2)
VenuesManager.clearAllData(sharedPrefs, keystoreDataSource)
assert(VenuesManager.getVenuesQrCode(keystoreDataSource)?.count() ?: 0 == 0)
assert(VenuesManager.getVenuesQrCode(keystoreDataSource, includingFuture = true)?.count() ?: 0 == 0)
assert(VenuesManager.getVenuesQrCode(keystoreDataSource)?.count() ?: 0 == 0)
}
@OptIn(ExperimentalTime::class)
......
......@@ -2,11 +2,11 @@
"config": [
{
"name": "lastUpdate",
"value": "3 february 2021"
"value": "9 march 2021"
},
{
"name": "version",
"value": 32
"value": 38
},
{
"name": "versionCalibrationBle",
......@@ -21,8 +21,8 @@
"value": "v2"
},
{
"name" : "ameliUrl",
"url" : "https://declare.ameli.fr/tousanticovid/t/%@/"
"name" : "app.ameliUrl",
"value" : ""
},
{
"name": "app.keyfigures.displayDepartmentLevel",
......@@ -110,7 +110,7 @@
},
{
"name": "app.venuesSalt",
"value": 2
"value": 100
},
{
"name": "app.venuesTimestampRoundingInterval",
......@@ -132,6 +132,10 @@
"name": "app.positiveSampleSpan",
"value": 7
},
{
"name": "app.contagiousSpan",
"value": 10
},
{
"name": "app.quarantinePeriod",
"value": 7
......@@ -182,7 +186,7 @@
},
{
"name": "ble.filterConfig",
"value": "{\"a\":4.3429448190325175,\"b\":0.1,\"deltas\":[29.6,20.9,18.5,17.6,16.9,15.5,15.0,15.0,15.0,15.0],\"durationThreshold\":90,\"p0\":-66.0,\"rssiThreshold\":-25,\"timeOverlap\":60,\"timeWindow\":120,\"riskThreshold\":0.1}"
"value": "{\"a\":4.3429448190325175,\"b\":0.1,\"deltas\":[39.0,27.0,23.0,21.0,20.0,19.0,18.0,17.0,16.0,15.0],\"durationThreshold\":90,\"p0\":-66.0,\"rssiThreshold\":-25,\"timeOverlap\":60,\"timeWindow\":120,\"riskThreshold\":0.1}"
},
{
"name": "ble.filterMode",
......
......@@ -778,13 +778,13 @@
"common.updatePostalCode":"Code postal: %@",
"common.updatePostalCode.end":"Changer",
"myHealthStateHeaderCell.exposureDate.title": "Date d'exposition approximative :",
"myHealthStateHeaderCell.exposureDate.title": "Date de contact approximative :",
"myHealthStateHeaderCell.exposureDate.range": "Entre le %@ et %@",
"notification.lowRisk.title":"Info : contacts",
"notification.lowRisk.message":"Vous avez des contacts avec des personnes qui se sont déclarées positifs COVID-19, sans risque. Continuez de bien respecter les mesures barrières !",
"notification.lowRisk.title":"Info : restez vigilant",
"notification.lowRisk.message":"Restez vigilant, vous croisez régulièrement des personnes positives et contagieuses. Continuez de bien respecter les mesures barrières !",
"notification.atHighWarning.title": "Alerte : exposition à risque",
"notification.atHighWarning.title": "Alerte : contact à risque dans un lieu",
"notification.atHighWarning.message": "Vous avez fréquenté le même lieu ou événement qu’au moins un utilisateur testé positif à la COVID-19 et contagieux ces derniers jours. Si vous êtes un mineur, discutez-en avec vos parents ou vos responsables légaux.",
"manageDataController.hideStatus.title": "Mon statut de risque",
......@@ -792,7 +792,7 @@
"manageDataController.hideStatus.button": "Masquer mon statut",
"risk.section.measures.title" : "Respectez les mesures barrières",
"risk.section.measures.body" : "Veuillez à respecter les mesures barrières pour freiner la propagation du virus.",
"risk.section.measures.body" : "Veillez à respecter les mesures barrières pour freiner la propagation du virus.",
"risk.section.measures.button" : "Les mesures barrières",
"risk.section.mcc.title" : "Mes Conseils Covid",
......@@ -804,60 +804,62 @@
"risk.section.limit.body" : "Veillez à limiter vos contacts en particulier avec les personnes à risque de forme grave.",
"risk.section.test.title" : "Faites-vous tester",
"risk.section.test.body" : "Pour savoir quel jour est le plus adéquat pour vous faire tester en fonction de votre situation, actualisez votre état dans le module \"Recommandation isolement et test\". Vous bénéficiez d'un accès prioritaire au test.\n\nContactez votre médecin traitant en cas de doute.\n\nSi vous n'avez pas de médecin, appelez le 0 800 130 000 afin d'être orienté vers un médecin (service gratuit + appel gratuit).",
"risk.section.test.body" : "Vous bénéficiez d'un accès prioritaire au test. Il vous est recommandé de vous faire tester immédiatement et 7 jours après votre date de contact.\n\nPour savoir quel jour est le plus adéquat pour vous faire tester en fonction de votre situation, actualisez votre état dans le module \"Recommandation isolement\".\n\nContactez votre médecin traitant en cas de doute.\n\nSi vous n'avez pas de médecin, appelez le 0 800 130 000 afin d'être orienté vers un médecin (service gratuit + appel gratuit).",
"risk.section.test.button":"Trouver un centre",
"risk.section.test.url":"https://www.sante.fr/covid19/external/depistage?source=TousAntiCovid",
"risk.section.symptoms.title" : "Apparition de symptômes",
"risk.section.symptoms.body" : "En cas de doute, n'hésitez pas à effectuer le questionnaire d'orientation sur Mes Conseils Covid ou appeler votre médecin.\n\nSi vous avez des symptômes compatibles avec la COVID-19, vous pouvez également actualiser votre état dans le module \"Recommandation isolement et test\" afin de savoir si votre durée d'isolement doit être modifiée.",
"risk.section.symptoms.body" : "En cas de doute, n'hésitez pas à effectuer le questionnaire d'orientation sur Mes Conseils Covid ou appeler votre médecin.\n\nSi vous avez des symptômes compatibles avec la COVID-19, vous pouvez également actualiser votre état dans le module \"Recommandation isolement\" afin de savoir si votre durée d'isolement doit être modifiée.",
"risk.section.isolate.title" : "Isolez-vous",
"risk.section.isolate.body" : "Pour calculer la durée d'isolement nécessaire selon votre situation et protéger les autres, vous pouvez vous rendre sur le module \"Recommandation isolement\".\n\nVous pouvez bénéficer d'un arrêt de travail auprès de l'Assurance Maladie.\n\nVeillez à limiter vos contacts en particulier avec les personnes à risque de forme grave. Soyez extrêmement vigilant sur le respect strict des mesures barrières.",
"risk0.home.title" : "Pas d'exposition à risque détectée",
"risk0.home.title" : "Pas de contact à risque détecté",
"risk0.home.sub" : "Appuyez pour avoir des conseils, savoir où se faire dépister et plus",
"risk0.details.title" : "Pas d'exposition à risque détectée",
"risk0.details.title" : "Pas de contact à risque détectée",
"risk0.details.sub" : "N'oubliez pas pour autant les mesures barrières et les recommandations sanitaires",
"risk0.section1.title" : "Votre risque",
"risk0.section1.body" : "Vous n'avez pas été à proximité d'un utilisateur testé positif et contagieux ni partagé un même lieu.\n\nVous serez averti si vous avez été à proximité (distance estimée à moins de deux mètres) ou dans le même lieu à risque qu'un utilisateur déclaré comme un cas de COVID-19.\n\nLa vérification de votre état se fait toutes les 24h.\n\nTousAntiCovid vous donnera alors les recommandations du ministère des Solidarités et de la Santé.",
"risk0.section1.body" : "Vous n'avez pas été à proximité d'un utilisateur testé positif et contagieux.\n\nVous serez averti si vous avez été à proximité (distance estimée à moins de deux mètres) d'un utilisateur déclaré comme un cas de COVID-19.\n\nLa vérification de votre état se fait environ toutes les 24h.\n\nTousAntiCovid vous donnera alors les recommandations du ministère des Solidarités et de la Santé.",
"risk1.notif.title" : "Info : restez vigilant",
"risk1.notif.sub" : "Vous croisez régulièrement des personnes positives et contagieuses. Consultez nos recommandations.",
"risk1.home.title" : "Restez vigilant",
"risk1.home.sub" : "Vous croisez régulièrement des personnes positives et contagieuses. Consultez nos recommandations.",
"risk1.details.title" : "Pas d'exposition à risque détectée, mais restez vigilant",
"risk1.details.title" : "Pas de contact à risque détecté, mais restez vigilant",
"risk1.details.sub" : "N'oubliez pas les mesures barrières et les recommandations sanitaires",
"risk1.section1.title" : "Votre risque",
"risk1.section1.body" : "Vous n'avez pas été à proximité d'un utilisateur testé positif et contagieux ni déclaré avoir partagé un même lieu, mais vous croisez régulièrement des personnes positives et contagieuses.\n\nVous serez averti si vous avez été à proximité (distance estimée à moins de deux mètres) ou dans le même lieu à risque qu'un utilisateur déclaré comme un cas de COVID-19.\n\nLa vérification de votre état se fait toutes les 24h.\n\nTousAntiCovid vous donnera alors les recommandations du ministère des Solidarités et de la Santé.",
"risk2.notif.title" : "Info lieu",
"risk2.notif.sub" : "Vous avez partagé le même lieu qu'au moins une personne contagieuse. Si vous êtes un mineur, discutez-en avec vos parents ou vos responsables légaux.",
"risk1.section1.body" : "Vous n'avez pas été à proximité d'un utilisateur testé positif et contagieux, mais vous croisez régulièrement des personnes positives et contagieuses.\n\nVous serez averti si vous avez été à proximité (distance estimée à moins de deux mètres) ou dans le même lieu à risque qu'un utilisateur déclaré comme un cas de COVID-19.\n\nLa vérification de votre état se fait environ toutes les 24 heures.\n\nTousAntiCovid vous donnera alors les recommandations du ministère des Solidarités et de la Santé.",
"risk2.notif.title" : "Info: lieu à risque",
"risk2.notif.sub" : "Vous avez été exposé à un risque de contamination modéré suite à la fréquentation d’un même lieu qu'une personne contagieuse. Si vous êtes un mineur, discutez-en avec vos parents ou vos responsables légaux",
"risk2.home.title" : "Info lieu : risque de contamination modéré",
"risk2.home.sub" : "Consultez nos recommandations",
"risk2.details.title" : "Vous avez fréquenté un lieu avec un risque de contamination modéré",
"risk2.details.sub" : "Faites-vous tester et respectez les mesures barrières !",
"risk2.section1.title" : "Votre risque",
"risk2.section1.body" : "Vous avez partagé le même lieu à risque modéré qu'au moins une personne contagieuse et qui se serait déclarée positive dans l'application.\n\nFaites-vous tester et respectez les mesures barrières!\"\n\nIl vous est recommandé de vous faire tester 7 jours après votre date d'exposition. Pour en savoir plus, allez sur le module \"recommandation isolement et test\". Vous bénéficiez d'un accès prioritaire au test.\n\nSi vous avez le moindre doute notamment sur votre exposition à risque, contactez votre médecin en l'informant que vous avez été été dans un lieu avec un risque de contamination modéré.\n\nVous serez averti si vous avez été à proximité (distance estimée à moins de deux mètres) ou dans le même lieu à risque qu'un utilisateur déclaré comme un cas de COVID-19.",
"risk2.section1.body" : "Vous avez été exposé à un risque de contamination modéré suite à la fréquentation d’un même lieu qu’une personne contagieuse et qui s'est déclarée positive dans l'application.\n\nLa date de contact affichée est approximative à plus ou moins un jour, pour préserver l’anonymat des personnes s'étant déclarées positives.\n\nSi vous avez le moindre doute notamment sur votre exposition à risque, contactez votre médecin en l'informant que vous avez été dans un lieu avec un risque de contamination modéré.",
"risk3.notif.title" : "Alerte lieu",
"risk3.notif.sub" : "Vous avez partagé le même lieu qu'au moins une personne contagieuse et qui se serait déclarée positive dans l'application. Si vous êtes un mineur, discutez-en avec vos parents ou vos responsables légaux.",
"risk3.home.title" : "Alerte : exposition à risque élevée dans un lieu",
"risk3.notif.title" : "Alerte : lieu à risque",
"risk3.notif.sub" : "Vous avez été exposé à un risque de contamination élevé suite à la fréquentation d’un même lieu qu' une personne contagieuse. Si vous êtes un mineur, discutez-en avec vos parents ou vos responsables légaux.",
"risk3.home.title" : "Alerte : contact à risque élevé dans un lieu",
"risk3.home.sub" : "Consultez nos recommandations",
"risk3.details.title" : "Exposition à risque élevée dans un lieu : vous êtes un contact à risque",
"risk3.details.title" : "Vous avez fréquenté un lieu avec un risque de contamination élevé : vous êtes un contact à risque",
"risk3.details.sub" : "Isolez-vous et faites-vous tester !",