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

Update to 3.7.2

- Remove some analytics
- Round analytics timestamp to the hour
- Combo DCC
- Duplicate Warning
- Fix back button when reporting
- Auto scroll on newly added certificate
- Fix crash with viewPager
parent 919c6a09
......@@ -46,6 +46,7 @@ import timber.log.Timber
import java.io.File
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
import java.util.UUID
......@@ -268,7 +269,7 @@ object AnalyticsManager : LifecycleObserver {
if (getSharedPrefs(context).isOptIn) {
CoroutineScope(Dispatchers.IO).launch {
val timestampedEventList = getAppEvents(context).toMutableList()
timestampedEventList += TimestampedEvent(eventName.name, dateFormat.format(Date()), desc ?: "")
timestampedEventList += TimestampedEvent(eventName.name, dateFormat.format(roundedHourDate()), desc ?: "")
val file = File(File(context.filesDir, FOLDER_NAME), FILE_NAME_APP_EVENTS)
writeTimestampedEventProtoToFile(file, timestampedEventList.toProto())
}
......@@ -281,7 +282,7 @@ object AnalyticsManager : LifecycleObserver {
if (getSharedPrefs(context).isOptIn) {
CoroutineScope(Dispatchers.IO).launch {
val timestampedEventList = getHealthEvents(context).toMutableList()
timestampedEventList += TimestampedEvent(eventName.name, dateFormat.format(Date()), desc ?: "")
timestampedEventList += TimestampedEvent(eventName.name, dateFormat.format(roundedHourDate()), desc ?: "")
val file = File(File(context.filesDir, FOLDER_NAME), FILE_NAME_HEALTH_EVENTS)
writeTimestampedEventProtoToFile(file, timestampedEventList.toProto())
}
......@@ -296,7 +297,7 @@ object AnalyticsManager : LifecycleObserver {
CoroutineScope(Dispatchers.IO).launch {
val name = "ERR-${wsName.uppercase(Locale.getDefault())}-${wsVersion.uppercase(Locale.getDefault())}-$errorCode"
val timestampedEventList = getErrors(filesDir).toMutableList()
timestampedEventList += TimestampedEvent(name, dateFormat.format(Date()), desc ?: "")
timestampedEventList += TimestampedEvent(name, dateFormat.format(roundedHourDate()), "")
val file = File(File(filesDir, FOLDER_NAME), FILE_NAME_APP_ERRORS)
writeTimestampedEventProtoToFile(file, timestampedEventList.toProto())
}
......@@ -404,6 +405,14 @@ object AnalyticsManager : LifecycleObserver {
}
}
private fun roundedHourDate(): Date {
return Calendar.getInstance().apply {
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.time
}
@Synchronized
private fun <T> executeActionOnAtomicFile(action: () -> T): T {
return action()
......
......@@ -13,7 +13,6 @@ package com.lunabeestudio.analytics.model
@Suppress("EnumEntryName")
enum class AppEventName {
e1,
e2,
e3,
e4,
e5,
......@@ -24,13 +23,10 @@ enum class AppEventName {
e10,
e11,
e12,
e13,
e14,
e15,
e16,
e17,
e18,
e19,
e20,
e21,
}
\ No newline at end of file
......@@ -29,6 +29,9 @@ import retrofit2.HttpException
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import timber.log.Timber
import java.io.IOException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
......@@ -118,18 +121,24 @@ internal object AnalyticsServerManager {
AnalyticsResult.Failure(HttpException(result))
}
} catch (e: Exception) {
AnalyticsManager.reportWSError(
context,
context.filesDir,
AnalyticsServiceName.ANALYTICS,
apiVersion,
(e as? HttpException)?.code() ?: 0,
e.message
)
if (!e.isNoInternetException()) {
AnalyticsManager.reportWSError(
context,
context.filesDir,
AnalyticsServiceName.ANALYTICS,
apiVersion,
(e as? HttpException)?.code() ?: 0,
e.message
)
}
AnalyticsResult.Failure(e)
}
}
private fun Exception.isNoInternetException(): Boolean = this is SocketTimeoutException
|| this is IOException
|| this is UnknownHostException
private fun certificateFromString(context: Context, fileName: String): X509Certificate {
return CertificateFactory.getInstance("X.509").generateCertificate(
context.resources.openRawResource(
......
......@@ -21,12 +21,16 @@ class SpaceItem : BaseItem<SpaceItem.ViewHolder>(
R.layout.item_space, SpaceItem::ViewHolder, R.id.item_space
) {
@DimenRes
var spaceRes: Int = -1
var spaceRes: Int = DEFAULT_HEIGHT
override fun bindView(holder: ViewHolder, payloads: List<Any>) {
super.bindView(holder, payloads)
holder.space.apply {
if (spaceRes != -1) {
if (spaceRes == DEFAULT_HEIGHT) {
updateLayoutParams {
height = 0
}
} else {
updateLayoutParams {
height = context.resources.getDimensionPixelSize(spaceRes)
}
......@@ -37,6 +41,10 @@ class SpaceItem : BaseItem<SpaceItem.ViewHolder>(
class ViewHolder(v: View) : RecyclerView.ViewHolder(v) {
val space: Space = v.findViewById(R.id.space)
}
companion object {
const val DEFAULT_HEIGHT: Int = -1
}
}
fun spaceItem(block: (SpaceItem.() -> Unit)): SpaceItem = SpaceItem()
......
......@@ -35,7 +35,7 @@ import kotlinx.coroutines.launch
abstract class FastAdapterFragment : BaseFragment() {
protected var binding: FragmentRecyclerViewBinding? = null
private var adapter: FastItemAdapter<GenericItem> = GenericFastItemAdapter()
protected val fastAdapter: FastItemAdapter<GenericItem> = GenericFastItemAdapter()
protected abstract fun getItems(): List<GenericItem>
protected abstract fun getAppBarLayout(): AppBarLayout?
private var onScrollListener: RecyclerView.OnScrollListener? = null
......@@ -49,11 +49,11 @@ abstract class FastAdapterFragment : BaseFragment() {
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
adapter.attachDefaultListeners = false
fastAdapter.attachDefaultListeners = false
val view = inflater.inflate(layout, container, false)
binding = FragmentRecyclerViewBinding.bind(view)
binding?.recyclerView?.layoutManager = LinearLayoutManager(requireContext())
binding?.recyclerView?.adapter = adapter
binding?.recyclerView?.adapter = fastAdapter
onScrollListener = binding?.recyclerView?.closeKeyboardOnScroll(context)
return view
}
......@@ -66,7 +66,7 @@ abstract class FastAdapterFragment : BaseFragment() {
if (items.isEmpty()) {
showEmpty()
} else {
adapter.setNewList(items)
fastAdapter.setNewList(items)
showData()
}
}
......
......@@ -14,6 +14,7 @@
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="dividerColor">@color/color_mine_shaft</item>
<item name="colorDisabled">@color/color_white_15</item>
</style>
<style name="Theme.StopCovid.Widget" parent="Theme.StopCovid.Base.Widget">
......@@ -53,6 +54,7 @@
<item name="bottomSheetDialogTheme">@style/ThemeOverlay.StopCovid.BottomSheetDialog</item>
<item name="dividerColor">@color/color_mercury</item>
<item name="colorDisabled">@color/color_white_15</item>
</style>
</resources>
......@@ -2,4 +2,5 @@
<resources>
<attr name="dividerColor" format="color" />
<attr name="widgetBackgroundColor" format="color" />
<attr name="colorDisabled" format="color" />
</resources>
\ No newline at end of file
......@@ -47,5 +47,6 @@
<color name="color_silver">#CCCCCC</color>
<color name="color_white_15">#26FFFFFF</color>
<color name="color_black_15">#26000000</color>
<color name="color_black_38">#61000000</color>
</resources>
......@@ -37,7 +37,7 @@
<item name="bottomSheetDialogTheme">@style/ThemeOverlay.StopCovid.BottomSheetDialog</item>
<item name="dividerColor">@color/color_mercury</item>
<item name="colorDisabled">@color/color_black_38</item>
</style>
<!-- Base application theme. -->
......
......@@ -18,6 +18,7 @@ import com.lunabeestudio.analytics.manager.AnalyticsManager
import com.lunabeestudio.analytics.model.AnalyticsServiceName
import com.lunabeestudio.domain.model.WalletCertificateType
import com.lunabeestudio.framework.remote.RetrofitClient
import com.lunabeestudio.framework.remote.extension.remoteToRobertException
import com.lunabeestudio.framework.remote.model.ApiConversionErrorRS
import com.lunabeestudio.framework.remote.model.ApiConversionRQ
import com.lunabeestudio.framework.remote.server.InGroupeApi
......@@ -26,6 +27,7 @@ import com.lunabeestudio.robert.RobertManager
import com.lunabeestudio.robert.datasource.RemoteCertificateDataSource
import com.lunabeestudio.robert.datasource.SharedCryptoDataSource
import com.lunabeestudio.robert.model.BackendException
import com.lunabeestudio.robert.model.NoInternetException
import com.lunabeestudio.robert.model.RobertResultData
import com.lunabeestudio.robert.model.UnknownException
import kotlinx.coroutines.Dispatchers
......@@ -77,15 +79,18 @@ class InGroupeDatasource(
}
}
} catch (e: Exception) {
AnalyticsManager.reportWSError(
context,
context.filesDir,
AnalyticsServiceName.CERTIFICATE_CONVERSION,
"0",
0,
e.message,
)
RobertResultData.Failure(BackendException("Unknown error : ${e.message}"))
val robertException = e.remoteToRobertException()
if (robertException !is NoInternetException) {
AnalyticsManager.reportWSError(
context,
context.filesDir,
AnalyticsServiceName.CERTIFICATE_CONVERSION,
"0",
0,
e.message,
)
}
RobertResultData.Failure(robertException)
}
}
}
......@@ -159,15 +164,18 @@ class InGroupeDatasource(
}
}
} catch (e: Exception) {
AnalyticsManager.reportWSError(
context,
context.filesDir,
AnalyticsServiceName.CERTIFICATE_CONVERSION,
"0",
0,
e.message,
)
RobertResultData.Failure(BackendException("Unknown error : ${e.message}"))
val robertException = e.remoteToRobertException()
if (robertException !is NoInternetException) {
AnalyticsManager.reportWSError(
context,
context.filesDir,
AnalyticsServiceName.CERTIFICATE_CONVERSION,
"0",
0,
e.message,
)
}
RobertResultData.Failure(robertException)
}
}
}
......
......@@ -22,6 +22,7 @@ import com.lunabeestudio.robert.model.UnknownException
import retrofit2.HttpException
import java.io.IOException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import javax.net.ssl.SSLException
internal fun Exception.remoteToRobertException(): RobertException = when (this) {
......@@ -29,6 +30,7 @@ internal fun Exception.remoteToRobertException(): RobertException = when (this)
is SSLException -> BackendException()
is SocketTimeoutException,
is IOException,
is UnknownHostException,
-> NoInternetException()
is HttpException -> {
try {
......
......@@ -6,6 +6,7 @@ import com.lunabeestudio.framework.remote.datasource.ServiceDataSource
import com.lunabeestudio.framework.remote.extension.remoteToRobertException
import com.lunabeestudio.framework.remote.model.ApiCommonRS
import com.lunabeestudio.robert.model.BackendException
import com.lunabeestudio.robert.model.NoInternetException
import com.lunabeestudio.robert.model.RobertResult
import com.lunabeestudio.robert.model.RobertResultData
import retrofit2.HttpException
......@@ -39,16 +40,19 @@ internal object RequestHelper {
}
} catch (e: Exception) {
Timber.e(ServiceDataSource::class.java.simpleName, e.message ?: "")
analyticsServiceName?.let {
AnalyticsManager.reportWSError(
context, filesDir,
it,
apiVersion,
(e as? HttpException)?.code() ?: 0,
e.message
)
val robertException = e.remoteToRobertException()
if (robertException !is NoInternetException) {
analyticsServiceName?.let {
AnalyticsManager.reportWSError(
context, filesDir,
it,
apiVersion,
(e as? HttpException)?.code() ?: 0,
e.message
)
}
}
RobertResult.Failure(error = e.remoteToRobertException())
RobertResult.Failure(error = robertException)
}
}
......@@ -67,16 +71,19 @@ internal object RequestHelper {
}
} catch (e: Exception) {
Timber.e(e)
analyticsServiceName?.let {
AnalyticsManager.reportWSError(
context, filesDir,
it,
apiVersion,
(e as? HttpException)?.code() ?: 0,
e.message
)
val robertException = e.remoteToRobertException()
if (robertException !is NoInternetException) {
analyticsServiceName?.let {
AnalyticsManager.reportWSError(
context, filesDir,
it,
apiVersion,
(e as? HttpException)?.code() ?: 0,
e.message
)
}
}
RobertResultData.Failure(error = e.remoteToRobertException())
RobertResultData.Failure(error = robertException)
}
}
}
\ No newline at end of file
......@@ -45,8 +45,8 @@ android {
applicationId "fr.gouv.android.stopcovid"
minSdkVersion 21
targetSdkVersion 30
versionCode 330
versionName "3.7.1"
versionCode 332
versionName "3.7.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
......
......@@ -6,7 +6,7 @@
},
{
"name": "version",
"value": 84
"value": 85
},
{
"name": "versionCalibrationBle",
......@@ -111,6 +111,10 @@
}
]
},
{
"name": "app.displayActivityPass",
"value": false
},
{
"name": "app.isolation.duration",
"value": 691200
......
......@@ -705,7 +705,7 @@
"walletController.title":"Wallet",
"walletController.recentCertificatesSection.title":"Recent certificates",
"walletController.recentCertificatesSection.subtitle":"In this section, you have all your vaccination certificates and test certificates less than 3 days old.\n⚠️ Check eligibility for the pass in the \"Information\" tab.",
"walletController.recentCertificatesSection.subtitle":"⚠️ Check eligibility for the pass in the \"Information\" tab.",
"walletController.oldCertificatesSection.title":"Older certificates",
"walletController.oldCertificatesSection.subtitle":"These test certificates are more than 3 days old.",
"walletController.menu.share":"Share the certificate",
......@@ -967,7 +967,7 @@
"home.walletSection.favoriteCertificate.cell.title": "My favorite certificate",
"home.walletSection.favoriteCertificate.cell.subtitle": "Tap for full screen",
"walletController.favoriteCertificateSection.title": "My favorite certificate",
"walletController.favoriteCertificateSection.subtitle": "Have your favorite certificate here by tapping the ❤️ icon on the certificate you want.",
"walletController.favoriteCertificateSection.subtitle": "Have your favorite certificate here by tapping the heart ❤️ icon on the certificate you want.",
"walletController.favoriteCertificateSection.openFullScreen": "Display full screen",
"manageDataController.userLanguage.title": "Language",
......@@ -990,10 +990,10 @@
"widget.dcc.empty":"Add here your favorite certificate by tapping the heart ❤️ icon you want",
"widget.dcc.full":"Tap for full screen",
"walletController.favoriteCertificateSection.widget":"👉 Use the widget to have this favorite certificate. Make sure to have the latest version of TousAntiCovid.",
"walletController.favoriteCertificateSection.widget.ios":"👉 Use the widget or the Apple Watch app to have this favorite certificate. Make sure to have the latest version of TousAntiCovid.",
"walletController.favoriteCertificateSection.widget.ios":"👉 Use the widget or the Apple Watch app to have this favorite certificate.\n💡 If you have a problem with a widget (all \"black\" for instance), update the app, remove it and put it back from the gallery.",
"appShortcut.favoriteDcc": "Favorite certificate",
"keyfigure.nombrevaccinations.colorCode.light":"#51E476",
"keyfigure.nombrevaccinations.colorCode.dark":"#51E476",
"keyfigure.nombrevaccinations.colorCode.light":"#007AFF",
"keyfigure.nombrevaccinations.colorCode.dark":"#0B84FF",
"keyfigure.nombrevaccinations.label":"Total first vaccinations",
"keyfigure.nombrevaccinations.shortLabel":"First vaccinations",
"keyfigure.nombrevaccinations.description":"This indicator represents the total number of people vaccinated with the first dose.\nThe data are consolidated the day after they are reported to take into account the latest vaccination data from the night before.",
......@@ -1009,7 +1009,7 @@
"universalQrScanController.actionSheet.title":"Please select the way you want to import the QR Code:",
"universalQrScanController.actionSheet.imagePicker":"Import from a photo",
"universalQrScanController.actionSheet.documentPicker":"Import from a PDF file",
"wallet.blacklist.warning": "🔴⚠️ This certificate seems to be used fraudulently. If this certificate belongs to you, please contact support on 0 800 08 71 48. If this certificate does not belong to you, you risk a fine of 45,000 euros and 3 years in prison.",
"wallet.blacklist.warning": "🔴 This certificate seems to be used fraudulently. If this certificate belongs to you, please contact support on 0 800 08 71 48. If this certificate does not belong to you, you risk a fine of 45,000 euros and 3 years in prison.",
"attestation.form.reason_curfew.label":"Motif couvre-feu",
"attestation.form.reason_curfew.placeholder":"-",
......@@ -1107,11 +1107,11 @@
"manageDataController.logFiles.title": "Log files",
"manageDataController.logFiles.subtitle": "To help the technical team, you can share these files when you contact the support team by email.\n\nThese log files are only stored on your smartphone, and don't contain personal data.",
"manageDataController.logFiles.noLogs": "You don't have any log file.",
"manageDataController.logFiles.logsFilesCount": "You currently have %d logs file(s).",
"manageDataController.logFiles.logsFilesCount": "You currently have %d log file(s).",
"manageDataController.logFiles.share.button": "Share logs",
"manageDataController.logFiles.delete.button": "Delete logs",
"manageDataController.logFiles.delete.confirmationDialog.title": "Warning",
"manageDataController.logFiles.delete.confirmationDialog.message": "Are you sure you want to delete the logs files?",
"manageDataController.logFiles.delete.confirmationDialog.message": "Are you sure you want to delete the log files?",
"pdfImport.protected.enterPassword.alert.title": "Protected document",
"pdfImport.protected.enterPassword.alert.message": "Please enter the document password to import the QR Code.",
......@@ -1120,7 +1120,7 @@
"pdfImport.protected.wrongPassword.alert.message": "The provided document password is wrong.\nDo you want to try again?",
"vaccineCompletionController.button.favorite.title": "Add to favorites",
"vaccineCompletionController.footer.favorite": "Touch this button if you want to set this certificate as the favorite one in your wallet.",
"vaccineCompletionController.footer.favorite": "Tap this button if you want to set this certificate as the favorite one in your wallet.",
"accessibility.home.otherOptions": "Other available actions",
"accessibility.isolation.formWasUpdated": "The form was updated. Continue to browse it to answer the questions and read the recommandations when available.",
......@@ -1130,8 +1130,19 @@
"accessibility.onboarding.explanations.step2": "Step 2",
"accessibility.onboarding.explanations.step3": "Step 3",
"vaccineCompletionController.footer.notify": "En appuyant sur ce bouton, vous recevrez une notification le %@.",
"vaccineCompletionController.button.notifyAndFavorite.title": "Me notifier et ajouter en favori ❤️",
"vaccineCompletionController.footer.notifyAndFavorite": "En appuyant sur ce bouton, vous recevrez une notification le %@, et ce certificat sera ajouté en favori dans votre carnet."
"vaccineCompletionController.footer.notify": "By tapping this button, you will receive a notification on %@.",
"vaccineCompletionController.button.notifyAndFavorite.title": "Notify me and add to favorite",
"vaccineCompletionController.footer.notifyAndFavorite": "By tapping this button, you will receive a notification on %@, and this certificate will be added as a favorite ❤️ in your TousAntiCovid wallet.",
"activityPass.fullscreen.title": "Pass Activité",
"activityPass.fullscreen.explanation": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
"activityPass.fullscreen.readMore": "En savoir plus",
"activityPass.fullscreen.readMore.url": "",
"activityPass.fullscreen.unavailable.alert.title": "Indisponible",
"activityPass.fullscreen.unavailable.alert.message": "Votre connexion ou le service de génération de Pass Activité ne sont pas disponibles.\n\nVous pouvez utiliser le certificat dans l'onglet \"Frontière\".",
"activityPass.fullscreen.notYet.alert.title": "Pas encore",
"activityPass.fullscreen.notYet.alert.message": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"activityPass.fullscreen.button.generate": "Générer un Pass Activité",
"europeanCertificate.fullscreen.type.activityPass": "Pass Activité"
}
......@@ -670,7 +670,7 @@
"walletController.title":"Carnet",
"walletController.recentCertificatesSection.title":"Certificats récents",
"walletController.recentCertificatesSection.subtitle":"Dans cette section, vous avez les certificats de vaccination et les certificats de test de moins de 3 jours.\n⚠️ Vérifiez l'éligibilité pour le pass sanitaire dans \"Informations\".",
"walletController.recentCertificatesSection.subtitle":"⚠️ Vérifiez l'éligibilité pour le pass sanitaire dans \"Informations\".",
"walletController.oldCertificatesSection.title":"Certificats plus anciens",
"walletController.oldCertificatesSection.subtitle":"Ces certificats de test ont plus de 3 jours.",
"walletController.menu.share":"Partager le certificat",
......@@ -941,7 +941,7 @@
"home.walletSection.favoriteCertificate.cell.title": "Mon certificat favori",
"home.walletSection.favoriteCertificate.cell.subtitle": "Appuyez pour l’afficher en plein écran",
"walletController.favoriteCertificateSection.title": "Mon certificat favori",
"walletController.favoriteCertificateSection.subtitle": "Ajoutez ici votre certificat favori en appuyant sur l’icône ❤️ sur le certificat (au format européen) souhaité.",
"walletController.favoriteCertificateSection.subtitle": "Ajoutez ici votre certificat favori en appuyant sur l’icône coeur ❤️ sur le certificat (au format européen) souhaité.",
"walletController.favoriteCertificateSection.openFullScreen": "Afficher en plein écran",
"manageDataController.userLanguage.title":"Langue",
......@@ -964,10 +964,10 @@
"widget.dcc.empty":"Ajoutez ici votre certificat favori en appuyant sur l'icône coeur ❤️ sur le certificat (au format européen) souhaité.",
"widget.dcc.full":"Appuyez pour passer en plein écran",
"walletController.favoriteCertificateSection.widget":"👉 Retrouvez ce certificat favori dans un widget. Mettez bien à jour TousAntiCovid.",
"walletController.favoriteCertificateSection.widget.ios":"👉 Retrouvez ce certificat favori dans un widget et l'appli Apple Watch. Mettez bien à jour TousAntiCovid.",
"walletController.favoriteCertificateSection.widget.ios":"👉 Retrouvez ce certificat favori dans un widget et l'appli Apple Watch.\n💡 Si vous avez un problème avec un widget (ex : tout \"noir\") : mettez à jour l'appli en version 3.7.2 mininum, supprimez le widget et remettez-le. Merci !",
"appShortcut.favoriteDcc": "Certificat favori",
"keyfigure.nombrevaccinations.colorCode.light":"#51E476",
"keyfigure.nombrevaccinations.colorCode.dark":"#51E476",
"keyfigure.nombrevaccinations.colorCode.light":"#007AFF",
"keyfigure.nombrevaccinations.colorCode.dark":"#0B84FF",
"keyfigure.nombrevaccinations.label":"Total primo vaccinations",
"keyfigure.nombrevaccinations.shortLabel":"Primo vaccinations",
"keyfigure.nombrevaccinations.description":"Cet indicateur représente le nombre total de personnes primo vaccinées.\nLes données sont consolidées le lendemain de leur remontée pour tenir compte des dernières données de vaccination de la veille au soir.",
......@@ -1082,7 +1082,7 @@
"manageDataController.logFiles.title": "Fichiers de logs",
"manageDataController.logFiles.subtitle": "Pour aider l'équipe technique, vous pouvez partager ce(s) fichier(s) quand vous contactez l'équipe de support par email.\n\nCes fichiers de logs sont uniquement stockés sur votre smartphone, et ne contiennent pas de données personnelles.",
"manageDataController.logFiles.noLogs": "Vous n'avez actuellement aucun fichier de log.",
"manageDataController.logFiles.logsFilesCount": "Vous avez actuellement %d fichier(s) de logs.",
"manageDataController.logFiles.logsFilesCount": "Vous avez actuellement %d fichier(s) de log.",
"manageDataController.logFiles.share.button": "Partager les logs",
"manageDataController.logFiles.delete.button": "Supprimer les logs",
"manageDataController.logFiles.delete.confirmationDialog.title": "Attention",
......@@ -1095,7 +1095,7 @@
"pdfImport.protected.wrongPassword.alert.message": "Le mot de passe saisi n'est pas le bon.\nVoulez-vous essayer à nouveau ?",
"vaccineCompletionController.button.favorite.title": "Ajouter en favori",
"vaccineCompletionController.footer.favorite": "En appuyant sur ce bouton, ce certificat sera ajouté en favori dans votre carnet.",
"vaccineCompletionController.footer.favorite": "En appuyant sur ce bouton, ce certificat sera ajouté en favori ❤️ dans votre carnet.",
"accessibility.home.otherOptions": "Autres actions disponibles",
"accessibility.isolation.formWasUpdated": "Le formulaire a été mis à jour. Continuez de le parcourir pour répondre aux différentes questions et lire les recommandations le cas échéant.",
......@@ -1106,6 +1106,18 @@
"accessibility.onboarding.explanations.step3": "étape 3",
"vaccineCompletionController.footer.notify": "En appuyant sur ce bouton, vous recevrez une notification le %@.",
"vaccineCompletionController.button.notifyAndFavorite.title": "Me notifier et ajouter en favori ❤️",
"vaccineCompletionController.footer.notifyAndFavorite": "En appuyant sur ce bouton, vous recevrez une notification le %@, et ce certificat sera ajouté en favori dans votre carnet."
"vaccineCompletionController.button.notifyAndFavorite.title": "Me notifier et ajouter en favori",
"vaccineCompletionController.footer.notifyAndFavorite": "En appuyant sur ce bouton, vous recevrez une notification le %@, et ce certificat sera ajouté en favori ❤️ dans votre carnet.",
"activityPass.fullscreen.title": "Pass Activité",
"activityPass.fullscreen.explanation": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
"activityPass.fullscreen.readMore": "En savoir plus",
"activityPass.fullscreen.readMore.url": "",
"activityPass.fullscreen.unavailable.alert.title": "Indisponible",
"activityPass.fullscreen.unavailable.alert.message": "Votre connexion ou le service de génération de Pass Activité ne sont pas disponibles.\n\nVous pouvez utiliser le certificat dans l'onglet \"Frontière\".",
"activityPass.fullscreen.notYet.alert.title": "Pas encore",
"activityPass.fullscreen.notYet.alert.message": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"activityPass.fullscreen.button.generate": "Générer un Pass Activité",
"europeanCertificate.fullscreen.type.activityPass": "Pass Activité"
}
......@@ -374,7 +374,6 @@ class StopCovid : Application(), LifecycleObserver, RobertApplication, Isolation
override fun notifyAtRiskLevelChange() {
RisksLevelManager.getCurrentLevel(robertManager.atRiskStatus?.riskLevel)?.let { riskLevel ->
AnalyticsManager.reportHealthEvent(this, HealthEventName.eh2, riskLevel.riskLevel.roundToInt().toString())
AnalyticsManager.reportAppEvent(this, AppEventName.e2)
val inputData = Data.Builder()
.putString(AtRiskNotificationWorker.INPUT_DATA_TITLE_KEY, riskLevel.labels.notifTitle)
.putString(AtRiskNotificationWorker.INPUT_DATA_MESSAGE_KEY, riskLevel.labels.notifBody)
......
......@@ -107,3 +107,5 @@ val String.countryCodeToFlagEmoji: String
""
}
}
fun String.splitUrlFragment(): List<String> = this.split(Char(0x1E))